| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | FruitType | ID | Price | Name | Tag | Stock |
| 2 | map<int32,Fruit> | map<int32,Item> | int32 | string | string | int32 |
| 3 | Outer key | Inner key | Indexed field | Display | Tag | Stock |
| 4 | 1 | 100 | 99 | Apple | fresh | 120 |
| 5 | 1 | 101 | 79 | Pear | fresh | 80 |
| 6 | 2 | 200 | 99 | Berry | frozen | 40 |
RELEASE NOTES
First-class C# loader plugin, Protobuf Editions 2023/2024 across all
three plugins, a unified
make.py
build pipeline replacing init.bat / init.sh / prepare.bat, and
vcpkg-managed protobuf with a quarterly-pinned matrix.
New protoc-gen-csharp-tableau-loader plugin. Targets Unity 2022.3 LTS / .NET 8, generates *.pc.cs. Same Hub / Messager / Load API surface as Go & C++, including patch loading, MessagerOptions, custom ReadFunc/LoadFunc, and a thread-safe Atomic<T>-backed Hub.
var hub = new Tableau.Hub();
var opts = new Tableau.Load.Options {
IgnoreUnknownFields = true,
PatchDirs = new() { "./patch" },
};
hub.Load("./conf", Format.JSON, opts);
var conf = hub.GetItemConf();All three plugins (Go / C++ / C#) emit code that compiles cleanly under edition = "2023" and "2024" alongside proto2 / proto3. The build toolchain in init.sh / init.bat was modernized to install a matching protoc.
// proto2 / proto3 still supported
// new: Editions 2023 & 2024
edition = "2024";
package protoconf;
message ItemConf { ... }Three real test suites — Go (testing), C++ (gtest), C# (xUnit) — exercise the same patch scenarios with golden-file parity. Standalone main.go / main.cpp / Program.cs demos were retired.
✓ go main_test.go::Test_Patch_* PASS
✓ cpp tests/patch_test.cpp PatchConf_* PASS
✓ csharp tests/PatchTests.cs PatchConf_* PASS
// All three load the same testdata/conf + testdata/patchconf
// and compare to testdata/patchresult/ goldens.make.py Pipeline
One Python 3.10+ stdlib-only entry point replaces init.sh, init.bat, and prepare.bat. Subcommands: setup, generate, build, test, clean, env. CI runs the same script as developers.
$ python3 make.py setup --lang all
$ python3 make.py test --lang go
$ python3 make.py test --lang cpp # vcpkg-installed protobuf
$ python3 make.py test --lang csharp -k HubTests
$ python3 make.py test --lang cpp --protobuf-version 3.21.12buf Codegen
Reproducible dev environment via .devcontainer/: VS Code → "Reopen in Container" gives the same Go, buf, vcpkg, and protobuf versions used in CI. buf generate replaces the per-language gen.sh / gen.bat scripts in every test workspace.
GO_VERSION=1.24.0
BUF_VERSION=1.67.0
DOTNET_VERSION=8.0
DEFAULT_VARIANT=modern
MODERN_PROTOBUF_VERSION=6.33.4
LEGACY_V3_PROTOBUF_VERSION=3.21.12The C++ runtime now installs a Tableau log sink on libprotobuf — routing [libprotobuf] messages into the Tableau logger. Compile-time TABLEAU_PB_LOG_LEGACY picks legacy SetLogHandler (protobuf ≤ 3.x) or modern absl::LogSink (protobuf ≥ 4.x with Abseil).
#if TABLEAU_PB_LOG_LEGACY
// SetLogHandler(ProtobufLogHandler) on protobuf 3.x
#else
// class ProtobufAbslLogSink : public absl::LogSink {
// void Send(const absl::LogEntry& entry) override;
// };
#endif
ATOM_LOGGER_CALL(tableau::log::DefaultLogger(), lvl,
"[libprotobuf %s:%d] %s", ...);pkg/treemap/redblacktree now uses self-referential generics on Go ≥ 1.26 (Lesser[T Lesser[T]]), with a //go:build !go1.26 fallback to keep older toolchains compiling. Tightens type safety for FindIter, UpperBound, LowerBound.
//go:build go1.26
package redblacktree
type Lesser[T Lesser[T]] interface {
comparable
Less(other T) bool
}Index field in a list under upper maps now resolves correctly (#158)
Reworked
LevelMessage
to track
MapDepth
+ a new
LeveledContainerDepth(). List levels under a parent map now generate the correct
number of leveled finders (FindItem1,
FindItem2, …). Adds Fruit6Conf.json + 543
lines of index_test.go.
Index parser skips
oneof
branches when walking levels
(#156)
Three-line fix in
internal/index/descriptor.go: when iterating a message's fields, descriptors with
ContainingOneof() != nil
are skipped, removing spurious "field not found" errors caused
by oneof name conflicts.
Field-name case conversion + cross-platform generation order (#153)
New
underscoresToCamelCase
helper unifies property naming across all three plugins;
introduces
internal/xproto.SplitShards
so generation order is identical on Linux / macOS / Windows. New
StrcaseConf regression suite covers
UserID,
V2Ray,
XCoordinate, etc.
Windows
prepare.bat
CMake 3.x install + admin elevation prompt
(#152, #154)
Bootstrap script now winget-installs the right CMake major version and re-launches itself elevated when needed. Subsequent commits absorbed it into make.py setup.
Templated includes use original proto names; OrderedMap accessors adjusted (#151)
Generated C++
hub.pc.cc
/
hub_shard.pc.cc
templates emit the original (non-snake-cased) include names, and
the OrderedMap accessor in C++ & C# generators only fires
when there's a top-level map.
C++
GetLastLoadedTime
no longer marked
inline
(#146)
The inline keyword on a non-trivial accessor caused ODR violations when the symbol was referenced from multiple translation units; removing it makes the link-time behavior portable.
Consider Fruit6Conf: an outer map keyed
by
FruitType
whose values contain a list of items, with the index
Price<ID>
and ordered index
Price<ID>@OrderedFruit. v0.5.0 generated the wrong number of leveled containers because
MapDepth
alone didn't capture "list under map". v0.6.0 introduces
LeveledContainerDepth(), which adds 1 for non-map levels that still need the parent map's
container.
▸ Index.xlsx — Fruit6Conf
| A | B | C | |
|---|---|---|---|
| 1 | FruitType | ID | Price |
| 2 | map<int32,Fruit> | [Item] | int32 |
| 3 | Outer map key | List of items (vertical) | Indexed by Price<ID> |
| 4 | 1 | — | 99 |
| 5 | 1 | — | 79 |
| 6 | 2 | — | 99 |
When a level message embeds a
oneof, the parser previously tried to resolve oneof case fields by name
and conflicted with regular fields. The fix skips any descriptor
whose
ContainingOneof()
is non-nil.
for i := 0; i < md.Fields().Len(); i++ {
fd := md.Fields().Get(i)
if fd.ContainingOneof() != nil {
continue // skip oneof case fields
}
// ... existing logic
}From a single .proto set, v0.6.0 generates idiomatic Go, C++17, and C# loaders — and three real test suites (testing, gtest, xUnit) running the same PatchConf scenarios against shared testdata/ goldens.
func prepareHub(t *testing.T) *hub.MyHub {
h := hub.NewMyHub()
h.Load("../testdata/conf/",
format.JSON,
load.IgnoreUnknownFields())
return h
}TEST_F(PatchTest, RecursivePatchConf) {
auto opts = NewOptions();
opts->patch_dirs = {
test::TestPaths::PatchConf().string()};
Hub::Instance().Load(...);
}[Fact]
public void PatchReplaceConf() {
var opts = new Load.Options {
PatchDirs = new() { TestPaths.PatchConfDir }
};
var hub = new Hub();
hub.Load(...);
}
make.py
uses Python 3.10 stdlib only. It mounts vcpkg, sources
vcvarsall.bat
per-subprocess on Windows (your shell PATH/INCLUDE/LIB are never
mutated), and is itself unit-tested via
test_make.py
+
testing-make.yml.
# one-time host toolchain (no-op inside devcontainer)
$ python3 make.py setup --lang all
# per-language
$ python3 make.py test --lang go -k Test_ActivityConf_OrderedMap
$ python3 make.py test --lang cpp --cxx-std 20 --cxx-compiler clang
$ python3 make.py test --lang cpp --protobuf-version 3.21.12
$ python3 make.py test --lang csharp -k HubTests
# diagnostic JSON (paths, versions, env probes)
$ python3 make.py env