From 8c6e90f730a2ca6751fba93687c94b6a5d027c37 Mon Sep 17 00:00:00 2001 From: Matt Bolt Date: Thu, 30 Jul 2026 17:38:06 -0400 Subject: [PATCH 1/3] First pass at generation backend refactor + java generation in bingen --- cmd/bingen/bingen.go | 64 +- internal/generator/context.go | 183 - internal/generator/core/backend.go | 121 + internal/generator/core/emit.go | 83 + internal/generator/core/scope.go | 46 + internal/generator/core/stream.go | 135 + internal/generator/core/walk.go | 184 + internal/generator/golang/backend.go | 588 +++ internal/generator/golang/context.go | 92 + .../{bingen.go => golang/generate.go} | 35 +- internal/generator/golang/templates.go | 112 + .../golang/templates/go/marshaller.go.tmpl | 83 + .../golang/templates/go/streamer.go.tmpl | 61 + .../{ => golang}/templates/go/support.go.tmpl | 0 .../golang/templates/go/unmarshaller.go.tmpl | 73 + internal/generator/java/backend.go | 348 ++ internal/generator/java/decoder_test.go | 100 + internal/generator/java/encoder_test.go | 80 + internal/generator/java/externaltypes.go | 22 + internal/generator/java/generate.go | 223 ++ internal/generator/java/generate_test.go | 40 + internal/generator/java/helper_test.go | 396 ++ internal/generator/java/hooks_test.go | 99 + internal/generator/java/implements.go | 137 + internal/generator/java/javatype.go | 150 + internal/generator/java/javatype_test.go | 83 + internal/generator/java/migration_test.go | 90 + internal/generator/java/options.go | 116 + internal/generator/java/options_test.go | 131 + internal/generator/java/parity_test.go | 260 ++ internal/generator/java/record_test.go | 43 + internal/generator/java/roundtrip_test.go | 378 ++ internal/generator/java/stream_test.go | 133 + internal/generator/java/templates.go | 130 + .../java/templates/java/BinDecoder.java.tmpl | 16 + .../java/templates/java/BinEncoder.java.tmpl | 16 + .../templates/java/BingenConsumer.java.tmpl | 19 + .../templates/java/BingenElement.java.tmpl | 16 + .../templates/java/BingenFieldInfo.java.tmpl | 15 + .../templates/java/BingenPullStream.java.tmpl | 153 + .../java/BingenStreamException.java.tmpl | 18 + .../templates/java/BingenStreamFn.java.tmpl | 21 + .../java/templates/java/BingenValue.java.tmpl | 30 + .../templates/java/DecodingContext.java.tmpl | 75 + .../templates/java/EncodingContext.java.tmpl | 74 + .../java/templates/java/GoTime.java.tmpl | 139 + .../java/templates/java/ReadBuffer.java.tmpl | 231 ++ .../java/StringTableReader.java.tmpl | 49 + .../java/StringTableWriter.java.tmpl | 54 + .../java/templates/java/WriteBuffer.java.tmpl | 169 + .../java/templates/java/decoder.java.tmpl | 64 + .../java/templates/java/encoder.java.tmpl | 46 + .../java/templates/java/interface.java.tmpl | 16 + .../templates/java/package-info.java.tmpl | 12 + .../java/templates/java/record.java.tmpl | 45 + .../java/templates/java/registry.java.tmpl | 77 + .../java/templates/java/streamer.java.tmpl | 59 + internal/generator/java/validate.go | 113 + internal/generator/templates.go | 208 - .../generator/templates/go/marshaller.go.tmpl | 340 -- .../generator/templates/go/streamer.go.tmpl | 294 -- .../templates/go/unmarshaller.go.tmpl | 413 -- internal/generator/vars/vars.go | 215 - internal/types/types.go | 16 + internal/types/walk.go | 27 + tests/aliases/aliases_codecs.go | 739 ++-- tests/aliasnil/aliasnil.go | 13 + tests/aliasnil/aliasnil_codecs.go | 469 +++ tests/aliasnil/bingen.go | 4 + tests/container/container_codecs.go | 63 +- tests/containerv2/containerv2_codecs.go | 140 +- tests/generator_test.go | 32 +- .../opencost/java/com/bingen/BinDecoder.java | 16 + .../opencost/java/com/bingen/BinEncoder.java | 16 + .../java/com/bingen/BingenConsumer.java | 19 + .../java/com/bingen/BingenElement.java | 16 + .../java/com/bingen/BingenFieldInfo.java | 13 + .../java/com/bingen/BingenPullStream.java | 148 + .../com/bingen/BingenStreamException.java | 16 + .../java/com/bingen/BingenStreamFn.java | 21 + .../opencost/java/com/bingen/BingenValue.java | 26 + .../java/com/bingen/DecodingContext.java | 67 + .../java/com/bingen/EncodingContext.java | 64 + tests/opencost/java/com/bingen/GoTime.java | 139 + .../opencost/java/com/bingen/ReadBuffer.java | 213 + .../java/com/bingen/StringTableReader.java | 45 + .../java/com/bingen/StringTableWriter.java | 50 + .../opencost/java/com/bingen/WriteBuffer.java | 130 + .../com/opencost/opencost/Allocation.java | 186 + .../opencost/opencost/AllocationDecoder.java | 190 + .../opencost/opencost/AllocationEncoder.java | 108 + .../opencost/AllocationProperties.java | 86 + .../opencost/AllocationPropertiesDecoder.java | 171 + .../opencost/AllocationPropertiesEncoder.java | 127 + .../com/opencost/opencost/AllocationSet.java | 66 + .../opencost/AllocationSetDecoder.java | 159 + .../opencost/AllocationSetEncoder.java | 119 + .../opencost/opencost/AllocationSetRange.java | 40 + .../opencost/AllocationSetRangeDecoder.java | 75 + .../opencost/AllocationSetRangeEncoder.java | 57 + .../opencost/AllocationSetStreamer.java | 176 + .../java/com/opencost/opencost/Any.java | 66 + .../com/opencost/opencost/AnyDecoder.java | 99 + .../com/opencost/opencost/AnyEncoder.java | 71 + .../java/com/opencost/opencost/Asset.java | 16 + .../opencost/opencost/AssetProperties.java | 69 + .../opencost/AssetPropertiesDecoder.java | 104 + .../opencost/AssetPropertiesEncoder.java | 77 + .../java/com/opencost/opencost/AssetSet.java | 61 + .../opencost/opencost/AssetSetDecoder.java | 139 + .../opencost/opencost/AssetSetEncoder.java | 104 + .../com/opencost/opencost/AssetSetRange.java | 40 + .../opencost/AssetSetRangeDecoder.java | 75 + .../opencost/AssetSetRangeEncoder.java | 57 + .../opencost/opencost/AssetSetStreamer.java | 153 + .../java/com/opencost/opencost/Breakdown.java | 49 + .../opencost/opencost/BreakdownDecoder.java | 60 + .../opencost/opencost/BreakdownEncoder.java | 41 + .../java/com/opencost/opencost/Cloud.java | 71 + .../com/opencost/opencost/CloudDecoder.java | 102 + .../com/opencost/opencost/CloudEncoder.java | 72 + .../opencost/opencost/ClusterManagement.java | 50 + .../opencost/ClusterManagementDecoder.java | 88 + .../opencost/ClusterManagementEncoder.java | 66 + .../java/com/opencost/opencost/Disk.java | 81 + .../com/opencost/opencost/DiskDecoder.java | 113 + .../com/opencost/opencost/DiskEncoder.java | 80 + .../com/opencost/opencost/LoadBalancer.java | 66 + .../opencost/LoadBalancerDecoder.java | 99 + .../opencost/LoadBalancerEncoder.java | 71 + .../java/com/opencost/opencost/Network.java | 66 + .../com/opencost/opencost/NetworkDecoder.java | 99 + .../com/opencost/opencost/NetworkEncoder.java | 71 + .../java/com/opencost/opencost/Node.java | 121 + .../com/opencost/opencost/NodeDecoder.java | 146 + .../com/opencost/opencost/NodeEncoder.java | 98 + .../com/opencost/opencost/PVAllocation.java | 39 + .../opencost/PVAllocationDecoder.java | 54 + .../opencost/PVAllocationEncoder.java | 39 + .../java/com/opencost/opencost/PVKey.java | 39 + .../com/opencost/opencost/PVKeyDecoder.java | 62 + .../com/opencost/opencost/PVKeyEncoder.java | 47 + .../opencost/RawAllocationOnlyData.java | 39 + .../RawAllocationOnlyDataDecoder.java | 54 + .../RawAllocationOnlyDataEncoder.java | 39 + .../com/opencost/opencost/SharedAsset.java | 50 + .../opencost/opencost/SharedAssetDecoder.java | 88 + .../opencost/opencost/SharedAssetEncoder.java | 66 + .../com/opencost/opencost/TypeRegistry.java | 90 + .../java/com/opencost/opencost/Window.java | 40 + .../com/opencost/opencost/WindowDecoder.java | 64 + .../com/opencost/opencost/WindowEncoder.java | 51 + .../com/opencost/opencost/package-info.java | 12 + tests/opencost/opencost_codecs.go | 3523 +++++++---------- tests/roundtrip_test.go | 117 + tests/shape/bingen.go | 6 + tests/shape/shape.go | 35 + tests/shape/shape_codecs.go | 708 ++++ tests/streamfeed/bingen.go | 3 + tests/streamfeed/streamfeed.go | 11 + tests/streamfeed/streamfeed_codecs.go | 671 ++++ tests/sttable/bingen.go | 3 + tests/sttable/sttable.go | 9 + tests/sttable/sttable_codecs.go | 489 +++ tests/timerec/bingen.go | 3 + tests/timerec/timerec.go | 11 + tests/timerec/timerec_codecs.go | 452 +++ tests/var_test.go | 137 - 168 files changed, 17369 insertions(+), 4401 deletions(-) delete mode 100644 internal/generator/context.go create mode 100644 internal/generator/core/backend.go create mode 100644 internal/generator/core/emit.go create mode 100644 internal/generator/core/scope.go create mode 100644 internal/generator/core/stream.go create mode 100644 internal/generator/core/walk.go create mode 100644 internal/generator/golang/backend.go create mode 100644 internal/generator/golang/context.go rename internal/generator/{bingen.go => golang/generate.go} (79%) create mode 100644 internal/generator/golang/templates.go create mode 100644 internal/generator/golang/templates/go/marshaller.go.tmpl create mode 100644 internal/generator/golang/templates/go/streamer.go.tmpl rename internal/generator/{ => golang}/templates/go/support.go.tmpl (100%) create mode 100644 internal/generator/golang/templates/go/unmarshaller.go.tmpl create mode 100644 internal/generator/java/backend.go create mode 100644 internal/generator/java/decoder_test.go create mode 100644 internal/generator/java/encoder_test.go create mode 100644 internal/generator/java/externaltypes.go create mode 100644 internal/generator/java/generate.go create mode 100644 internal/generator/java/generate_test.go create mode 100644 internal/generator/java/helper_test.go create mode 100644 internal/generator/java/hooks_test.go create mode 100644 internal/generator/java/implements.go create mode 100644 internal/generator/java/javatype.go create mode 100644 internal/generator/java/javatype_test.go create mode 100644 internal/generator/java/migration_test.go create mode 100644 internal/generator/java/options.go create mode 100644 internal/generator/java/options_test.go create mode 100644 internal/generator/java/parity_test.go create mode 100644 internal/generator/java/record_test.go create mode 100644 internal/generator/java/roundtrip_test.go create mode 100644 internal/generator/java/stream_test.go create mode 100644 internal/generator/java/templates.go create mode 100644 internal/generator/java/templates/java/BinDecoder.java.tmpl create mode 100644 internal/generator/java/templates/java/BinEncoder.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenConsumer.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenElement.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenFieldInfo.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenPullStream.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenStreamException.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenStreamFn.java.tmpl create mode 100644 internal/generator/java/templates/java/BingenValue.java.tmpl create mode 100644 internal/generator/java/templates/java/DecodingContext.java.tmpl create mode 100644 internal/generator/java/templates/java/EncodingContext.java.tmpl create mode 100644 internal/generator/java/templates/java/GoTime.java.tmpl create mode 100644 internal/generator/java/templates/java/ReadBuffer.java.tmpl create mode 100644 internal/generator/java/templates/java/StringTableReader.java.tmpl create mode 100644 internal/generator/java/templates/java/StringTableWriter.java.tmpl create mode 100644 internal/generator/java/templates/java/WriteBuffer.java.tmpl create mode 100644 internal/generator/java/templates/java/decoder.java.tmpl create mode 100644 internal/generator/java/templates/java/encoder.java.tmpl create mode 100644 internal/generator/java/templates/java/interface.java.tmpl create mode 100644 internal/generator/java/templates/java/package-info.java.tmpl create mode 100644 internal/generator/java/templates/java/record.java.tmpl create mode 100644 internal/generator/java/templates/java/registry.java.tmpl create mode 100644 internal/generator/java/templates/java/streamer.java.tmpl create mode 100644 internal/generator/java/validate.go delete mode 100644 internal/generator/templates.go delete mode 100644 internal/generator/templates/go/marshaller.go.tmpl delete mode 100644 internal/generator/templates/go/streamer.go.tmpl delete mode 100644 internal/generator/templates/go/unmarshaller.go.tmpl delete mode 100644 internal/generator/vars/vars.go create mode 100644 internal/types/walk.go create mode 100644 tests/aliasnil/aliasnil.go create mode 100644 tests/aliasnil/aliasnil_codecs.go create mode 100644 tests/aliasnil/bingen.go create mode 100644 tests/opencost/java/com/bingen/BinDecoder.java create mode 100644 tests/opencost/java/com/bingen/BinEncoder.java create mode 100644 tests/opencost/java/com/bingen/BingenConsumer.java create mode 100644 tests/opencost/java/com/bingen/BingenElement.java create mode 100644 tests/opencost/java/com/bingen/BingenFieldInfo.java create mode 100644 tests/opencost/java/com/bingen/BingenPullStream.java create mode 100644 tests/opencost/java/com/bingen/BingenStreamException.java create mode 100644 tests/opencost/java/com/bingen/BingenStreamFn.java create mode 100644 tests/opencost/java/com/bingen/BingenValue.java create mode 100644 tests/opencost/java/com/bingen/DecodingContext.java create mode 100644 tests/opencost/java/com/bingen/EncodingContext.java create mode 100644 tests/opencost/java/com/bingen/GoTime.java create mode 100644 tests/opencost/java/com/bingen/ReadBuffer.java create mode 100644 tests/opencost/java/com/bingen/StringTableReader.java create mode 100644 tests/opencost/java/com/bingen/StringTableWriter.java create mode 100644 tests/opencost/java/com/bingen/WriteBuffer.java create mode 100644 tests/opencost/java/com/opencost/opencost/Allocation.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationProperties.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationPropertiesEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSet.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSetRange.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSetRangeEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AllocationSetStreamer.java create mode 100644 tests/opencost/java/com/opencost/opencost/Any.java create mode 100644 tests/opencost/java/com/opencost/opencost/AnyDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AnyEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/Asset.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetProperties.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSet.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSetRange.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java create mode 100644 tests/opencost/java/com/opencost/opencost/Breakdown.java create mode 100644 tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/Cloud.java create mode 100644 tests/opencost/java/com/opencost/opencost/CloudDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/CloudEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/ClusterManagement.java create mode 100644 tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/ClusterManagementEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/Disk.java create mode 100644 tests/opencost/java/com/opencost/opencost/DiskDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/DiskEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/LoadBalancer.java create mode 100644 tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/Network.java create mode 100644 tests/opencost/java/com/opencost/opencost/NetworkDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/NetworkEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/Node.java create mode 100644 tests/opencost/java/com/opencost/opencost/NodeDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/NodeEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/PVAllocation.java create mode 100644 tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/PVKey.java create mode 100644 tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java create mode 100644 tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/SharedAsset.java create mode 100644 tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/TypeRegistry.java create mode 100644 tests/opencost/java/com/opencost/opencost/Window.java create mode 100644 tests/opencost/java/com/opencost/opencost/WindowDecoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/WindowEncoder.java create mode 100644 tests/opencost/java/com/opencost/opencost/package-info.java create mode 100644 tests/roundtrip_test.go create mode 100644 tests/shape/bingen.go create mode 100644 tests/shape/shape.go create mode 100644 tests/shape/shape_codecs.go create mode 100644 tests/streamfeed/bingen.go create mode 100644 tests/streamfeed/streamfeed.go create mode 100644 tests/streamfeed/streamfeed_codecs.go create mode 100644 tests/sttable/bingen.go create mode 100644 tests/sttable/sttable.go create mode 100644 tests/sttable/sttable_codecs.go create mode 100644 tests/timerec/bingen.go create mode 100644 tests/timerec/timerec.go create mode 100644 tests/timerec/timerec_codecs.go delete mode 100644 tests/var_test.go diff --git a/cmd/bingen/bingen.go b/cmd/bingen/bingen.go index 431ec09..32058d1 100644 --- a/cmd/bingen/bingen.go +++ b/cmd/bingen/bingen.go @@ -9,19 +9,51 @@ import ( "path/filepath" "strings" - "github.com/opencost/bingen/internal/generator" + "github.com/opencost/bingen/internal/generator/golang" + "github.com/opencost/bingen/internal/generator/java" "github.com/opencost/bingen/internal/types" ) const DefaultBufferPackage string = "github.com/opencost/bingen/pkg/util" +// optionFlag collects repeatable -opt key=value language-specific options into +// a map. +type optionFlag map[string]string + +func (o optionFlag) String() string { + pairs := make([]string, 0, len(o)) + for k, v := range o { + pairs = append(pairs, fmt.Sprintf("%s=%s", k, v)) + } + return strings.Join(pairs, ",") +} + +func (o optionFlag) Set(s string) error { + k, v, ok := strings.Cut(s, "=") + if !ok { + return fmt.Errorf("invalid -opt %q, expected key=value", s) + } + k = strings.TrimSpace(k) + if k == "" { + return fmt.Errorf("invalid -opt %q, empty key", s) + } + o[k] = strings.TrimSpace(v) + return nil +} + var ( packageName = flag.String("package", "", "package name to generate binary codecs for") buffer = flag.String("buffer", DefaultBufferPackage, "[DEPRECATED] qualified package for the Buffer type") version = flag.Uint("version", 1, "the versioning to use for the binary generator") + lang = flag.String("lang", "go", "target language: go|java") + options = optionFlag{} //output = flag.String("output", "", "output file name; default srcdir/_codecs.go") ) +func init() { + flag.Var(options, "opt", "language-specific option key=value (repeatable)") +} + // Usage is a replacement usage function for the flags package. func Usage() { fmt.Fprintf(os.Stderr, "Usage of bingen:\n") @@ -79,10 +111,16 @@ func main() { dir = filepath.Dir(args[0]) } - codecPath := path.Join(dir, fmt.Sprintf("%s_codecs.go", *packageName)) - if fileExists(codecPath) { - if err := os.Remove(codecPath); err != nil { - log.Fatalf("failed to remove existing codec file %q: %v", codecPath, err) + targetLang := strings.ToLower(strings.TrimSpace(*lang)) + + // The go exporter overwrites a single _codecs.go file; remove any stale + // copy up front. Other languages manage their own output layout. + if targetLang == "" || targetLang == "go" { + codecPath := path.Join(dir, fmt.Sprintf("%s_codecs.go", *packageName)) + if fileExists(codecPath) { + if err := os.Remove(codecPath); err != nil { + log.Fatalf("failed to remove existing codec file %q: %v", codecPath, err) + } } } @@ -93,5 +131,19 @@ func main() { fmt.Fprintf(os.Stderr, "Failed to parse @bingen annotations: %s", err) return } - generator.Generate(dir, *packageName, DefaultBufferPackage, tc) + + switch targetLang { + case "", "go": + golang.Generate(dir, *packageName, DefaultBufferPackage, tc) + case "java": + opts, err := java.FromConfig(*packageName, options) + if err != nil { + log.Fatalf("%s", err) + } + if err := java.Generate(dir, tc, opts); err != nil { + log.Fatalf("%s", err) + } + default: + log.Fatalf("unsupported -lang %q (want go|java)", *lang) + } } diff --git a/internal/generator/context.go b/internal/generator/context.go deleted file mode 100644 index ba98381..0000000 --- a/internal/generator/context.go +++ /dev/null @@ -1,183 +0,0 @@ -package generator - -import ( - "fmt" - "strings" - - "github.com/opencost/bingen/internal/generator/vars" - "github.com/opencost/bingen/internal/types" -) - -// GeneratorContext is a stateful context that controls the flow of generation based on -// the scope of the generation. -type GeneratorContext interface { - // VersionSetConst returns the version set constant used for this generator - VersionSetConst() string - - // HandleError handles any inline errors that occur during reading or writing by returning the - // generated error handling code for the provided error string - HandleError(errString string) string - - // IsStreamable returns true if we should generate streaming implementations of the type - IsStreamable() bool - - // IsStringTable returns true if we store/load a table of strings in the format - IsStringTable() bool - - // IsPreProcess returns true if we should pre process the generated struct before encoding. - IsPreProcess() bool - - // IsPostProcess returns true if we should post process the generated struct before returning. - IsPostProcess() bool - - // IsMigration returns true if we should test for a migration scenario (version delta), and call - // a migration func. - IsMigration() bool - - // NextVar returns the next available general variable name which can be used to avoid collision. - NextVar() string - - // NextMapVar returns the next available map variable name which can be used to avoid collisions. - NextMapVar() string - - // NextLoopVar returns the next available loop index variable name which can be used to avoid collisions. - NextLoopVar() string - - // NextErrVar returns the next available ok variable name. - NextOKVar() string - - // NextErrVar returns the next available error variable name. - NextErrVar() string - - // WithErrorHandler allows the context to be copied with a new error handler override - WithErrorHandler(handler func(string) string) GeneratorContext -} - -// GeneratorContextFactory creates new GeneratorContext instances -type GeneratorContextFactory interface { - // NewContext creates a new GeneratorContext implementation - NewContext(opts *types.GenerateTypeOpts) GeneratorContext -} - -// genContextFactory is the default implementation of GeneratorContextFactory -type genContextFactory struct { - errorHandler func(string) string -} - -// NewContext creates a new GeneratorContext implementation -func (gcf *genContextFactory) NewContext(opts *types.GenerateTypeOpts) GeneratorContext { - if opts == nil { - opts = &types.GenerateTypeOpts{} - } - - return &genContext{ - vsc: fmt.Sprintf("%sCodecVersion", titleCaser.String(opts.SetName)), - opts: opts, - loops: vars.NewAlphaVarNames(vars.SkipAllBut(vars.I, vars.J)...), - maps: vars.NewAlphaVarNames(vars.SkipAllBut(vars.Z, vars.V)...), - vars: vars.NewAlphaVarNames(vars.I, vars.J, vars.K, vars.Z, vars.V), - oks: vars.NewAlphaVarNames(), - errs: vars.NewAlphaVarNames(), - errHandler: gcf.errorHandler, - } -} - -// NewGeneratorContextFactory creates a default GeneratorContext with the default error handler -func NewGeneratorContextFactory(errorHandler func(string) string) GeneratorContextFactory { - return &genContextFactory{ - errorHandler: errorHandler, - } -} - -// genContext is the default implementation of GeneratorContext -type genContext struct { - vsc string - opts *types.GenerateTypeOpts - vars vars.VarNames - loops vars.VarNames - maps vars.VarNames - oks vars.VarNames - errs vars.VarNames - errHandler func(string) string -} - -// WithErrorHandler allows the context to be copied with a new error handler override -func (gc *genContext) WithErrorHandler(handler func(string) string) GeneratorContext { - return &genContext{ - vsc: gc.vsc, - opts: gc.opts, - vars: gc.vars, - loops: gc.loops, - maps: gc.maps, - oks: gc.oks, - errs: gc.errs, - errHandler: handler, - } -} - -// HandleError handles any inline errors that occur during reading or writing by -// returning the generated code to be used in handling the errString provided. -// -// There are two straight-forward implementations here, where the non-streaming generators -// simply return the error, and the streaming variants set the error flag. The default implementation -// is the non-streaming error handler -func (gc *genContext) HandleError(errString string) string { - return gc.errHandler(errString) -} - -func (gc *genContext) VersionSetConst() string { - return gc.vsc -} - -// IsStreamable returns true if we should generate streaming implementations of the type -func (gc *genContext) IsStreamable() bool { - return gc.opts.IsStreamable -} - -// IsStringTable returns true if we store/load a table of strings in the format -func (gc *genContext) IsStringTable() bool { - return gc.opts.IsGenerateStringTable -} - -// IsPreProcess returns true if we should pre process the generated struct before encoding. -func (gc *genContext) IsPreProcess() bool { - return gc.opts.IsPreProcess -} - -// IsPostProcess returns true if we should post process the generated struct before returning. -func (gc *genContext) IsPostProcess() bool { - return gc.opts.IsPostProcess -} - -// IsMigration returns true if we should test for a migration scenario (version delta), and call -// a migration func. -func (gc *genContext) IsMigration() bool { - return gc.opts.IsMigration -} - -// NextVar returns the next available general variable name which can be used to avoid collision. -func (gc *genContext) NextVar() string { - return gc.vars.Next() -} - -// NextMapVar returns the next available map variable name which can be used to avoid collisions. -func (gc *genContext) NextMapVar() string { - return gc.maps.Next() -} - -// NextLoopVar returns the next available loop index variable name which can be used to avoid collisions. -func (gc *genContext) NextLoopVar() string { - return gc.loops.Next() -} - -// NextErrVar returns the next available ok variable name. -func (gc *genContext) NextOKVar() string { - n := gc.oks.Next() - return fmt.Sprintf("ok%s", strings.ToUpper(n)) -} - -// NextErrVar returns the next available error variable name. -func (gc *genContext) NextErrVar() string { - n := gc.errs.Next() - return fmt.Sprintf("err%s", strings.ToUpper(n)) -} diff --git a/internal/generator/core/backend.go b/internal/generator/core/backend.go new file mode 100644 index 0000000..b6733b2 --- /dev/null +++ b/internal/generator/core/backend.go @@ -0,0 +1,121 @@ +package core + +import "github.com/opencost/bingen/internal/types" + +// Backend renders the target-language syntax for each node the core codec walk +// visits. Backend owns type mapping, naming, and how each operation is output. +// Each method documents it's binary contract such that the core's guarantees hold +// across languages. +// +// Callback parameters (whenNil, whenPresent, body, readElem, readPair) are +// invoked by the Backend at the point the recursed code belongs, letting the +// Backend own the surrounding control-flow syntax. +type Backend interface { + // TypeName returns the target type for t. When boxed is true a nullable form + // is required (ie: Java Integer rather than int). The core requests boxed + // for collection elements and pointer values. + TypeName(t types.GenType, boxed bool) string + + // EncodeFieldSource returns the expression reading struct field from the + // value being encoded. + EncodeFieldSource(field string) string + + // CommitField assigns valueExpr into field on the value being built. + CommitField(e *Emit, field string, valueExpr string) + + // Default returns the value expression for a field whose version exceeds the + // payload version. + Default(t types.GenType, opts *types.FieldOpts) string + + // Comment writes a comment to the generated output with the provided text + Comment(e *Emit, text string) + + //-------------------------------------------------------------------------- + // Encode + //-------------------------------------------------------------------------- + + // WriteNilFlag writes the one-byte presence marker: present=1, absent=0. + WriteNilFlag(e *Emit, present bool) + + // NilGuard renders "if target is nil { whenNil } else { whenPresent }". + NilGuard(e *Emit, target string, whenNil, whenPresent func()) + + // WritePrimitive writes a non-string primitive value. + WritePrimitive(e *Emit, t types.GenType, target string) + + // WriteString writes a string as a string-table index or a raw string, + // depending on the runtime context. + WriteString(e *Emit, t types.GenType, target string) + + // WriteSlice writes the element count then iterates, invoking body(elem) to + // encode each element expression. + WriteSlice(e *Emit, t *types.SliceType, target string, body func(elem string)) + + // WriteMap writes the entry count then iterates, invoking body(key, value) + // to encode each pair (key before value). + WriteMap(e *Emit, t *types.MapType, target string, body func(key, value string)) + + // WriteStruct writes the compatibility marker then delegates to the nested + // type's encoder. + WriteStruct(e *Emit, t types.GenType, target string) + + // WriteInterface writes the concrete type name and delegates through the + // registry. + WriteInterface(e *Emit, t types.GenType, target string) + + // WriteExternal writes a non-generated reference type handled by the runtime + // (ie: time.Time). It returns false if name is unsupported. + WriteExternal(e *Emit, t types.GenType, target string) bool + + // EncodeAlias encodes an alias value. body encodes the underlying value; the + // Backend passes it the target cast to the underlying type when the language + // requires it. + EncodeAlias(e *Emit, at *types.AliasType, target string, body func(underlying string)) + + //-------------------------------------------------------------------------- + // Decode + //-------------------------------------------------------------------------- + + // DeclareVar declares an uninitialized local of t's type named v. + DeclareVar(e *Emit, t types.GenType, v string) + + // VersionGate renders "if fieldVersion <= version { whenCompatible } else { + // setDefault }". + VersionGate(e *Emit, fieldVersion uint8, whenCompatible, setDefault func()) + + // ReadNilGuard reads the presence byte, assigning nil to v in the absent + // branch and running whenPresent otherwise. + ReadNilGuard(e *Emit, v string, whenPresent func()) + + // ReadPrimitive reads a non-string primitive into v. + ReadPrimitive(e *Emit, t types.GenType, v string) + + // ReadString reads a string (table index or raw) into v. t is the (possibly + // pointer) string type. + ReadString(e *Emit, t types.GenType, v string) + + // ReadSlice reads the element count then iterates; readElem reads one element + // and returns the variable holding it, which the Backend appends to v. + ReadSlice(e *Emit, t *types.SliceType, v string, readElem func() string) + + // ReadMap reads the entry count then iterates; readPair reads one key/value + // (key before value) and returns their variables, which the Backend puts in v. + ReadMap(e *Emit, t *types.MapType, v string, readPair func() (key, value string)) + + // ReadStruct reads the compatibility marker then delegates to the nested + // type's decoder, into v. + ReadStruct(e *Emit, t types.GenType, v string) + + // ReadInterface reads the concrete type name and delegates through the + // registry, into v. + ReadInterface(e *Emit, t types.GenType, v string) + + // ReadExternal reads a runtime-handled reference type into v. It returns + // false if name is unsupported. + ReadExternal(e *Emit, t types.GenType, v string) bool + + // DecodeAlias decodes into v (declared as the alias type). body reads the + // underlying value into the variable name it is given; the Backend then + // converts it to the alias type as needed (Java passes v through unchanged). + DecodeAlias(e *Emit, at *types.AliasType, v string, body func(underlying string)) +} diff --git a/internal/generator/core/emit.go b/internal/generator/core/emit.go new file mode 100644 index 0000000..7105d49 --- /dev/null +++ b/internal/generator/core/emit.go @@ -0,0 +1,83 @@ +// Package core is the language-neutral core of the bingen code generators. It +// walks the type IR and drives the binary format structure (field ordering, nil +// flags, string-table branching, version gating, reference/alias resolution, +// and recursion), delegating all target-language syntax to a Backend implementation. +package core + +import ( + "fmt" + "sort" + "strings" +) + +// Emit accumulates generated source lines with indentation, unique variable +// names, the set of required imports, and the first error encountered. +type Emit struct { + sb strings.Builder + nextVar int + indent int + imports map[string]bool + err error +} + +// NewEmit returns an Emit that starts at the given indent level. +func NewEmit(indent int) *Emit { + return &Emit{ + indent: indent, + imports: make(map[string]bool), + } +} + +// NextVar returns a new unique local variable name. +func (e *Emit) NextVar() string { + v := fmt.Sprintf("v%d", e.nextVar) + e.nextVar++ + return v +} + +// Line writes a single indented line. +func (e *Emit) Line(s string) { + e.sb.WriteString(strings.Repeat(" ", e.indent)) + e.sb.WriteString(s) + e.sb.WriteByte('\n') +} + +// Linef writes a single indented, formatted line. +func (e *Emit) Linef(format string, args ...any) { + e.Line(fmt.Sprintf(format, args...)) +} + +// Indented runs body with one additional level of indentation. +func (e *Emit) Indented(body func()) { + e.indent++ + body() + e.indent-- +} + +// Import records a required import. +func (e *Emit) Import(imp string) { + e.imports[imp] = true +} + +// Errf records the first error encountered; later calls are ignored. +func (e *Emit) Errf(format string, args ...any) { + if e.err == nil { + e.err = fmt.Errorf(format, args...) + } +} + +// Result returns the rendered body (trailing newline trimmed), the sorted set of +// required imports, and any error captured. +func (e *Emit) Result() (string, []string, error) { + if e.err != nil { + return "", nil, e.err + } + + imports := make([]string, 0, len(e.imports)) + for imp := range e.imports { + imports = append(imports, imp) + } + sort.Strings(imports) + + return strings.TrimRight(e.sb.String(), "\n"), imports, nil +} diff --git a/internal/generator/core/scope.go b/internal/generator/core/scope.go new file mode 100644 index 0000000..f657eb7 --- /dev/null +++ b/internal/generator/core/scope.go @@ -0,0 +1,46 @@ +package core + +import "fmt" + +// DebugScope is used to output lead and trailing emissions during code generation +type DebugScope interface { + Begin() DebugScope + End() +} + +// just a default debug emission scope that writes a comment delimitting the start/end +// of an encode/decode scope +type emitScope struct { + b Backend + e *Emit + label string + header string + typeName string +} + +// creates a new debug scope emission +func newDebugScope(b Backend, e *Emit, label string, header string, typeName string) DebugScope { + return &emitScope{ + b: b, + e: e, + label: label, + header: header, + typeName: typeName, + } +} + +// BeginDebugScope creates a new DebugScope and calls Begin() +func BeginDebugScope(b Backend, e *Emit, label, header, typeName string) DebugScope { + return newDebugScope(b, e, label, header, typeName).Begin() +} + +func (es *emitScope) Begin() DebugScope { + t := fmt.Sprintf("--- [begin][%s][%s](%s) ---", es.label, es.header, es.typeName) + es.b.Comment(es.e, t) + return es +} + +func (es *emitScope) End() { + t := fmt.Sprintf("--- [end][%s][%s](%s) ---", es.label, es.header, es.typeName) + es.b.Comment(es.e, t) +} diff --git a/internal/generator/core/stream.go b/internal/generator/core/stream.go new file mode 100644 index 0000000..33e021f --- /dev/null +++ b/internal/generator/core/stream.go @@ -0,0 +1,135 @@ +package core + +import "github.com/opencost/bingen/internal/types" + +// StreamBackend renders a streaming decoder. Instead of building a value, it +// yields each field and a single depth of all slices and maps on the type to +// consumer. It reuses the read-value methods from Backend for scalars, structs, +// interfaces, and references, and adds the yield/collection primitives below. +type StreamBackend interface { + Backend + + // FieldInfo emits the per-field descriptor (name + type) that subsequent + // yields reference. + FieldInfo(e *Emit, name string, t types.GenType) + + // Yield yields a single value for the current field. + Yield(e *Emit, value string) + + // YieldNil yields a nil value for the current field. + YieldNil(e *Emit) + + // YieldIndexed yields one element of a flattened collection with its index or + // key. + YieldIndexed(e *Emit, index, value string) + + // StreamNilGuard reads the presence byte, running whenNil in the absent + // branch and whenPresent otherwise. + StreamNilGuard(e *Emit, whenNil, whenPresent func()) + + // StreamSlice reads the element count then iterates, invoking body(idx) per + // element (body reads the element and yields it indexed). + StreamSlice(e *Emit, t *types.SliceType, body func(index string)) + + // StreamMap reads the entry count then iterates, invoking body() per entry + // (body reads the key/value and yields them keyed). + StreamMap(e *Emit, t *types.MapType, body func()) + + // StreamDefault yields the default for a field newer than the payload + // version (nil for nilable, the zero/annotation default for basics, nothing + // for other types without an explicit default). + StreamDefault(e *Emit, t types.GenType, opts *types.FieldOpts) +} + +// StreamStruct renders the streaming-decode body for the provided StructType by yielding +// each of it's fields, in order. +func StreamStruct(b StreamBackend, st *types.StructType) (string, []string, error) { + e := NewEmit(2) + for _, f := range st.Fields { + streamField(e, b, f) + } + return e.Result() +} + +func streamField(e *Emit, b StreamBackend, f *types.StructField) { + b.FieldInfo(e, f.Name, f.Type) + + var fieldVersion uint8 + if f.Opts != nil { + fieldVersion = f.Opts.Version + } + + if fieldVersion == 0 { + streamType(e, b, f.Type) + return + } + + b.VersionGate( + e, + fieldVersion, + func() { + streamType(e, b, f.Type) + }, + func() { + b.StreamDefault(e, f.Type, f.Opts) + }) +} + +func streamType(e *Emit, b StreamBackend, t types.GenType) { + if !t.IsNilable() { + streamRaw(e, b, t) + return + } + + b.StreamNilGuard( + e, + func() { + b.YieldNil(e) + }, + func() { + streamRaw(e, b, t) + }) +} + +func streamRaw(e *Emit, b StreamBackend, t types.GenType) { + code := t.Code() + + switch code { + case types.TypeSlice: + st := t.(*types.SliceType) + b.StreamSlice(e, st, func(index string) { + b.YieldIndexed(e, index, decodeValue(e, b, st.InnerType)) + }) + + case types.TypeMap: + mt := t.(*types.MapType) + b.StreamMap(e, mt, func() { + key := decodeValue(e, b, mt.KeyType) + value := decodeValue(e, b, mt.ValueType) + b.YieldIndexed(e, key, value) + }) + + case types.TypeAlias: + // An alias of a collection streams its underlying collection element by + // element; any other alias is fully read and yielded as a single value. + inner := t.(*types.AliasType).Alias + innerCode := inner.Code() + + if innerCode == types.TypeSlice || innerCode == types.TypeMap { + streamRaw(e, b, inner) + return + } + streamSingle(e, b, t) + + default: + streamSingle(e, b, t) + } +} + +// streamSingle reads a whole value into a new variable and yields it to the consumer. +func streamSingle(e *Emit, b StreamBackend, t types.GenType) { + v := e.NextVar() + b.DeclareVar(e, t, v) + decodeRaw(e, b, t, v) + b.Yield(e, v) +} diff --git a/internal/generator/core/walk.go b/internal/generator/core/walk.go new file mode 100644 index 0000000..0ca9dfd --- /dev/null +++ b/internal/generator/core/walk.go @@ -0,0 +1,184 @@ +package core + +import "github.com/opencost/bingen/internal/types" + +// EncodeStruct renders the field encoding body for the provided types.StructType in +// field order, through the nil-flag and type dispatch. The surrounding method's version +// and hook handling is provided by the Backend implementation. +func EncodeStruct(b Backend, st *types.StructType) (string, []string, error) { + e := NewEmit(2) + for _, f := range st.Fields { + encodeType(e, b, f.Type, b.EncodeFieldSource(f.Name)) + } + return e.Result() +} + +// encodeType writes a leading presence byte for nilable types, then the raw +// value. Aliases re-enter here (not encodeRaw) so an alias of a nilable type +// keeps its nil flag +func encodeType(e *Emit, b Backend, t types.GenType, target string) { + if !t.IsNilable() { + encodeRaw(e, b, t, target) + return + } + + b.NilGuard(e, target, + func() { + b.WriteNilFlag(e, false) + }, + func() { + b.WriteNilFlag(e, true) + encodeRaw(e, b, t, target) + }) +} + +func encodeRaw(e *Emit, b Backend, t types.GenType, target string) { + code := t.Code() + + // handle non-string primitive values first + if types.IsNonStringPrimitive(code) { + b.WritePrimitive(e, t, target) + return + } + + // handle remaining types + switch code { + case types.TypeString: + b.WriteString(e, t, target) + case types.TypeSlice: + st := t.(*types.SliceType) + b.WriteSlice(e, st, target, func(elem string) { + encodeType(e, b, st.InnerType, elem) + }) + case types.TypeMap: + mt := t.(*types.MapType) + b.WriteMap(e, mt, target, func(key, value string) { + encodeType(e, b, mt.KeyType, key) + encodeType(e, b, mt.ValueType, value) + }) + case types.TypeStruct: + b.WriteStruct(e, t, target) + case types.TypeInterface: + b.WriteInterface(e, t, target) + case types.TypeAlias: + at := t.(*types.AliasType) + b.EncodeAlias(e, at, target, func(underlying string) { + encodeType(e, b, at.Alias, underlying) + }) + case types.TypeReference: + if resolved := t.(*types.ReferenceType).Resolve(); resolved != nil { + encodeRaw(e, b, resolved, target) + return + } + if !b.WriteExternal(e, t, target) { + e.Errf("unsupported external reference type %q", t.Name()) + } + + default: + e.Errf("unsupported type %q (code %d)", t.Name(), code) + } +} + +// DecodeStruct renders the field-decoding body for st, committing each field to +// the Backend's builder. The surrounding method (version read/check, build, +// migrate/post-process hooks) belongs to the Backend's file scaffolding. +func DecodeStruct(b Backend, st *types.StructType) (string, []string, error) { + e := NewEmit(2) + for _, f := range st.Fields { + decodeField(e, b, f) + } + return e.Result() +} + +// decodeField applies version gating: fields newer than the payload version get +// the default; otherwise the value is read and committed. +func decodeField(e *Emit, b Backend, f *types.StructField) { + var fieldVersion uint8 + if f.Opts != nil { + fieldVersion = f.Opts.Version + } + + if fieldVersion == 0 { + b.CommitField(e, f.Name, decodeValue(e, b, f.Type)) + return + } + + b.VersionGate( + e, + fieldVersion, + func() { + b.CommitField(e, f.Name, decodeValue(e, b, f.Type)) + }, + func() { + b.CommitField(e, f.Name, b.Default(f.Type, f.Opts)) + }) +} + +// decodeValue declares a new variable, reads into it, and returns its name. +func decodeValue(e *Emit, b Backend, t types.GenType) string { + v := e.NextVar() + + b.DeclareVar(e, t, v) + decodeInto(e, b, t, v) + + return v +} + +// decodeInto reads a leading presence byte for nilable types, then the raw +// value. Aliases re-enter here (not decodeRaw) so an alias of a nilable type +// consumes its nil flag, mirroring encodeType. +func decodeInto(e *Emit, b Backend, t types.GenType, v string) { + if !t.IsNilable() { + decodeRaw(e, b, t, v) + return + } + + b.ReadNilGuard(e, v, func() { + decodeRaw(e, b, t, v) + }) +} + +func decodeRaw(e *Emit, b Backend, t types.GenType, v string) { + code := t.Code() + + // handle non-string primitive values first + if types.IsNonStringPrimitive(code) { + b.ReadPrimitive(e, t, v) + return + } + + switch code { + case types.TypeString: + b.ReadString(e, t, v) + case types.TypeSlice: + st := t.(*types.SliceType) + b.ReadSlice(e, st, v, func() string { + return decodeValue(e, b, st.InnerType) + }) + case types.TypeMap: + mt := t.(*types.MapType) + b.ReadMap(e, mt, v, func() (string, string) { + return decodeValue(e, b, mt.KeyType), decodeValue(e, b, mt.ValueType) + }) + case types.TypeStruct: + b.ReadStruct(e, t, v) + case types.TypeInterface: + b.ReadInterface(e, t, v) + case types.TypeAlias: + at := t.(*types.AliasType) + b.DecodeAlias(e, at, v, func(underlying string) { + decodeInto(e, b, at.Alias, underlying) + }) + case types.TypeReference: + if resolved := t.(*types.ReferenceType).Resolve(); resolved != nil { + decodeRaw(e, b, resolved, v) + return + } + if !b.ReadExternal(e, t, v) { + e.Errf("unsupported external reference type %q", t.Name()) + } + + default: + e.Errf("unsupported type %q (code %d)", t.Name(), code) + } +} diff --git a/internal/generator/golang/backend.go b/internal/generator/golang/backend.go new file mode 100644 index 0000000..0ce52e1 --- /dev/null +++ b/internal/generator/golang/backend.go @@ -0,0 +1,588 @@ +package golang + +import ( + "fmt" + "strings" + + "github.com/opencost/bingen/internal/generator/core" + "github.com/opencost/bingen/internal/types" +) + +// GoBackend renders Go marshal/unmarshal statements for the core codec walk, +// mirroring internal/generator/templates/go/{marshaller,unmarshaller}.go.tmpl. +// The generated file is run through go/format + goimports, so this backend does +// not track imports. +type GoBackend struct { + // streaming selects the error-handling form: streaming decoders run inside a + // range-over-func that returns nothing, so errors set stream.err and return + // bare rather than `return err`. + streaming bool +} + +func NewGoBackend() *GoBackend { + return &GoBackend{} +} + +func NewGoStreamBackend() *GoBackend { + return &GoBackend{ + streaming: true, + } +} + +// primitive type to write methods on the buffer +var goWrite = map[uint8]string{ + types.TypeBool: "WriteBool", + types.TypeInt: "WriteInt", + types.TypeInt8: "WriteInt8", + types.TypeInt16: "WriteInt16", + types.TypeInt32: "WriteInt32", + types.TypeInt64: "WriteInt64", + types.TypeUInt: "WriteUInt", + types.TypeUInt8: "WriteUInt8", + types.TypeUInt16: "WriteUInt16", + types.TypeUInt32: "WriteUInt32", + types.TypeUInt64: "WriteUInt64", + types.TypeFloat32: "WriteFloat32", + types.TypeFloat64: "WriteFloat64", +} + +// primitive type to read methods on the buffer +var goRead = map[uint8]string{ + types.TypeBool: "ReadBool", + types.TypeInt: "ReadInt", + types.TypeInt8: "ReadInt8", + types.TypeInt16: "ReadInt16", + types.TypeInt32: "ReadInt32", + types.TypeInt64: "ReadInt64", + types.TypeUInt: "ReadUInt", + types.TypeUInt8: "ReadUInt8", + types.TypeUInt16: "ReadUInt16", + types.TypeUInt32: "ReadUInt32", + types.TypeUInt64: "ReadUInt64", + types.TypeFloat32: "ReadFloat32", + types.TypeFloat64: "ReadFloat64", +} + +// goDefaultCast maps a numeric primitive to its cast form, reproducing the +// template's ToDefaultValue. +var goDefaultCast = map[uint8]string{ + types.TypeInt: "int", + types.TypeInt8: "int8", + types.TypeInt16: "int16", + types.TypeInt32: "int32", + types.TypeInt64: "int64", + types.TypeUInt: "uint", + types.TypeUInt8: "uint8", + types.TypeUInt16: "uint16", + types.TypeUInt32: "uint32", + types.TypeUInt64: "uint64", + types.TypeFloat32: "float32", + types.TypeFloat64: "float64", +} + +func (g *GoBackend) TypeName(t types.GenType, boxed bool) string { + return t.TypeName() +} + +func (g *GoBackend) EncodeFieldSource(field string) string { + return "target." + field +} + +func (g *GoBackend) CommitField(e *core.Emit, field, valueExpr string) { + e.Linef("target.%s = %s", field, valueExpr) +} + +func (g *GoBackend) Default(t types.GenType, opts *types.FieldOpts) string { + if t.IsNilable() { + return "nil" + } + + def := "" + if opts != nil { + def = opts.Default + } + + code := t.Code() + + // bool default + if code == types.TypeBool { + if def == "" { + return "false" + } + return def + } + + // number primitive default + if types.IsNumericalPrimitive(code) { + if def == "" { + def = "0" + } + + return fmt.Sprintf("%s(%s)", goDefaultCast[code], def) + } + + // string primitive default + if code == types.TypeString { + return fmt.Sprintf("%q", def) + } + + // all other type defaults + if def != "" { + return def + } + return t.Name() + "{}" +} + +// Comment writes a comment to the generated output with the provided text +func (g *GoBackend) Comment(e *core.Emit, text string) { + for line := range strings.Lines(text) { + e.Linef("// %s", line) + } +} + +//-------------------------------------------------------------------------- +// Encode +//-------------------------------------------------------------------------- + +func (g *GoBackend) WriteNilFlag(e *core.Emit, present bool) { + if present { + e.Line("buff.WriteUInt8(uint8(1)) // write non-nil byte") + } else { + e.Line("buff.WriteUInt8(uint8(0)) // write nil byte") + } +} + +func (g *GoBackend) NilGuard(e *core.Emit, target string, whenNil, whenPresent func()) { + e.Linef("if %s == nil {", target) + e.Indented(whenNil) + e.Line("} else {") + e.Indented(whenPresent) + e.Line("}") +} + +func (g *GoBackend) WritePrimitive(e *core.Emit, t types.GenType, target string) { + if t.IsPtr() { + target = "*" + target + } + + e.Linef("buff.%s(%s)", goWrite[t.Code()], target) +} + +func (g *GoBackend) WriteString(e *core.Emit, t types.GenType, target string) { + if t.IsPtr() { + target = "*" + target + } + + idx := e.NextVar() + + e.Line("if ctx.IsStringTable() {") + e.Indented(func() { + e.Linef("%s := ctx.Table.AddOrGet(%s)", idx, target) + e.Linef("buff.WriteInt(%s) // write table index", idx) + }) + e.Line("} else {") + e.Indented(func() { + e.Linef("buff.WriteString(%s) // write string", target) + }) + e.Line("}") +} + +func (g *GoBackend) WriteSlice(e *core.Emit, t *types.SliceType, target string, body func(elem string)) { + loop := e.NextVar() + + ds := core.BeginDebugScope(g, e, "write", "slice", t.Name()) + defer ds.End() + + e.Linef("buff.WriteInt(len(%s)) // slice length", target) + e.Linef("for %s := range %s {", loop, target) + e.Indented(func() { + body(fmt.Sprintf("%s[%s]", target, loop)) + }) + e.Line("}") +} + +func (g *GoBackend) WriteMap(e *core.Emit, t *types.MapType, target string, body func(key, value string)) { + k := e.NextVar() + v := e.NextVar() + + ds := core.BeginDebugScope(g, e, "write", "map", t.TypeName()) + defer ds.End() + + e.Linef("buff.WriteInt(len(%s)) // map length", target) + e.Linef("for %s, %s := range %s {", k, v, target) + e.Indented(func() { + body(k, v) + }) + e.Line("}") +} + +func (g *GoBackend) WriteStruct(e *core.Emit, t types.GenType, target string) { + err := e.NextVar() + + ds := core.BeginDebugScope(g, e, "write", "struct", t.Name()) + defer ds.End() + + e.Line("buff.WriteInt(0) // [compatibility, unused]") + e.Linef("%s := %s.MarshalBinaryWithContext(ctx)", err, target) + g.returnIfErr(e, err) +} + +func (g *GoBackend) WriteInterface(e *core.Emit, t types.GenType, target string) { + iv := e.NextVar() + mv := e.NextVar() + ok := e.NextVar() + err := e.NextVar() + + ds := core.BeginDebugScope(g, e, "write", "interface", t.Name()) + defer ds.End() + + e.Linef("%s := reflect.ValueOf(%s).Interface()", iv, target) + e.Linef("%s, %s := %s.(BinEncoder)", mv, ok, iv) + e.Linef("if !%s {", ok) + e.Indented(func() { + e.Linef(`return fmt.Errorf("type: %%s does not implement %%s.BinEncoder", typeToString(%s), GeneratorPackageName)`, target) + }) + e.Line("}") + + e.Linef("buff.WriteString(typeToString(%s))", target) + e.Line("buff.WriteInt(0) // [compatibility, unused]") + e.Linef("%s := %s.MarshalBinaryWithContext(ctx)", err, mv) + g.returnIfErr(e, err) +} + +func (g *GoBackend) WriteExternal(e *core.Emit, t types.GenType, target string) bool { + // Go handles any unresolved reference generically via its BinaryMarshaler. + data := e.NextVar() + err := e.NextVar() + + ds := core.BeginDebugScope(g, e, "write", "reference", t.Name()) + defer ds.End() + + e.Linef("%s, %s := %s.MarshalBinary()", data, err, target) + g.returnIfErr(e, err) + e.Linef("buff.WriteInt(len(%s))", data) + e.Linef("buff.WriteBytes(%s)", data) + + return true +} + +func (g *GoBackend) EncodeAlias(e *core.Emit, at *types.AliasType, target string, body func(underlying string)) { + inner := target + if at.IsPtr() { + inner = "*" + target + } + + var casted string + if at.Alias.IsPtr() { + casted = fmt.Sprintf("((%s)(%s))", at.Alias.TypeName(), inner) + } else { + casted = fmt.Sprintf("%s(%s)", at.Alias.TypeName(), inner) + } + + ds := core.BeginDebugScope(g, e, "write", "alias", at.Name()) + defer ds.End() + + body(casted) +} + +//-------------------------------------------------------------------------- +// Decode +//-------------------------------------------------------------------------- + +func (g *GoBackend) DeclareVar(e *core.Emit, t types.GenType, v string) { + e.Linef("var %s %s", v, t.TypeName()) +} + +func (g *GoBackend) VersionGate(e *core.Emit, fieldVersion uint8, whenCompatible, setDefault func()) { + e.Linef("if uint8(%d) <= version {", fieldVersion) + e.Indented(whenCompatible) + e.Line("} else {") + e.Indented(setDefault) + e.Line("}") +} + +func (g *GoBackend) ReadNilGuard(e *core.Emit, v string, whenPresent func()) { + e.Line("if buff.ReadUInt8() == uint8(0) {") + e.Indented(func() { + e.Linef("%s = nil", v) + }) + e.Line("} else {") + e.Indented(whenPresent) + e.Line("}") +} + +func (g *GoBackend) ReadPrimitive(e *core.Emit, t types.GenType, v string) { + if t.IsPtr() { + tmp := e.NextVar() + + e.Linef("%s := buff.%s()", tmp, goRead[t.Code()]) + e.Linef("%s = &%s", v, tmp) + return + } + + e.Linef("%s = buff.%s()", v, goRead[t.Code()]) +} + +func (g *GoBackend) ReadString(e *core.Emit, t types.GenType, v string) { + dest := v + + if t.IsPtr() { + tmp := e.NextVar() + + e.Linef("var %s string", tmp) + g.readStringInto(e, tmp) + e.Linef("%s = &%s", v, tmp) + return + } + + g.readStringInto(e, dest) +} + +func (g *GoBackend) readStringInto(e *core.Emit, dest string) { + idx := e.NextVar() + + e.Line("if ctx.IsStringTable() {") + e.Indented(func() { + e.Linef("%s := buff.ReadInt() // read string index", idx) + e.Linef("%s = ctx.Table.At(%s)", dest, idx) + }) + e.Line("} else {") + e.Indented(func() { + e.Linef("%s = buff.ReadString() // read string", dest) + }) + e.Line("}") +} + +func (g *GoBackend) ReadSlice(e *core.Emit, t *types.SliceType, v string, readElem func() string) { + ln := e.NextVar() + loop := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "slice", t.Name()) + defer ds.End() + + e.Linef("%s := buff.ReadInt() // slice len", ln) + e.Linef("%s = make(%s, %s)", v, t.TypeName(), ln) + e.Linef("for %s := range %s {", loop, ln) + e.Indented(func() { + e.Linef("%s[%s] = %s", v, loop, readElem()) + }) + e.Line("}") +} + +func (g *GoBackend) ReadMap(e *core.Emit, t *types.MapType, v string, readPair func() (key, value string)) { + ln := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "map", t.Name()) + defer ds.End() + + e.Linef("%s := buff.ReadInt() // map len ", ln) + e.Linef("%s = make(%s, %s)", v, t.TypeName(), ln) + e.Linef("for range %s {", ln) + e.Indented(func() { + key, value := readPair() + e.Linef("%s[%s] = %s", v, key, value) + }) + e.Line("}") +} + +func (g *GoBackend) ReadStruct(e *core.Emit, t types.GenType, v string) { + ub := e.NextVar() + err := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "struct", t.Name()) + defer ds.End() + + e.Linef("%s := new(%s)", ub, t.Name()) + e.Line("buff.ReadInt() // [compatibility, unused]") + e.Linef("%s := %s.UnmarshalBinaryWithContext(ctx)", err, ub) + g.returnIfErr(e, err) + if t.IsPtr() { + e.Linef("%s = %s", v, ub) + } else { + e.Linef("%s = *%s", v, ub) + } +} + +func (g *GoBackend) ReadInterface(e *core.Emit, t types.GenType, v string) { + tn := e.NextVar() + nm := e.NextVar() + ub := e.NextVar() + ok := e.NextVar() + err := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "interface", t.Name()) + defer ds.End() + + e.Linef("%s := buff.ReadString()", tn) + e.Linef("_, %s, _ := resolveType(%s)", nm, tn) + e.Linef("if _, ok := typeMap[%s]; !ok {", nm) + e.Indented(func() { + g.fail(e, fmt.Sprintf(`fmt.Errorf("unknown type: %%s", %s)`, nm)) + }) + e.Line("}") + e.Linef("%s, %s := reflect.New(typeMap[%s]).Interface().(BinDecoder)", ub, ok, nm) + e.Linef("if !%s {", ok) + e.Indented(func() { + g.fail(e, fmt.Sprintf(`fmt.Errorf("type: %%s does not implement %%s.BinDecoder.", %s, GeneratorPackageName)`, nm)) + }) + e.Line("}") + e.Line("buff.ReadInt() // [compatibility, unused]") + e.Linef("%s := %s.UnmarshalBinaryWithContext(ctx)", err, ub) + g.returnIfErr(e, err) + e.Linef("%s = %s.(%s)", v, ub, t.Name()) +} + +func (g *GoBackend) ReadExternal(e *core.Emit, t types.GenType, v string) bool { + ub := e.NextVar() + ln := e.NextVar() + ba := e.NextVar() + err := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "reference", t.Name()) + defer ds.End() + + e.Linef("%s := new(%s)", ub, t.Name()) + e.Linef("%s := buff.ReadInt() // byte array length", ln) + e.Linef("%s := buff.ReadBytes(%s)", ba, ln) + e.Linef("%s := %s.UnmarshalBinary(%s)", err, ub, ba) + g.returnIfErr(e, err) + if t.IsPtr() { + e.Linef("%s = %s", v, ub) + } else { + e.Linef("%s = *%s", v, ub) + } + + return true +} + +func (g *GoBackend) DecodeAlias(e *core.Emit, at *types.AliasType, v string, body func(underlying string)) { + tmp := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "alias", at.Name()) + defer ds.End() + + e.Linef("var %s %s", tmp, at.Alias.TypeName()) + + body(tmp) + + if at.IsPtr() { + cast := e.NextVar() + e.Linef("%s := %s(%s)", cast, at.Name(), tmp) + e.Linef("%s = &%s", v, cast) + } else { + e.Linef("%s = %s(%s)", v, at.Name(), tmp) + } +} + +func (g *GoBackend) returnIfErr(e *core.Emit, err string) { + e.Linef("if %s != nil {", err) + e.Indented(func() { + g.fail(e, err) + }) + e.Line("}") +} + +// fail emits an early exit with an error: `return err` normally, or +// `stream.err = err; return` inside a streaming range-over-func. +func (g *GoBackend) fail(e *core.Emit, errExpr string) { + if g.streaming { + e.Linef("stream.err = %s", errExpr) + e.Line("return") + return + } + + e.Linef("return %s", errExpr) +} + +//-------------------------------------------------------------------------- +// Streaming +//-------------------------------------------------------------------------- + +func (g *GoBackend) FieldInfo(e *core.Emit, name string, t types.GenType) { + e.Line("fi = bstream.BingenFieldInfo{") + e.Indented(func() { + e.Linef("Type: reflect.TypeFor[%s](),", t.TypeName()) + e.Linef("Name: %q,", name) + }) + e.Line("}") +} + +func (g *GoBackend) Yield(e *core.Emit, value string) { + g.yield(e, fmt.Sprintf("bstream.SingleV(%s)", value)) +} + +func (g *GoBackend) YieldNil(e *core.Emit) { + g.yield(e, "nil") +} + +func (g *GoBackend) YieldIndexed(e *core.Emit, index, value string) { + g.yield(e, fmt.Sprintf("bstream.PairV(%s, %s)", index, value)) +} + +func (g *GoBackend) yield(e *core.Emit, valueExpr string) { + e.Linef("if !yield(fi, %s) {", valueExpr) + e.Indented(func() { + e.Line("return") + }) + e.Line("}") +} + +func (g *GoBackend) StreamNilGuard(e *core.Emit, whenNil, whenPresent func()) { + e.Line("if buff.ReadUInt8() == uint8(0) {") + e.Indented(whenNil) + e.Line("} else {") + e.Indented(whenPresent) + e.Line("}") +} + +func (g *GoBackend) StreamSlice(e *core.Emit, t *types.SliceType, body func(index string)) { + ln := e.NextVar() + loop := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "streaming-slice", t.Name()) + defer ds.End() + + e.Linef("%s := buff.ReadInt() // slice len", ln) + e.Linef("for %s := range %s {", loop, ln) + e.Indented(func() { + body(loop) + }) + e.Line("}") +} + +func (g *GoBackend) StreamMap(e *core.Emit, t *types.MapType, body func()) { + ln := e.NextVar() + + ds := core.BeginDebugScope(g, e, "read", "streaming-map", t.Name()) + defer ds.End() + + e.Linef("%s := buff.ReadInt() // map len", ln) + e.Linef("for range %s {", ln) + e.Indented(body) + e.Line("}") +} + +func (g *GoBackend) StreamDefault(e *core.Emit, t types.GenType, opts *types.FieldOpts) { + if t.IsNilable() { + g.YieldNil(e) + return + } + + if t.Code() <= types.TypeString { + v := e.NextVar() + e.Linef("var %s %s = %s // default", v, t.TypeName(), g.Default(t, opts)) + g.Yield(e, v) + return + } + + def := "" + if opts != nil { + def = opts.Default + } + + if def != "" { + v := e.NextVar() + e.Linef("var %s %s = %s // default", v, t.TypeName(), def) + g.Yield(e, v) + } +} diff --git a/internal/generator/golang/context.go b/internal/generator/golang/context.go new file mode 100644 index 0000000..0f09e5f --- /dev/null +++ b/internal/generator/golang/context.go @@ -0,0 +1,92 @@ +package golang + +import ( + "fmt" + + "github.com/opencost/bingen/internal/types" +) + +// GeneratorContext exposes the per-type flags and constants the marshaller, +// unmarshaller, and streamer method skeletons need. +type GeneratorContext interface { + // VersionSetConst returns the version set constant used for this generator + VersionSetConst() string + + // IsStreamable returns true if we should generate streaming implementations of the type + IsStreamable() bool + + // IsStringTable returns true if we store/load a table of strings in the format + IsStringTable() bool + + // IsPreProcess returns true if we should pre process the generated struct before encoding. + IsPreProcess() bool + + // IsPostProcess returns true if we should post process the generated struct before returning. + IsPostProcess() bool + + // IsMigration returns true if we should test for a migration scenario (version delta), and call + // a migration func. + IsMigration() bool +} + +// GeneratorContextFactory creates new GeneratorContext instances +type GeneratorContextFactory interface { + // NewContext creates a new GeneratorContext implementation + NewContext(opts *types.GenerateTypeOpts) GeneratorContext +} + +// genContextFactory is the default implementation of GeneratorContextFactory +type genContextFactory struct{} + +// NewContext creates a new GeneratorContext implementation +func (gcf *genContextFactory) NewContext(opts *types.GenerateTypeOpts) GeneratorContext { + if opts == nil { + opts = &types.GenerateTypeOpts{} + } + + return &genContext{ + vsc: fmt.Sprintf("%sCodecVersion", titleCaser.String(opts.SetName)), + opts: opts, + } +} + +// NewGeneratorContextFactory creates the default GeneratorContextFactory. +func NewGeneratorContextFactory() GeneratorContextFactory { + return &genContextFactory{} +} + +// genContext is the default implementation of GeneratorContext +type genContext struct { + vsc string + opts *types.GenerateTypeOpts +} + +func (gc *genContext) VersionSetConst() string { + return gc.vsc +} + +// IsStreamable returns true if we should generate streaming implementations of the type +func (gc *genContext) IsStreamable() bool { + return gc.opts.IsStreamable +} + +// IsStringTable returns true if we store/load a table of strings in the format +func (gc *genContext) IsStringTable() bool { + return gc.opts.IsGenerateStringTable +} + +// IsPreProcess returns true if we should pre process the generated struct before encoding. +func (gc *genContext) IsPreProcess() bool { + return gc.opts.IsPreProcess +} + +// IsPostProcess returns true if we should post process the generated struct before returning. +func (gc *genContext) IsPostProcess() bool { + return gc.opts.IsPostProcess +} + +// IsMigration returns true if we should test for a migration scenario (version delta), and call +// a migration func. +func (gc *genContext) IsMigration() bool { + return gc.opts.IsMigration +} diff --git a/internal/generator/bingen.go b/internal/generator/golang/generate.go similarity index 79% rename from internal/generator/bingen.go rename to internal/generator/golang/generate.go index e24b935..822d2c0 100644 --- a/internal/generator/bingen.go +++ b/internal/generator/golang/generate.go @@ -1,4 +1,4 @@ -package generator +package golang import ( "bytes" @@ -10,13 +10,14 @@ import ( importsfmt "golang.org/x/tools/imports" + "github.com/opencost/bingen/internal/generator/core" "github.com/opencost/bingen/internal/types" ) func Generate(dir string, pkg string, bufferImport string, tc types.TypeCollection) { var out bytes.Buffer - ctxFactory := NewGeneratorContextFactory(ErrorHandler) + ctxFactory := NewGeneratorContextFactory() targetTypes := tc.Types() // Sort Types to ensure Deterministic Ordering @@ -36,28 +37,48 @@ func Generate(dir string, pkg string, bufferImport string, tc types.TypeCollecti panic(err) } + goBackend := NewGoBackend() + for _, t := range targetTypes { if st, ok := t.(*types.StructType); ok { + marshalBody, _, err := core.EncodeStruct(goBackend, st) + if err != nil { + panic(err) + } + err = WriteMarshallerTemplate(&out, MarshallerParams{ Context: ctxFactory.NewContext(st.Opts), Type: t, + Body: marshalBody, }) if err != nil { panic(err) } + unmarshalBody, _, err := core.DecodeStruct(goBackend, st) + if err != nil { + panic(err) + } + err = WriteUnmarshallerTemplate(&out, UnmarshallerParams{ Context: ctxFactory.NewContext(st.Opts), Type: t, + Body: unmarshalBody, }) if err != nil { panic(err) } if st.Opts.IsStreamable { + streamBody, _, err := core.StreamStruct(NewGoStreamBackend(), st) + if err != nil { + panic(err) + } + err = WriteStreamerTemplate(&out, StreamParams{ - Context: ctxFactory.NewContext(st.Opts).WithErrorHandler(StreamErrorHandler), + Context: ctxFactory.NewContext(st.Opts), Type: t, + Body: streamBody, }) if err != nil { panic(err) @@ -95,14 +116,6 @@ func Generate(dir string, pkg string, bufferImport string, tc types.TypeCollecti } } -func ErrorHandler(newErr string) string { - return fmt.Sprintf("return %s", newErr) -} - -func StreamErrorHandler(errString string) string { - return "stream.err = " + errString + "\nreturn\n" -} - func toStreamableTypes(ts []types.GenType) []*types.StructType { streamTypes := []*types.StructType{} diff --git a/internal/generator/golang/templates.go b/internal/generator/golang/templates.go new file mode 100644 index 0000000..bfde574 --- /dev/null +++ b/internal/generator/golang/templates.go @@ -0,0 +1,112 @@ +package golang + +import ( + "embed" + "io" + "text/template" + + "github.com/opencost/bingen/internal/meta" + "github.com/opencost/bingen/internal/types" + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +const ( + // BingenSupportTemplate is the template name for supporting bingen code, including the file + // header, package declaration, imports, and various utilities. + BingenSupportTemplate = "support.go.tmpl" + + // BingenMarshallerTemplate is the template name for the binary marshalling generation. It contains + // the MarshalBinary() implementation as well as various sub-templates for writing different types. + BingenMarshallerTemplate = "marshaller.go.tmpl" + + // BingenUnmarshallerTemplate is the template name for the binary unmarshalling generation. It contains + // the UnmarshalBinary() implementation as well as various sub-templates for reading different types. + BingenUnmarshallerTemplate = "unmarshaller.go.tmpl" + + // BingenStreamerTemplate is the template name for the binary streaming generation. It contains variations + // to the unmarshalling generation as well as calls into the unmarshalling template. + BingenStreamerTemplate = "streamer.go.tmpl" +) + +//go:embed templates/go/*.tmpl +var goBingenTemplatesFS embed.FS + +var ( + goBingenTemplates *template.Template + titleCaser cases.Caser = cases.Title(language.Und, cases.NoLower) +) + +// initialize the templating engine with the go template files, provide external support via +// func maps +func init() { + var err error + + goBingenTemplates = template.New("go-bingen-templates") + goBingenTemplates = goBingenTemplates.Funcs(template.FuncMap{ + "ToTitle": titleCaser.String, + }) + + goBingenTemplates, err = goBingenTemplates.ParseFS(goBingenTemplatesFS, "templates/go/*.tmpl") + if err != nil { + panic(err) + } +} + +// MarshallerParams contains the general set of parameters to pass to the marshaller +// method skeleton: the generator context, the type being marshalled, and the +// field-encoding Body produced by the core Go backend. +type MarshallerParams struct { + Context GeneratorContext + Type types.GenType + Body string +} + +// UnmarshallerParams contains the parameters passed to the unmarshaller method +// skeleton: the generator context, the type being unmarshalled, and the +// field-decoding Body produced by the core Go backend. +type UnmarshallerParams struct { + Context GeneratorContext + Type types.GenType + Body string +} + +// StreamParams contains the general set of parameters to pass to any type streaming generator. It contains +// the current generator context and the type currently being generated. +type StreamParams struct { + Context GeneratorContext + Type types.GenType + Body string +} + +// SupportParams contains the general set of parameters to pass to the support generator. This includes code +// that supports all bingen operations. +type SupportParams struct { + Package string + Imports []string + BufferImport string + VersionSets []meta.VersionSet + Types []types.GenType + StreamableTypes []*types.StructType +} + +// WriteSupportTemplate writes the file header, package declaration, imports, and all supporting bingen +// code to the provided `io.Writer` +func WriteSupportTemplate(writer io.Writer, params SupportParams) error { + return goBingenTemplates.ExecuteTemplate(writer, BingenSupportTemplate, params) +} + +// WriteMarshallerTemplate writes the binary marshalling code to the provided `io.Writer` +func WriteMarshallerTemplate(writer io.Writer, params MarshallerParams) error { + return goBingenTemplates.ExecuteTemplate(writer, BingenMarshallerTemplate, params) +} + +// WriteUnmarshallerTemplate writes the binary unmarshalling code to the provided `io.Writer` +func WriteUnmarshallerTemplate(writer io.Writer, params UnmarshallerParams) error { + return goBingenTemplates.ExecuteTemplate(writer, BingenUnmarshallerTemplate, params) +} + +// WriteStreamerTemplate writes all of the streaming unmarshalling code to the provided `io.Writer` +func WriteStreamerTemplate(writer io.Writer, params StreamParams) error { + return goBingenTemplates.ExecuteTemplate(writer, BingenStreamerTemplate, params) +} diff --git a/internal/generator/golang/templates/go/marshaller.go.tmpl b/internal/generator/golang/templates/go/marshaller.go.tmpl new file mode 100644 index 0000000..93ef028 --- /dev/null +++ b/internal/generator/golang/templates/go/marshaller.go.tmpl @@ -0,0 +1,83 @@ +{{/* + Marshaller method skeleton. The field-encoding body ({{ .Body }}) is produced + by the core Go backend (internal/generator/gobackend.go via + internal/generator/core), so the write* sub-templates that previously lived + here have been retired. The unmarshaller retains its read* defines because the + streamer still reuses them. +*/}} +//-------------------------------------------------------------------------- +// {{ .Type.Name }} +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this {{ .Type.Name }} instance +// into a byte array +func (target *{{ .Type.Name }}) MarshalBinary() (data []byte, err error) { +{{- if .Context.IsStringTable }} + ctx := NewEncodingContext(stringtable.NewIndexedStringTableWriter()) +{{- else }} + ctx := NewEncodingContext(nil) +{{- end }} + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this {{ .Type.Name }} instance +// into an io.Writer. +func (target *{{ .Type.Name }}) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + +{{ if .Context.IsStringTable }} + // run a pre-pass to collect all strings into the string table and discard all writes to the main + // buffer. Then, we write the string table, sorted by number of repeated uses (descending), to the + // main buffer, and use the resulting table as part of the context for the main pass. + prepass := stringtable.NewPrepassStringTableWriter() + prepassCtx := NewEncodingContextFromWriter(io.Discard, prepass) + + e := target.MarshalBinaryWithContext(prepassCtx) + if e != nil { + return e + } + + tableWriter := prepass.WriteSortedTo(buff) + ctx := NewEncodingContextFromBuffer(buff, tableWriter) +{{- else }} + ctx := NewEncodingContextFromBuffer(buff, nil) +{{- end }} + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this {{ .Type.Name }} instance +// into a byte array leveraging a predefined context. +func (target *{{ .Type.Name }}) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8({{ .Context.VersionSetConst }}) // version + + {{- if .Context.IsPreProcess }} + // execute pre-processing func + preProcess{{ .Type.Name }}(target) + {{- end }} + + {{ .Body }} + + return nil +} diff --git a/internal/generator/golang/templates/go/streamer.go.tmpl b/internal/generator/golang/templates/go/streamer.go.tmpl new file mode 100644 index 0000000..33b65da --- /dev/null +++ b/internal/generator/golang/templates/go/streamer.go.tmpl @@ -0,0 +1,61 @@ +{{/* + Streamer skeleton. The field-streaming body ({{ .Body }}) is produced by the + core Go backend (internal/generator/gobackend.go via + internal/generator/core StreamStruct), so the stream* sub-templates that + previously lived here have been retired. +*/}} +//-------------------------------------------------------------------------- +// {{ .Type.Name }}Stream +//-------------------------------------------------------------------------- + +// {{ .Type.Name }}Stream is a single use field stream for the contents of an {{ .Type.Name }} instance. Instead of creating an instance and populating +// the fields on that instance, we provide a streaming iterator which yields (BingenFieldInfo, *BingenValue) tuples for each +// streamable element. All slices and maps will be flattened one depth and each element streamed individually. +type {{ .Type.Name }}Stream struct { + reader io.Reader + ctx *DecodingContext + err error +} + +// Closes closes the internal io.Reader used to read and parse the {{ .Type.Name }} fields. +// This should be called once the stream is no longer needed. +func (stream *{{ .Type.Name }}Stream) Close() { + if closer, ok := stream.reader.(io.Closer); ok { + closer.Close() + } + stream.ctx.Close() +} + +// Error returns an error if one occurred during the process of streaming the {{ .Type.Name }} +// This can be checked after iterating through the Stream(). +func (stream *{{ .Type.Name }}Stream) Error() error { + return stream.err +} + +// New{{ .Type.Name }}Stream creates a new {{ .Type.Name }}Stream, which uses the io.Reader data to stream all internal fields of an {{ .Type.Name }} instance +func New{{ .Type.Name }}Stream(reader io.Reader) bstream.BingenStream { + ctx := NewDecodingContextFromReader(reader) + + return &{{ .Type.Name }}Stream{ + ctx: ctx, + reader: reader, + } +} + +// Stream returns the iterator which will stream each field of the target type. +func (stream *{{ .Type.Name }}Stream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstream.BingenValue] { + return func(yield func(bstream.BingenFieldInfo, *bstream.BingenValue) bool) { + var fi bstream.BingenFieldInfo + + ctx := stream.ctx + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > {{ .Context.VersionSetConst }} { + stream.err = fmt.Errorf("Invalid Version Unmarshalling {{ .Type.Name }}. Expected %d or less, got %d", {{ .Context.VersionSetConst }}, version) + return + } + + {{ .Body }} + } +} diff --git a/internal/generator/templates/go/support.go.tmpl b/internal/generator/golang/templates/go/support.go.tmpl similarity index 100% rename from internal/generator/templates/go/support.go.tmpl rename to internal/generator/golang/templates/go/support.go.tmpl diff --git a/internal/generator/golang/templates/go/unmarshaller.go.tmpl b/internal/generator/golang/templates/go/unmarshaller.go.tmpl new file mode 100644 index 0000000..9a4a8dc --- /dev/null +++ b/internal/generator/golang/templates/go/unmarshaller.go.tmpl @@ -0,0 +1,73 @@ +{{/* + Unmarshaller method skeleton. The field-decoding body ({{ .Body }}) is + produced by the core Go backend (internal/generator/gobackend.go via + internal/generator/core), so the read* sub-templates that previously lived + here have been retired now that the streamer is also on the core. +*/}} +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the {{ .Type.Name }} type +func (target *{{ .Type.Name }}) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the {{ .Type.Name }} type +func (target *{{ .Type.Name }}) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the {{ .Type.Name }} type +func (target *{{ .Type.Name }}) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > {{ .Context.VersionSetConst }} { + return fmt.Errorf("Invalid Version Unmarshalling {{ .Type.Name }}. Expected %d or less, got %d", {{ .Context.VersionSetConst }}, version) + } + + {{ .Body }} + + {{ if .Context.IsMigration -}} + // execute migration func if version delta detected + if version != {{ .Context.VersionSetConst }} { + migrate{{ .Type.Name }}(target, version, {{ .Context.VersionSetConst }}) + } + {{- end }} + + {{ if .Context.IsPostProcess -}} + // execute post-processing func + postProcess{{ .Type.Name }}(target) + {{- end }} + + return nil +} diff --git a/internal/generator/java/backend.go b/internal/generator/java/backend.go new file mode 100644 index 0000000..ffdee2e --- /dev/null +++ b/internal/generator/java/backend.go @@ -0,0 +1,348 @@ +package java + +import ( + "fmt" + "strings" + + "github.com/opencost/bingen/internal/generator/core" + "github.com/opencost/bingen/internal/types" +) + +// JavaBackend renders Java syntax for the core codec walk. It holds the runtime +// package so it can import runtime codec classes (ie: GoTime). +type JavaBackend struct { + runtimePkg string +} + +func NewJavaBackend(runtimePkg string) *JavaBackend { + return &JavaBackend{ + runtimePkg: runtimePkg, + } +} + +func (j *JavaBackend) TypeName(t types.GenType, boxed bool) string { + return javaType(t, boxed) +} + +func (j *JavaBackend) EncodeFieldSource(field string) string { + return fmt.Sprintf("value.%s()", JavaFieldName(field)) +} + +func (j *JavaBackend) CommitField(e *core.Emit, field, valueExpr string) { + e.Linef("builder.%s(%s);", JavaFieldName(field), valueExpr) +} + +func (j *JavaBackend) Default(t types.GenType, opts *types.FieldOpts) string { + return javaDefault(t, opts) +} + +// Comment writes a comment to the generated output with the provided text +func (j *JavaBackend) Comment(e *core.Emit, text string) { + for line := range strings.Lines(text) { + e.Linef("// %s", line) + } +} + +// useExternal records the imports needed to reference an external type's runtime +// codec class and returns that class name. +func (j *JavaBackend) useExternal(e *core.Emit, ext externalType) string { + for _, imp := range ext.typeImports { + e.Import(imp) + } + e.Import(j.runtimePkg + "." + ext.runtimeClass) + return ext.runtimeClass +} + +//-------------------------------------------------------------------------- +// Encode +//-------------------------------------------------------------------------- + +func (j *JavaBackend) WriteNilFlag(e *core.Emit, present bool) { + if present { + e.Line("buff.writeUInt8(1); // write non-nil byte") + } else { + e.Line("buff.writeUInt8(0); // write nil byte") + } +} + +func (j *JavaBackend) NilGuard(e *core.Emit, target string, whenNil, whenPresent func()) { + e.Linef("if (%s == null) {", target) + e.Indented(whenNil) + e.Line("} else {") + e.Indented(whenPresent) + e.Line("}") +} + +func (j *JavaBackend) WritePrimitive(e *core.Emit, t types.GenType, target string) { + e.Linef("buff.%s(%s);", primitives[t.Code()].write, target) +} + +func (j *JavaBackend) WriteString(e *core.Emit, t types.GenType, target string) { + e.Line("if (ctx.isStringTable()) {") + e.Indented(func() { + e.Linef("buff.writeInt(ctx.table().addOrGet(%s)); // string table index", target) + }) + e.Line("} else {") + e.Indented(func() { + e.Linef("buff.writeString(%s); // string", target) + }) + e.Line("}") +} + +func (j *JavaBackend) WriteSlice(e *core.Emit, t *types.SliceType, target string, body func(elem string)) { + elem := e.NextVar() + + e.Linef("buff.writeInt(%s.size()); // slice length", target) + e.Linef("for (%s %s : %s) {", javaType(t.InnerType, true), elem, target) + e.Indented(func() { + body(elem) + }) + e.Line("}") +} + +func (j *JavaBackend) WriteMap(e *core.Emit, t *types.MapType, target string, body func(key, value string)) { + e.Import("java.util.Map") + + entry := e.NextVar() + + e.Linef("buff.writeInt(%s.size()); // map length", target) + e.Linef( + "for (Map.Entry<%s, %s> %s : %s.entrySet()) {", + javaType(t.KeyType, true), + javaType(t.ValueType, true), + entry, + target) + e.Indented(func() { + body(entry+".getKey()", entry+".getValue()") + }) + e.Line("}") +} + +func (j *JavaBackend) WriteStruct(e *core.Emit, t types.GenType, target string) { + e.Line("buff.writeInt(0); // [compatibility, unused]") + e.Linef("%sEncoder.INSTANCE.encode(%s, ctx);", t.Name(), target) +} + +func (j *JavaBackend) WriteInterface(e *core.Emit, t types.GenType, target string) { + e.Linef("TypeRegistry.encode(%s, ctx);", target) +} + +func (j *JavaBackend) WriteExternal(e *core.Emit, t types.GenType, target string) bool { + ext, ok := externalTypes[t.Name()] + if !ok { + return false + } + + e.Linef("%s.encode(%s, buff);", j.useExternal(e, ext), target) + return true +} + +// EncodeAlias for the Java backend flattens aliases to their underlying type, so the target is +// passed through with no cast. +func (j *JavaBackend) EncodeAlias(e *core.Emit, at *types.AliasType, target string, body func(underlying string)) { + body(target) +} + +//-------------------------------------------------------------------------- +// Decode +//-------------------------------------------------------------------------- + +func (j *JavaBackend) DeclareVar(e *core.Emit, t types.GenType, v string) { + e.Linef("%s %s;", javaType(t, false), v) +} + +func (j *JavaBackend) VersionGate(e *core.Emit, fieldVersion uint8, whenCompatible, setDefault func()) { + e.Linef("if (%d <= version) {", fieldVersion) + e.Indented(whenCompatible) + e.Line("} else {") + e.Indented(setDefault) + e.Line("}") +} + +func (j *JavaBackend) ReadNilGuard(e *core.Emit, v string, whenPresent func()) { + e.Line("if (buff.readUInt8() == 0) {") + e.Indented(func() { + e.Linef("%s = null;", v) + }) + e.Line("} else {") + e.Indented(whenPresent) + e.Line("}") +} + +func (j *JavaBackend) ReadPrimitive(e *core.Emit, t types.GenType, v string) { + e.Linef("%s = buff.%s();", v, primitives[t.Code()].read) +} + +func (j *JavaBackend) ReadString(e *core.Emit, t types.GenType, v string) { + e.Line("if (ctx.isStringTable()) {") + e.Indented(func() { + e.Linef("%s = ctx.table().at(buff.readInt()); // string table index", v) + }) + e.Line("} else {") + e.Indented(func() { + e.Linef("%s = buff.readString(); // read string", v) + }) + e.Line("}") +} + +func (j *JavaBackend) ReadSlice(e *core.Emit, t *types.SliceType, v string, readElem func() string) { + e.Import("java.util.ArrayList") + e.Import("java.util.List") + + lenVar := e.NextVar() + idx := e.NextVar() + + e.Linef("int %s = buff.readInt(); // slice length", lenVar) + e.Linef("%s = new ArrayList<>(%s);", v, lenVar) + e.Linef("for (int %s = 0; %s < %s; %s++) {", idx, idx, lenVar, idx) + e.Indented(func() { + e.Linef("%s.add(%s);", v, readElem()) + }) + e.Line("}") +} + +func (j *JavaBackend) ReadMap(e *core.Emit, t *types.MapType, v string, readPair func() (key, value string)) { + e.Import("java.util.LinkedHashMap") + e.Import("java.util.Map") + + lenVar := e.NextVar() + idx := e.NextVar() + + e.Linef("int %s = buff.readInt(); // map length", lenVar) + e.Linef("%s = new LinkedHashMap<>(%s);", v, lenVar) + e.Linef("for (int %s = 0; %s < %s; %s++) {", idx, idx, lenVar, idx) + e.Indented(func() { + key, value := readPair() + e.Linef("%s.put(%s, %s);", v, key, value) + }) + e.Line("}") +} + +func (j *JavaBackend) ReadStruct(e *core.Emit, t types.GenType, v string) { + e.Line("buff.readInt(); // [compatibility, unused]") + e.Linef("%s = %sDecoder.INSTANCE.decode(ctx);", v, t.Name()) +} + +func (j *JavaBackend) ReadInterface(e *core.Emit, t types.GenType, v string) { + name := e.NextVar() + e.Linef("String %s = buff.readString();", name) + e.Linef("%s = (%s) TypeRegistry.decode(%s, ctx);", v, javaType(t, false), name) +} + +func (j *JavaBackend) ReadExternal(e *core.Emit, t types.GenType, v string) bool { + ext, ok := externalTypes[t.Name()] + if !ok { + return false + } + + e.Linef("%s = %s.decode(buff);", v, j.useExternal(e, ext)) + return true +} + +// DecodeAlias for the Java backend flattens aliases to their underlying type, so v is read into +// directly with no conversion. +func (j *JavaBackend) DecodeAlias(e *core.Emit, at *types.AliasType, v string, body func(underlying string)) { + body(v) +} + +//-------------------------------------------------------------------------- +// Streaming +//-------------------------------------------------------------------------- + +func (j *JavaBackend) FieldInfo(e *core.Emit, name string, t types.GenType) { + e.Linef("fi = new BingenFieldInfo(%q);", name) +} + +func (j *JavaBackend) Yield(e *core.Emit, value string) { + j.accept(e, fmt.Sprintf("BingenValue.single(%s)", value)) +} + +func (j *JavaBackend) YieldNil(e *core.Emit) { + j.accept(e, "null") +} + +func (j *JavaBackend) YieldIndexed(e *core.Emit, index, value string) { + j.accept(e, fmt.Sprintf("BingenValue.pair(%s, %s)", index, value)) +} + +func (j *JavaBackend) accept(e *core.Emit, valueExpr string) { + e.Linef("if (!consumer.accept(fi, %s)) {", valueExpr) + e.Indented(func() { e.Line("return;") }) + e.Line("}") +} + +func (j *JavaBackend) StreamNilGuard(e *core.Emit, whenNil, whenPresent func()) { + e.Line("if (buff.readUInt8() == 0) {") + e.Indented(whenNil) + e.Line("} else {") + e.Indented(whenPresent) + e.Line("}") +} + +func (j *JavaBackend) StreamSlice(e *core.Emit, t *types.SliceType, body func(index string)) { + lenVar := e.NextVar() + idx := e.NextVar() + e.Linef("int %s = buff.readInt();", lenVar) + e.Linef("for (int %s = 0; %s < %s; %s++) {", idx, idx, lenVar, idx) + e.Indented(func() { body(idx) }) + e.Line("}") +} + +func (j *JavaBackend) StreamMap(e *core.Emit, t *types.MapType, body func()) { + lenVar := e.NextVar() + idx := e.NextVar() + e.Linef("int %s = buff.readInt();", lenVar) + e.Linef("for (int %s = 0; %s < %s; %s++) {", idx, idx, lenVar, idx) + e.Indented(body) + e.Line("}") +} + +func (j *JavaBackend) StreamDefault(e *core.Emit, t types.GenType, opts *types.FieldOpts) { + if t.IsNilable() { + j.YieldNil(e) + return + } + + v := e.NextVar() + e.Linef("%s %s = %s;", javaType(t, false), v, javaDefault(t, opts)) + j.Yield(e, v) +} + +// javaDefault returns the Java expression assigned to a field whose version +// exceeds the payload version. Nilable types default to null and primitives to +// their zero value (or the raw annotation default when present); go-style cast +// defaults are not translated. +func javaDefault(t types.GenType, opts *types.FieldOpts) string { + if t.IsNilable() { + return "null" + } + + def := "" + if opts != nil { + def = opts.Default + } + + switch t.Code() { + case types.TypeBool: + if def == "" { + return "false" + } + return def + + case types.TypeString: + return fmt.Sprintf("%q", def) + + case types.TypeAlias: + return javaDefault(t.(*types.AliasType).Alias, opts) + + case types.TypeStruct, types.TypeInterface, types.TypeReference: + return "null" + + default: + if def == "" { + return "0" + } + + return def + } +} diff --git a/internal/generator/java/decoder_test.go b/internal/generator/java/decoder_test.go new file mode 100644 index 0000000..28de5d4 --- /dev/null +++ b/internal/generator/java/decoder_test.go @@ -0,0 +1,100 @@ +package java + +import ( + "testing" + + "github.com/opencost/bingen/internal/types" +) + +// personPetHarness round-trips a struct with a map and a nested pointer struct +// entirely in java and asserts record equality. +const personPetHarness = `import com.example.model.Person; +import com.example.model.Pet; +import com.example.model.PersonEncoder; +import com.example.model.PersonDecoder; +import com.bingen.DecodingContext; +import com.bingen.EncodingContext; +import java.util.Map; + +public final class PersonPetMain { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) { + Person p = Person.builder() + .name("Ada") + .age(36) + .scores(Map.of("math", 95)) + .pet(Pet.builder().kind("cat").build()) + .build(); + + EncodingContext ec = EncodingContext.create(); + PersonEncoder.INSTANCE.encode(p, ec); + Person back = PersonDecoder.INSTANCE.decode(DecodingContext.fromBytes(ec.toBytes())); + + check(p.equals(back), "round-trip equality; got " + back); + System.out.println("OK"); + } +} +` + +// personPetStructs builds Person{Name, Age, Scores map[string]int, Pet *Pet} and +// Pet{Kind}, exercising maps and nested pointer structs. +func personPetStructs() []types.GenType { + stringT := types.BasicTypes[types.TypeString] + intT := types.BasicTypes[types.TypeInt] + + pet := &types.StructType{ + BasicType: types.NewBasicType("", "Pet", types.TypeStruct, false, false), + Fields: []*types.StructField{{Name: "Kind", Type: stringT}}, + Opts: &types.GenerateTypeOpts{SetName: "Model", SetVersion: 1}, + } + + person := &types.StructType{ + BasicType: types.NewBasicType("", "Person", types.TypeStruct, false, false), + Fields: []*types.StructField{ + {Name: "Name", Type: stringT}, + {Name: "Age", Type: intT}, + {Name: "Scores", Type: &types.MapType{ + BasicType: types.NewBasicType("", "map[string]int", types.TypeMap, false, false), + KeyType: stringT, + ValueType: intT, + }}, + {Name: "Pet", Type: pet.CreatePtr()}, + }, + Opts: &types.GenerateTypeOpts{SetName: "Model", SetVersion: 1}, + } + + return []types.GenType{person, pet} +} + +// TestCodec_MapAndNestedStruct round-trips a map + nested pointer struct in java. +func TestCodec_MapAndNestedStruct(t *testing.T) { + const goPackage = "model" + const harnessName = "PersonPetMain" + const exampleJavaPackageBase = "com.example" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: personPetHarness, + } + + out := buildJavaTestFromTypes( + t, + ".", + goPackage, + exampleJavaPackageBase, + newTypesCollectionWith(personPetStructs()...), + javaMain, + ) + + if o, err := runJavaTest(t, out, harnessName); err != nil { + t.Fatalf("PersonPetMain failed: %v\n%s", err, o) + } +} diff --git a/internal/generator/java/encoder_test.go b/internal/generator/java/encoder_test.go new file mode 100644 index 0000000..aa7411f --- /dev/null +++ b/internal/generator/java/encoder_test.go @@ -0,0 +1,80 @@ +package java + +import ( + "os" + "path/filepath" + "testing" + + "github.com/opencost/bingen/tests/container" +) + +// encodeMainHarness builds a Container via the generated builder, encodes it +// with the generated encoder, and writes the bytes to args[0]. +const encodeMainHarness = `import com.opencost.container.Container; +import com.opencost.container.ContainerEncoder; +import com.bingen.EncodingContext; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +public final class EncodeMain { + public static void main(String[] args) throws Exception { + Container c = Container.builder() + .name("TestContainer") + .children(List.of("a", "b", "c")) + .value(3.14) + .build(); + + EncodingContext ctx = EncodingContext.create(); + ContainerEncoder.INSTANCE.encode(c, ctx); + Files.write(Path.of(args[0]), ctx.toBytes()); + } +} +` + +// TestEncoder_JavaToGoRoundTrip generates the java encoder for Container, runs +// it to produce bytes, then decodes those bytes with the real go container +// codec and asserts the values survived the crossing. +func TestEncoder_JavaToGoRoundTrip(t *testing.T) { + const goPackage = "container" + const harnessName = "EncodeMain" + + checkJava(t) + + tc := newTypesCollectionWith(containerStruct()) + out := buildJavaTestFromTypes(t, ".", goPackage, BaseJavaPackage, tc, &javaSource{ + FileName: harnessName, + Source: encodeMainHarness, + }) + + if o, err := runJavaTest(t, out, harnessName, "encoded.bin"); err != nil { + t.Fatalf("EncodeMain failed: %v\n%s", err, o) + } + + binPath := filepath.Join(out, "encoded.bin") + data, err := os.ReadFile(binPath) + if err != nil { + t.Fatalf("reading encoded bytes: %v", err) + } + + var c container.Container + if err := c.UnmarshalBinary(data); err != nil { + t.Fatalf("go UnmarshalBinary of java-encoded bytes failed: %v", err) + } + + if c.Name != "TestContainer" { + t.Errorf("Name = %q, want %q", c.Name, "TestContainer") + } + if want := []string{"a", "b", "c"}; len(c.Children) != len(want) { + t.Fatalf("Children = %v, want %v", c.Children, want) + } else { + for i, v := range want { + if c.Children[i] != v { + t.Errorf("Children[%d] = %q, want %q", i, c.Children[i], v) + } + } + } + if c.Value != 3.14 { + t.Errorf("Value = %v, want 3.14", c.Value) + } +} diff --git a/internal/generator/java/externaltypes.go b/internal/generator/java/externaltypes.go new file mode 100644 index 0000000..91c38e1 --- /dev/null +++ b/internal/generator/java/externaltypes.go @@ -0,0 +1,22 @@ +package java + +// externalType describes how a non-generated go type that bingen encodes as an +// external reference (length-prefixed MarshalBinary output) is handled in Java: +// the Java type a field maps to, the imports that type needs, and the runtime +// class that reproduces the reference's byte format. +type externalType struct { + javaType string // ie: "OffsetDateTime" + typeImports []string // ie: []string{"java.time.OffsetDateTime"} + runtimeClass string // codec class in the runtime package, ie: "GoTime" +} + +// externalTypes maps a go reference type name (as it appears in the IR, ie: +// "time.Time") to its Java handling. User-defined external types are not yet +// registrable here; that needs a config surface analogous to @bingen:import. +var externalTypes = map[string]externalType{ + "time.Time": { + javaType: "OffsetDateTime", + typeImports: []string{"java.time.OffsetDateTime"}, + runtimeClass: "GoTime", + }, +} diff --git a/internal/generator/java/generate.go b/internal/generator/java/generate.go new file mode 100644 index 0000000..c91725e --- /dev/null +++ b/internal/generator/java/generate.go @@ -0,0 +1,223 @@ +package java + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/opencost/bingen/internal/generator/core" + "github.com/opencost/bingen/internal/types" +) + +// Generate emits the Java exporter output for the collected types into the +// directory derived from opts. The per-type records, split encoder/decoder +// types, and runtime are added in subsequent phases; this scaffolding +// establishes the end-to-end pipeline and output layout. +func Generate(sourceDir string, tc types.TypeCollection, opts *Options) error { + if opts == nil { + return fmt.Errorf("java: nil options") + } + + pkgDir := opts.PackageDir() + if err := os.MkdirAll(pkgDir, 0o750); err != nil { + return fmt.Errorf("java: creating output dir %q: %w", pkgDir, err) + } + + if err := writeFile(filepath.Join(pkgDir, "package-info.java"), PackageInfoTemplate, opts); err != nil { + return err + } + + if err := emitRuntime(opts); err != nil { + return err + } + + // Resolve the interface implementation graph via the go type checker when any + // generated struct references a named interface. + info := &interfaceInfo{ + Implements: map[string][]string{}, + } + + interfaces := neededInterfaces(tc) + if len(interfaces) > 0 { + loaded, err := loadInterfaceInfo(sourceDir, structNames(tc), interfaces) + if err != nil { + return err + } + + info = loaded + if err := emitInterfaces(pkgDir, opts, interfaces); err != nil { + return err + } + if err := emitRegistry(pkgDir, opts, tc, info); err != nil { + return err + } + } + + for _, t := range tc.Types() { + st, ok := t.(*types.StructType) + if !ok { + continue + } + if err := emitRecord(pkgDir, opts, st, info); err != nil { + return err + } + if err := emitEncoder(pkgDir, opts, st); err != nil { + return err + } + if err := emitDecoder(pkgDir, opts, st); err != nil { + return err + } + if st.Opts.IsStreamable { + if err := emitStreamer(pkgDir, opts, st); err != nil { + return err + } + } + } + + fmt.Printf("java: generated package %s -> %s (%d types)\n", opts.JavaPackage, pkgDir, len(tc.Types())) + return nil +} + +// emitInterfaces writes an empty marker interface per referenced go interface. +func emitInterfaces(pkgDir string, opts *Options, interfaces []string) error { + for _, name := range interfaces { + params := InterfaceParams{Package: opts.JavaPackage, Name: name} + if err := writeFile(filepath.Join(pkgDir, name+".java"), InterfaceTemplate, params); err != nil { + return err + } + } + return nil +} + +// emitRegistry writes the wire-string -> codec dispatch table for every +// generated struct type. +func emitRegistry(pkgDir string, opts *Options, tc types.TypeCollection, info *interfaceInfo) error { + var entries []RegistryEntry + for _, name := range structNames(tc) { + entries = append(entries, RegistryEntry{ + Wire: info.wireName(name), + Type: name, + }) + } + + params := RegistryParams{ + Package: opts.JavaPackage, + RuntimePackage: opts.RuntimePackage, + Entries: entries, + } + return writeFile(filepath.Join(pkgDir, "TypeRegistry.java"), RegistryTemplate, params) +} + +// emitRecord writes the immutable record + builder for a single struct type. +func emitRecord(pkgDir string, opts *Options, st *types.StructType, info *interfaceInfo) error { + params := RecordParams{ + Package: opts.JavaPackage, + Imports: requiredImports(st), + ImplementsClause: implementsClause(info.Implements[st.Name()]), + Type: st, + } + return writeFile(filepath.Join(pkgDir, st.Name()+".java"), RecordTemplate, params) +} + +// implementsClause builds the java `implements A, B` clause, or "" when the +// struct satisfies no generated interfaces. +func implementsClause(interfaces []string) string { + if len(interfaces) == 0 { + return "" + } + return " implements " + strings.Join(interfaces, ", ") +} + +// emitEncoder writes the BinEncoder implementation for a single struct type. +func emitEncoder(pkgDir string, opts *Options, st *types.StructType) error { + body, imports, err := core.EncodeStruct(NewJavaBackend(opts.RuntimePackage), st) + if err != nil { + return fmt.Errorf("java: encoding %s: %w", st.Name(), err) + } + + params := CodecParams{ + Package: opts.JavaPackage, + RuntimePackage: opts.RuntimePackage, + Imports: imports, + Version: st.Opts.SetVersion, + StringTable: st.Opts.IsGenerateStringTable, + PreProcess: st.Opts.IsPreProcess, + Body: body, + Type: st, + } + return writeFile(filepath.Join(pkgDir, st.Name()+"Encoder.java"), EncoderTemplate, params) +} + +// emitDecoder writes the BinDecoder implementation for a single struct type. +func emitDecoder(pkgDir string, opts *Options, st *types.StructType) error { + body, imports, err := core.DecodeStruct(NewJavaBackend(opts.RuntimePackage), st) + if err != nil { + return fmt.Errorf("java: decoding %s: %w", st.Name(), err) + } + + params := CodecParams{ + Package: opts.JavaPackage, + RuntimePackage: opts.RuntimePackage, + Imports: imports, + Version: st.Opts.SetVersion, + PostProcess: st.Opts.IsPostProcess, + Migration: st.Opts.IsMigration, + Body: body, + Type: st, + } + return writeFile(filepath.Join(pkgDir, st.Name()+"Decoder.java"), DecoderTemplate, params) +} + +// emitStreamer writes the push streamer for a streamable struct type. +func emitStreamer(pkgDir string, opts *Options, st *types.StructType) error { + body, imports, err := core.StreamStruct(NewJavaBackend(opts.RuntimePackage), st) + if err != nil { + return fmt.Errorf("java: streaming %s: %w", st.Name(), err) + } + + params := CodecParams{ + Package: opts.JavaPackage, + RuntimePackage: opts.RuntimePackage, + Imports: imports, + Version: st.Opts.SetVersion, + Body: body, + Type: st, + } + return writeFile(filepath.Join(pkgDir, st.Name()+"Streamer.java"), StreamerTemplate, params) +} + +// emitRuntime writes the shared runtime (buffers, and in later phases the codec +// contexts and registry) into the configured runtime package. It is idempotent +// and safe to run for every generated package. +func emitRuntime(opts *Options) error { + runtimeDir := opts.RuntimePackageDir() + if err := os.MkdirAll(runtimeDir, 0o750); err != nil { + return fmt.Errorf("java: creating runtime dir %q: %w", runtimeDir, err) + } + + params := RuntimeParams{ + RuntimePackage: opts.RuntimePackage, + } + + for fileName, tmpl := range runtimeTemplates { + if err := writeFile(filepath.Join(runtimeDir, fileName), tmpl, params); err != nil { + return err + } + } + + return nil +} + +// writeFile renders the named template with data and writes it to path. +func writeFile(path string, template string, data any) error { + var buf bytes.Buffer + if err := writeTemplate(&buf, template, data); err != nil { + return err + } + if err := os.WriteFile(path, buf.Bytes(), 0o600); err != nil { + return fmt.Errorf("java: writing %q: %w", path, err) + } + return nil +} diff --git a/internal/generator/java/generate_test.go b/internal/generator/java/generate_test.go new file mode 100644 index 0000000..26071ac --- /dev/null +++ b/internal/generator/java/generate_test.go @@ -0,0 +1,40 @@ +package java + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestGenerate_EmitsPackageInfo(t *testing.T) { + out := t.TempDir() + + opts, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptOutputDir: out, + }) + if err != nil { + t.Fatalf("FromConfig: %v", err) + } + + if err := Generate(".", &fakeTypeCollection{}, opts); err != nil { + t.Fatalf("Generate: %v", err) + } + + pkgInfo := filepath.Join(out, "com", "opencost", "container", "package-info.java") + data, err := os.ReadFile(pkgInfo) + if err != nil { + t.Fatalf("reading generated package-info.java: %v", err) + } + + if !strings.Contains(string(data), "package com.opencost.container;") { + t.Fatalf("package-info.java missing package declaration, got:\n%s", data) + } +} + +func TestGenerate_NilOptions(t *testing.T) { + if err := Generate(".", &fakeTypeCollection{}, nil); err == nil { + t.Fatal("expected error for nil options") + } +} diff --git a/internal/generator/java/helper_test.go b/internal/generator/java/helper_test.go new file mode 100644 index 0000000..98f4108 --- /dev/null +++ b/internal/generator/java/helper_test.go @@ -0,0 +1,396 @@ +package java + +import ( + "bytes" + "encoding" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "github.com/opencost/bingen/internal/meta" + "github.com/opencost/bingen/internal/types" +) + +var ( + javaExec string + javaCC string +) + +func init() { + var err error + javaExec, err = exec.LookPath("java") + if err != nil { + javaExec = "" + } + + javaCC, err = exec.LookPath("javac") + if err != nil { + javaCC = "" + } +} + +const BaseJavaPackage string = "com.opencost" + +// containerStruct builds the IR for the container test struct without touching +// the filesystem: Name string, Children []string, Value float64. +func containerStruct() *types.StructType { + stringT := types.BasicTypes[types.TypeString] + return &types.StructType{ + BasicType: types.NewBasicType("", "Container", types.TypeStruct, false, false), + Fields: []*types.StructField{ + {Name: "Name", Type: stringT}, + {Name: "Children", Type: &types.SliceType{ + BasicType: types.NewBasicType("", "[]string", types.TypeSlice, false, false), + InnerType: stringT, + }}, + {Name: "Value", Type: types.BasicTypes[types.TypeFloat64]}, + }, + Opts: &types.GenerateTypeOpts{SetName: "ContainerExample", SetVersion: 1}, + } +} + +// fakeTypeCollection is a minimal TypeCollection used to drive the generation +// pipeline without parsing a real go package. +type fakeTypeCollection struct { + types []types.GenType +} + +func (f *fakeTypeCollection) AddStructType(*types.AnnotatedType, []*types.AnnotatedField) {} + +func (f *fakeTypeCollection) AddInterface(*types.AnnotatedType) {} + +func (f *fakeTypeCollection) AddAlias(*types.AnnotatedType, bool) {} + +func (f *fakeTypeCollection) Types() []types.GenType { + return f.types +} + +func (f *fakeTypeCollection) Imports() []string { + return nil +} + +func (f *fakeTypeCollection) VersionSets() []meta.VersionSet { + return nil +} + +func newTypesCollectionWith(typs ...types.GenType) types.TypeCollection { + return &fakeTypeCollection{ + types: typs, + } +} + +// javaSource represents a java source file with a test harness. +type javaSource struct { + FileName string + Source string +} + +func (js *javaSource) HarnessName() string { + return toHarnessName(js.FileName) +} + +// test helper which writes the java sources to a specific directory +func writeJavaSource(t *testing.T, dir string, file *javaSource, other ...*javaSource) { + t.Helper() + + files := append([]*javaSource{file}, other...) + for _, jfile := range files { + fileName := jfile.FileName + if !strings.Contains(fileName, ".java") { + fileName += ".java" + } + + fullPath := filepath.Join(dir, fileName) + if err := os.WriteFile(fullPath, []byte(jfile.Source), 0o600); err != nil { + t.Fatalf("writing harness: %v", err) + } + } +} + +// test helper which checks to see if java and javac are reachable on the path. +// if not, tests are skipped +func checkJava(t *testing.T) { + t.Helper() + + if javaExec == "" { + t.Skip("java not found on PATH; skipping java run test") + } + + if javaCC == "" { + t.Skip("javac not found on PATH; skipping java compile test") + } +} + +// findJavaSources returns every .java file beneath root. +func findJavaSources(t *testing.T, root string) []string { + t.Helper() + + var sources []string + err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() && strings.HasSuffix(path, ".java") { + sources = append(sources, path) + } + return nil + }) + + if err != nil { + t.Fatalf("walking %q: %v", root, err) + } + + return sources +} + +// compileJavaTree compiles every .java file beneath root, skipping the test if +// javac is unavailable. +func compileJavaTree(t *testing.T, root string) { + t.Helper() + + sources := findJavaSources(t, root) + if len(sources) == 0 { + t.Fatal("no .java sources generated") + } + + compileJava(t, root, sources) +} + +func compileJava(t *testing.T, dir string, sources []string) { + t.Helper() + + classes := filepath.Join(dir, "classes") + if err := os.MkdirAll(classes, 0o750); err != nil { + t.Fatalf("mkdir classes: %v", err) + } + + args := append([]string{"-encoding", "UTF-8", "-d", classes}, sources...) + cmd := exec.Command(javaCC, args...) + cmd.Dir = dir + + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("javac failed: %v\n%s", err, out) + } +} + +// builds the java runtime files and returns the temp output directory +func createAndEmitRuntime(t *testing.T, goPackage, baseJavaPackage string) string { + t.Helper() + + dir := t.TempDir() + + opts, err := FromConfig(goPackage, map[string]string{ + OptBasePackage: baseJavaPackage, + OptOutputDir: dir, + }) + if err != nil { + t.Fatalf("FromConfig: %v", err) + } + + // Emit the generated runtime under com/bingen. + if err := emitRuntime(opts); err != nil { + t.Fatalf("emitRuntime: %v", err) + } + return dir +} + +// test helper +func buildJavaTestFromTypes(t *testing.T, goSrcDir string, goPackage string, baseJavaPackage string, tc types.TypeCollection, javaSrc *javaSource, other ...*javaSource) string { + t.Helper() + + out := t.TempDir() + opts, err := FromConfig(goPackage, map[string]string{ + OptBasePackage: baseJavaPackage, + OptOutputDir: out, + }) + if err != nil { + t.Fatalf("FromConfig: %v", err) + } + if err := Generate(goSrcDir, tc, opts); err != nil { + t.Fatalf("Generate: %v", err) + } + + writeJavaSource(t, out, javaSrc, other...) + compileJavaTree(t, out) + + return out +} + +// loads the test types in /tests/ and returns the directory and type collection +func loadTestTypes(t *testing.T, goPackage string) (string, types.TypeCollection) { + t.Helper() + + // load types from the source go directory (/tests/) + dir := goSourceToDirectory(t, goPackage) + tc, err := types.LoadTypes(dir, goPackage, 1) + if err != nil { + t.Fatalf("LoadTypes: %v", err) + } + + return dir, tc +} + +func buildJavaTest(t *testing.T, goPackage string, javaSrc *javaSource, other ...*javaSource) string { + t.Helper() + + dir, tc := loadTestTypes(t, goPackage) + return buildJavaTestFromTypes(t, dir, goPackage, BaseJavaPackage, tc, javaSrc, other...) +} + +func runJavaTest(t *testing.T, runDir string, harnessName string, args ...string) ([]byte, error) { + t.Helper() + + allArgs := append( + []string{ + "-cp", + "classes", + harnessName, + }, + args..., + ) + + run := exec.Command(javaExec, allArgs...) + run.Dir = runDir + + return run.CombinedOutput() +} + +func buildAndRunJavaTest(t *testing.T, goSrcTestDir string, javaSrc *javaSource) { + t.Helper() + + out := buildJavaTest(t, goSrcTestDir, javaSrc) + o, err := runJavaTest(t, out, javaSrc.HarnessName()) + if err != nil { + t.Fatalf("%s failed: %v\n%s", javaSrc.HarnessName(), err, o) + } + t.Logf("%s", o) +} + +func goSourceToDirectory(t *testing.T, goSrc string) string { + t.Helper() + + dir, err := filepath.Abs(filepath.Join("..", "..", "..", "tests", goSrc)) + if err != nil { + t.Fatalf("abs go-src dir: %v", err) + } + return dir +} + +func toHarnessName(name string) string { + r, _ := strings.CutSuffix(name, ".java") + return r +} + +type binaryPtr[T any] interface { + encoding.BinaryMarshaler + encoding.BinaryUnmarshaler + *T +} + +type roundTripTestBuilder[T any, U binaryPtr[T]] struct { + goPackage string + harnessName string + javaMain *javaSource + sources []*javaSource + tc types.TypeCollection + assertFn func(*testing.T, *T, *T) +} + +func newRoundTripTestBuilder[T any, U binaryPtr[T]](goPackage string, javaMain *javaSource) *roundTripTestBuilder[T, U] { + return &roundTripTestBuilder[T, U]{ + goPackage: goPackage, + harnessName: javaMain.HarnessName(), + javaMain: javaMain, + sources: []*javaSource{}, + } +} + +func (rtt *roundTripTestBuilder[T, U]) AddSource(javaSrc *javaSource) *roundTripTestBuilder[T, U] { + rtt.sources = append(rtt.sources, javaSrc) + return rtt +} + +func (rtt *roundTripTestBuilder[T, U]) WithIRTypes(tc types.TypeCollection) *roundTripTestBuilder[T, U] { + rtt.tc = tc + return rtt +} + +func (rtt *roundTripTestBuilder[T, U]) WithAssertion(assertFn func(*testing.T, *T, *T)) *roundTripTestBuilder[T, U] { + rtt.assertFn = assertFn + return rtt +} + +func (rtt *roundTripTestBuilder[T, U]) Build(t *testing.T) *roundTripTest[T, U] { + var out string + if rtt.tc != nil { + out = buildJavaTestFromTypes(t, ".", rtt.goPackage, BaseJavaPackage, rtt.tc, rtt.javaMain, rtt.sources...) + } else { + out = buildJavaTest(t, rtt.goPackage, rtt.javaMain, rtt.sources...) + } + + return &roundTripTest[T, U]{ + t: t, + goPackage: rtt.goPackage, + harnessName: rtt.harnessName, + outDir: out, + assertFn: rtt.assertFn, + } +} + +type roundTripTest[T any, U binaryPtr[T]] struct { + t *testing.T + outDir string + goPackage string + harnessName string + assertFn func(*testing.T, *T, *T) +} + +func (rtt *roundTripTest[T, U]) Run(instance *T) { + t := rtt.t + t.Helper() + + inPath := filepath.Join(rtt.outDir, "in.bin") + outPath := filepath.Join(rtt.outDir, "out.bin") + + var orig U = instance + goBytes, err := orig.MarshalBinary() + if err != nil { + t.Fatalf("go MarshalBinary: %v", err) + return + } + + if err := os.WriteFile(inPath, goBytes, 0o600); err != nil { + t.Fatalf("writing in.bin: %v", err) + return + } + + if o, err := runJavaTest(t, rtt.outDir, rtt.harnessName, "in.bin", "out.bin"); err != nil { + t.Fatalf("%s failed: %v\n%s", rtt.harnessName, err, o) + return + } + + reBytes, err := os.ReadFile(outPath) + if err != nil { + t.Fatalf("reading out.bin: %v", err) + } + if !bytes.Equal(goBytes, reBytes) { + t.Fatalf("roundtrip byte comparison failed\n go: %x\n java: %x", goBytes, reBytes) + return + } + + var back U = new(T) + if err := back.UnmarshalBinary(reBytes); err != nil { + t.Fatalf("go decode of java-reencoded bytes: %v", err) + return + } + + if rtt.assertFn != nil { + rtt.assertFn(t, orig, back) + } +} + +func (rtt *roundTripTest[T, U]) Cleanup() { + _ = os.RemoveAll(rtt.outDir) +} diff --git a/internal/generator/java/hooks_test.go b/internal/generator/java/hooks_test.go new file mode 100644 index 0000000..5c6bbcc --- /dev/null +++ b/internal/generator/java/hooks_test.go @@ -0,0 +1,99 @@ +package java + +import ( + "testing" + + "github.com/opencost/bingen/internal/types" +) + +const noteHooksSource = `package com.opencost.note; + +public final class NoteHooks { + private NoteHooks() { + } + + // preProcess derives Length from Text before encoding. + public static Note preProcess(Note n) { + return new Note(n.text(), n.text().length()); + } + + // postProcess upper-cases Text after decoding. + public static Note postProcess(Note n) { + return new Note(n.text().toUpperCase(), n.length()); + } +} +` + +const noteMainSource = `import com.opencost.note.Note; +import com.opencost.note.NoteEncoder; +import com.opencost.note.NoteDecoder; + +public final class NoteMain { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) { + // Length starts at 0; preProcess should set it to text length (3) on encode. + byte[] bytes = NoteEncoder.toBytes(new Note("abc", 0)); + Note out = NoteDecoder.fromBytes(bytes); + check(out.text().equals("ABC"), "postProcess upper-case; text=" + out.text()); + check(out.length() == 3, "preProcess length; length=" + out.length()); + System.out.println("OK"); + } +} +` + +func noteStruct() *types.StructType { + return &types.StructType{ + BasicType: types.NewBasicType("", "Note", types.TypeStruct, false, false), + Fields: []*types.StructField{ + {Name: "Text", Type: types.BasicTypes[types.TypeString]}, + {Name: "Length", Type: types.BasicTypes[types.TypeInt]}, + }, + Opts: &types.GenerateTypeOpts{ + SetName: "Note", + SetVersion: 1, + IsPreProcess: true, + IsPostProcess: true, + }, + } +} + +// TestHooks_PreAndPostProcess verifies the encoder pre-process and decoder +// post-process hook points fire around the wire. +func TestHooks_PreAndPostProcess(t *testing.T) { + const goPackage = "note" + const harnessName = "NoteMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: noteMainSource, + } + + javaHooks := &javaSource{ + FileName: "NoteHooks.java", + Source: noteHooksSource, + } + + out := buildJavaTestFromTypes( + t, + ".", + goPackage, + BaseJavaPackage, + newTypesCollectionWith(noteStruct()), + javaMain, + javaHooks, + ) + + o, err := runJavaTest(t, out, harnessName) + if err != nil { + t.Fatalf("NoteMain failed: %v\n%s", err, o) + } + t.Logf("%s", string(o)) +} diff --git a/internal/generator/java/implements.go b/internal/generator/java/implements.go new file mode 100644 index 0000000..b7fa625 --- /dev/null +++ b/internal/generator/java/implements.go @@ -0,0 +1,137 @@ +package java + +import ( + "fmt" + "go/types" + "sort" + + bingentypes "github.com/opencost/bingen/internal/types" + "golang.org/x/tools/go/packages" +) + +// interfaceInfo captures the interface implementation graph derived from the go +// type checker for a single generated package. +type interfaceInfo struct { + // PkgPath is the fully-qualified import path of the source package, used to + // build the wire type strings for interface values. + PkgPath string + + // Implements maps each generated struct name to the sorted set of generated + // interface names it satisfies. + Implements map[string][]string +} + +// wireName returns the go wire type string written for a value of the named +// struct when it appears as an interface value. Generated bingen types use +// pointer receivers, so the pointer form is emitted (matching go typeToString). +func (ii *interfaceInfo) wireName(structName string) string { + return "*" + ii.PkgPath + "." + structName +} + +// neededInterfaces returns the sorted set of named interface types referenced by +// any generated struct field (recursing through slices, maps, and aliases). The +// empty interface{} is excluded; it maps to Object and needs no marker type. +func neededInterfaces(tc bingentypes.TypeCollection) []string { + found := make(map[string]bool) + + for _, t := range tc.Types() { + st, ok := t.(*bingentypes.StructType) + if !ok { + continue + } + for _, f := range st.Fields { + bingentypes.WalkType(f.Type, func(gt bingentypes.GenType) { + if gt.Code() == bingentypes.TypeInterface { + if name := gt.Name(); name != "interface{}" { + found[name] = true + } + } + }) + } + } + + out := make([]string, 0, len(found)) + for name := range found { + out = append(out, name) + } + sort.Strings(out) + return out +} + +// structNames returns the sorted names of all generated struct types, giving a +// deterministic registry order independent of source declaration order. +func structNames(tc bingentypes.TypeCollection) []string { + var names []string + for _, t := range tc.Types() { + if st, ok := t.(*bingentypes.StructType); ok { + names = append(names, st.Name()) + } + } + sort.Strings(names) + return names +} + +// loadInterfaceInfo type-checks the source package and computes the interface +// implementation graph using the go type checker, which resolves embedded and +// cross-package interfaces exactly. +func loadInterfaceInfo(sourceDir string, structs []string, interfaces []string) (*interfaceInfo, error) { + cfg := &packages.Config{ + Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo, + Dir: sourceDir, + } + pkgs, err := packages.Load(cfg, ".") + if err != nil { + return nil, fmt.Errorf("loading go types for %q: %w", sourceDir, err) + } + if len(pkgs) == 0 { + return nil, fmt.Errorf("no go package found in %q", sourceDir) + } + pkg := pkgs[0] + if len(pkg.Errors) > 0 { + return nil, fmt.Errorf("type errors in %q: %v", sourceDir, pkg.Errors[0]) + } + + scope := pkg.Types.Scope() + + ifaceTypes := make(map[string]*types.Interface, len(interfaces)) + for _, name := range interfaces { + obj := scope.Lookup(name) + if obj == nil { + return nil, fmt.Errorf("interface %q not found in package %q", name, pkg.PkgPath) + } + iface, ok := obj.Type().Underlying().(*types.Interface) + if !ok { + return nil, fmt.Errorf("type %q is not an interface", name) + } + ifaceTypes[name] = iface + } + + implements := make(map[string][]string) + for _, structName := range structs { + obj := scope.Lookup(structName) + if obj == nil { + continue + } + named, ok := obj.Type().(*types.Named) + if !ok { + continue + } + ptr := types.NewPointer(named) + + var satisfied []string + for _, ifaceName := range interfaces { + if types.Implements(ptr, ifaceTypes[ifaceName]) { + satisfied = append(satisfied, ifaceName) + } + } + if len(satisfied) > 0 { + sort.Strings(satisfied) + implements[structName] = satisfied + } + } + + return &interfaceInfo{ + PkgPath: pkg.PkgPath, + Implements: implements, + }, nil +} diff --git a/internal/generator/java/javatype.go b/internal/generator/java/javatype.go new file mode 100644 index 0000000..77d4a09 --- /dev/null +++ b/internal/generator/java/javatype.go @@ -0,0 +1,150 @@ +package java + +import ( + "sort" + "strings" + "unicode" + + "github.com/opencost/bingen/internal/types" +) + +// primitiveInfo holds the Java syntax for a primitive IR type: the unboxed and +// boxed type names and the ReadBuffer/WriteBuffer method suffixes. Unsigned +// values widen one step (uint/uint32 -> long, uint8/uint16 -> int) to preserve +// their full range. Strings are handled separately because of string-table +// support. +type primitiveInfo struct { + prim string + boxed string + read string + write string +} + +var primitives = map[uint8]primitiveInfo{ + types.TypeBool: {"boolean", "Boolean", "readBool", "writeBool"}, + types.TypeInt: {"int", "Integer", "readInt", "writeInt"}, + types.TypeInt8: {"byte", "Byte", "readInt8", "writeInt8"}, + types.TypeInt16: {"short", "Short", "readInt16", "writeInt16"}, + types.TypeInt32: {"int", "Integer", "readInt32", "writeInt32"}, + types.TypeInt64: {"long", "Long", "readInt64", "writeInt64"}, + types.TypeUInt: {"long", "Long", "readUInt", "writeUInt"}, + types.TypeUInt8: {"int", "Integer", "readUInt8", "writeUInt8"}, + types.TypeUInt16: {"int", "Integer", "readUInt16", "writeUInt16"}, + types.TypeUInt32: {"long", "Long", "readUInt32", "writeUInt32"}, + types.TypeUInt64: {"long", "Long", "readUInt64", "writeUInt64"}, + types.TypeFloat32: {"float", "Float", "readFloat32", "writeFloat32"}, + types.TypeFloat64: {"double", "Double", "readFloat64", "writeFloat64"}, +} + +// JavaType returns the Java type string for a field of the given IR type. +// Primitive fields are unboxed unless they are pointers (nilable), in which case +// the boxed wrapper is used. Slice/map element types are always boxed because +// Java generics cannot hold primitives. +func JavaType(t types.GenType) string { + return javaType(t, false) +} + +func javaType(t types.GenType, forceBox bool) string { + box := forceBox || t.IsPtr() + + if p, ok := primitives[t.Code()]; ok { + return toPrimitive(box, p.prim, p.boxed) + } + + switch t.Code() { + case types.TypeString: + return "String" + case types.TypeSlice: + st := t.(*types.SliceType) + return "List<" + javaType(st.InnerType, true) + ">" + case types.TypeMap: + mt := t.(*types.MapType) + return "Map<" + javaType(mt.KeyType, true) + ", " + javaType(mt.ValueType, true) + ">" + case types.TypeInterface: + if name := t.Name(); name != "interface{}" { + return name + } + return "Object" + case types.TypeStruct: + return t.Name() + case types.TypeAlias: + return javaType(t.(*types.AliasType).Alias, box) + case types.TypeReference: + if resolved := t.(*types.ReferenceType).Resolve(); resolved != nil { + return javaType(resolved, box) + } + + if ext, ok := externalTypes[t.Name()]; ok { + return ext.javaType + } + + return externalRefName(t.Name()) + } + + return "Object" +} + +// toPrimitive returns the boxed wrapper when box is true, otherwise the primitive. +func toPrimitive(box bool, primitive string, boxed string) string { + if box { + return boxed + } + return primitive +} + +// externalRefName reduces a qualified go type name (ie: "shared.Name") to its +// bare Java type name. +func externalRefName(name string) string { + if idx := strings.LastIndex(name, "."); idx >= 0 { + return name[idx+1:] + } + return name +} + +// JavaFieldName converts an exported go field name to a conventional Java +// camelCase name, guarding against reserved words. +func JavaFieldName(goName string) string { + if goName == "" { + return goName + } + + runes := []rune(goName) + runes[0] = unicode.ToLower(runes[0]) + name := string(runes) + if javaReservedWords[name] { + return name + "_" + } + return name +} + +// requiredImports returns the sorted set of imports required by the struct's +// fields: java.util collections and any external-type imports (ie: java.time), +// recursing into nested element types. +func requiredImports(st *types.StructType) []string { + need := make(map[string]bool) + + for _, f := range st.Fields { + types.WalkType(f.Type, func(t types.GenType) { + switch t.Code() { + case types.TypeSlice: + need["java.util.List"] = true + case types.TypeMap: + need["java.util.Map"] = true + case types.TypeReference: + if ext, ok := externalTypes[t.Name()]; ok { + for _, imp := range ext.typeImports { + need[imp] = true + } + } + } + }) + } + + out := make([]string, 0, len(need)) + for imp := range need { + out = append(out, imp) + } + sort.Strings(out) + + return out +} diff --git a/internal/generator/java/javatype_test.go b/internal/generator/java/javatype_test.go new file mode 100644 index 0000000..59aab9d --- /dev/null +++ b/internal/generator/java/javatype_test.go @@ -0,0 +1,83 @@ +package java + +import ( + "testing" + + "github.com/opencost/bingen/internal/types" +) + +func basic(code uint8) types.GenType { + return types.BasicTypes[code] +} + +func TestJavaType_Primitives(t *testing.T) { + cases := map[uint8]string{ + types.TypeBool: "boolean", + types.TypeInt: "int", + types.TypeInt8: "byte", + types.TypeInt16: "short", + types.TypeInt32: "int", + types.TypeInt64: "long", + types.TypeUInt: "long", + types.TypeUInt8: "int", + types.TypeUInt16: "int", + types.TypeUInt32: "long", + types.TypeUInt64: "long", + types.TypeFloat32: "float", + types.TypeFloat64: "double", + types.TypeString: "String", + } + + for code, want := range cases { + if got := JavaType(basic(code)); got != want { + t.Errorf("JavaType(code=%d) = %q, want %q", code, got, want) + } + } +} + +func TestJavaType_PointerBoxes(t *testing.T) { + if got := JavaType(basic(types.TypeInt).CreatePtr()); got != "Integer" { + t.Errorf("JavaType(*int) = %q, want Integer", got) + } + if got := JavaType(basic(types.TypeFloat64).CreatePtr()); got != "Double" { + t.Errorf("JavaType(*float64) = %q, want Double", got) + } + // String is a reference type; a pointer stays String. + if got := JavaType(basic(types.TypeString).CreatePtr()); got != "String" { + t.Errorf("JavaType(*string) = %q, want String", got) + } +} + +func TestJavaType_SliceAndMapBoxInner(t *testing.T) { + slice := &types.SliceType{ + BasicType: types.NewBasicType("", "[]int", types.TypeSlice, false, false), + InnerType: basic(types.TypeInt), + } + if got := JavaType(slice); got != "List" { + t.Errorf("JavaType([]int) = %q, want List", got) + } + + m := &types.MapType{ + BasicType: types.NewBasicType("", "map[string]float64", types.TypeMap, false, false), + KeyType: basic(types.TypeString), + ValueType: basic(types.TypeFloat64), + } + if got := JavaType(m); got != "Map" { + t.Errorf("JavaType(map[string]float64) = %q, want Map", got) + } +} + +func TestJavaFieldName(t *testing.T) { + cases := map[string]string{ + "Name": "name", + "Children": "children", + "ID": "iD", + "Value": "value", + } + + for in, want := range cases { + if got := JavaFieldName(in); got != want { + t.Errorf("JavaFieldName(%q) = %q, want %q", in, got, want) + } + } +} diff --git a/internal/generator/java/migration_test.go b/internal/generator/java/migration_test.go new file mode 100644 index 0000000..3de3f8f --- /dev/null +++ b/internal/generator/java/migration_test.go @@ -0,0 +1,90 @@ +package java + +import ( + "os" + "path/filepath" + "testing" + + "github.com/opencost/bingen/tests/container" +) + +// containerHooksSource is the user-supplied migration hook, mirroring the go +// migrateContainer func: when the legacy oldValue is set, promote it to Value. +const containerHooksSource = `package com.opencost.containerv2; + +public final class ContainerHooks { + private ContainerHooks() { + } + + public static Container migrate(Container c, int from, int to) { + if (c.oldValue() != 0.0) { + return new Container(c.name(), c.children(), c.oldValue(), c.oldValue()); + } + return c; + } +} +` + +const migrateMainSource = `import com.opencost.containerv2.Container; +import com.opencost.containerv2.ContainerDecoder; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class MigrateMain { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) throws Exception { + byte[] in = Files.readAllBytes(Path.of(args[0])); + Container c = ContainerDecoder.fromBytes(in); + check(c.name().equals("legacy"), "name=" + c.name()); + check(c.oldValue() == 42.5, "oldValue=" + c.oldValue()); + check(c.value() != null && c.value() == 42.5, "value=" + c.value()); + System.out.println("OK"); + } +} +` + +// TestVersioning_MigrateV1UnderV2 encodes a v1 Container in go, then decodes it +// with the java v2 codec: the field-version gate defaults the new Value to null, +// oldValue absorbs the v1 float, and the migrate hook promotes it to Value. +func TestVersioning_MigrateV1UnderV2(t *testing.T) { + checkJava(t) + + // compile java test harness + + javaMain := &javaSource{ + FileName: "MigrateMain.java", + Source: migrateMainSource, + } + javaHook := &javaSource{ + FileName: "ContainerHooks.java", + Source: containerHooksSource, + } + + v2Dir, tc := loadTestTypes(t, "containerv2") + out := buildJavaTestFromTypes(t, v2Dir, "containerv2", BaseJavaPackage, tc, javaMain, javaHook) + + // build a v1 container, marshal binary, write to java test harness dir + v1 := container.Container{Name: "legacy", Children: []string{"a", "b"}, Value: 42.5} + v1Bytes, err := v1.MarshalBinary() + if err != nil { + t.Fatalf("go v1 MarshalBinary: %v", err) + } + + inPath := filepath.Join(out, "v1.bin") + if err := os.WriteFile(inPath, v1Bytes, 0o600); err != nil { + t.Fatalf("writing v1.bin: %v", err) + } + + o, err := runJavaTest(t, out, javaMain.HarnessName(), "v1.bin") + if err != nil { + t.Fatalf("MigrateMain failed: %v\n%s", err, o) + } + + t.Logf("%s", string(o)) +} diff --git a/internal/generator/java/options.go b/internal/generator/java/options.go new file mode 100644 index 0000000..b9caaa8 --- /dev/null +++ b/internal/generator/java/options.go @@ -0,0 +1,116 @@ +// Package java implements the Java exporter for bingen. It reuses the +// language-neutral type intermediate representation produced by +// internal/types and emits Java 21 records, split encoder/decoder types, and +// the supporting runtime for the annotated Go structs. +package java + +import ( + "fmt" + "path/filepath" + "strings" +) + +// Language-specific option keys accepted via the CLI (-opt key=value). +const ( + // OptBasePackage is the required base Java package. The go package name is + // appended to it so that the final package's last segment always equals the + // source go package (ie: base "com.opencost" + go "container" -> + // "com.opencost.container"). + OptBasePackage = "basePackage" + + // OptOutputDir is the optional root output directory. Generated sources are + // written beneath it following the java package path. Defaults to ".". + OptOutputDir = "outputDir" + + // OptGoImport is the optional fully-qualified import path of the source go + // package. It is used to build the interface type strings written on the + // wire. When omitted it is resolved from the source directory at generation + // time. + OptGoImport = "goImport" + + // OptRuntimePackage is the optional java package the shared runtime (buffers, + // codec contexts, registry) is emitted into. It is kept separate from the + // data package so it is not duplicated when several go packages are generated + // under the same base package. Defaults to DefaultRuntimePackage. + OptRuntimePackage = "runtimePackage" +) + +// DefaultRuntimePackage is the java package the shared bingen runtime is +// emitted into when OptRuntimePackage is not provided. +const DefaultRuntimePackage = "com.bingen" + +// Options is the resolved, validated configuration for a single Java +// generation invocation. +type Options struct { + // BasePackage is the validated base java package (ie: "com.opencost"). + BasePackage string + + // GoPackage is the source go package name (ie: "container"). + GoPackage string + + // JavaPackage is BasePackage + "." + GoPackage. Its last segment always + // equals GoPackage. + JavaPackage string + + // OutputDir is the root directory generated sources are written beneath. + OutputDir string + + // GoImport is the fully-qualified import path of the source go package, or + // the empty string when it should be resolved at generation time. + GoImport string + + // RuntimePackage is the java package the shared runtime is emitted into. + RuntimePackage string +} + +// FromConfig validates the language-specific config map for the provided go +// package and returns the resolved Options. +func FromConfig(goPackage string, cfg map[string]string) (*Options, error) { + base := strings.TrimSpace(cfg[OptBasePackage]) + if base == "" { + return nil, fmt.Errorf("java: required option %q is not set", OptBasePackage) + } + if err := validateJavaPackage(base); err != nil { + return nil, fmt.Errorf("java: invalid %q %q: %w", OptBasePackage, base, err) + } + + outputDir := strings.TrimSpace(cfg[OptOutputDir]) + if outputDir == "" { + outputDir = "." + } + + runtimePkg := strings.TrimSpace(cfg[OptRuntimePackage]) + if runtimePkg == "" { + runtimePkg = DefaultRuntimePackage + } + if err := validateJavaPackage(runtimePkg); err != nil { + return nil, fmt.Errorf("java: invalid %q %q: %w", OptRuntimePackage, runtimePkg, err) + } + + return &Options{ + BasePackage: base, + GoPackage: goPackage, + JavaPackage: base + "." + goPackage, + OutputDir: outputDir, + GoImport: strings.TrimSpace(cfg[OptGoImport]), + RuntimePackage: runtimePkg, + }, nil +} + +// PackageDir returns the directory generated data .java files are written to, +// resolving the java package into nested directories beneath OutputDir. +func (o *Options) PackageDir() string { + return o.packageDir(o.JavaPackage) +} + +// RuntimePackageDir returns the directory the shared runtime .java files are +// written to. +func (o *Options) RuntimePackageDir() string { + return o.packageDir(o.RuntimePackage) +} + +// packageDir resolves a java package into nested directories beneath OutputDir. +func (o *Options) packageDir(pkg string) string { + segments := strings.Split(pkg, ".") + return filepath.Join(append([]string{o.OutputDir}, segments...)...) +} diff --git a/internal/generator/java/options_test.go b/internal/generator/java/options_test.go new file mode 100644 index 0000000..50b27b5 --- /dev/null +++ b/internal/generator/java/options_test.go @@ -0,0 +1,131 @@ +package java + +import ( + "path/filepath" + "testing" +) + +func TestFromConfig_DerivesJavaPackage(t *testing.T) { + opts, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // The last segment of the java package must equal the go package name. + if opts.JavaPackage != "com.opencost.container" { + t.Fatalf("JavaPackage = %q, want %q", opts.JavaPackage, "com.opencost.container") + } + if opts.GoPackage != "container" { + t.Fatalf("GoPackage = %q, want %q", opts.GoPackage, "container") + } + if opts.OutputDir != "." { + t.Fatalf("OutputDir = %q, want default %q", opts.OutputDir, ".") + } +} + +func TestFromConfig_RuntimePackageDefaultAndOverride(t *testing.T) { + opts, err := FromConfig("container", map[string]string{OptBasePackage: "com.opencost"}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if opts.RuntimePackage != DefaultRuntimePackage { + t.Fatalf("RuntimePackage = %q, want default %q", opts.RuntimePackage, DefaultRuntimePackage) + } + + opts, err = FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptRuntimePackage: "com.acme.rt", + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if opts.RuntimePackage != "com.acme.rt" { + t.Fatalf("RuntimePackage = %q, want %q", opts.RuntimePackage, "com.acme.rt") + } + + if _, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptRuntimePackage: "com.9bad", + }); err == nil { + t.Fatal("expected error for invalid runtimePackage") + } +} + +func TestRuntimePackageDir(t *testing.T) { + opts, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptOutputDir: "build/gen", + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := filepath.Join("build", "gen", "com", "bingen") + if got := opts.RuntimePackageDir(); got != want { + t.Fatalf("RuntimePackageDir() = %q, want %q", got, want) + } +} + +func TestFromConfig_RequiresBasePackage(t *testing.T) { + if _, err := FromConfig("container", map[string]string{}); err == nil { + t.Fatal("expected error when basePackage is missing") + } +} + +func TestFromConfig_TrimsAndValidatesBasePackage(t *testing.T) { + cases := map[string]bool{ + "com.opencost": true, + " com.opencost ": true, + "com.opencost.core": true, + "com._x$y.z9": true, + "": false, + "com..opencost": false, + "com.9bad": false, + "com.opencost.": false, + "com.op encost": false, + "com.class": false, // reserved word + } + + for base, wantOK := range cases { + _, err := FromConfig("container", map[string]string{OptBasePackage: base}) + if wantOK && err != nil { + t.Errorf("FromConfig(base=%q) unexpected error: %v", base, err) + } + if !wantOK && err == nil { + t.Errorf("FromConfig(base=%q) expected error, got nil", base) + } + } +} + +func TestFromConfig_HonorsOutputDirAndGoImport(t *testing.T) { + opts, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptOutputDir: "build/gen", + OptGoImport: "github.com/opencost/bingen/tests/container", + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if opts.OutputDir != "build/gen" { + t.Fatalf("OutputDir = %q, want %q", opts.OutputDir, "build/gen") + } + if opts.GoImport != "github.com/opencost/bingen/tests/container" { + t.Fatalf("GoImport = %q", opts.GoImport) + } +} + +func TestPackageDir(t *testing.T) { + opts, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptOutputDir: "build/gen", + }) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + want := filepath.Join("build", "gen", "com", "opencost", "container") + if got := opts.PackageDir(); got != want { + t.Fatalf("PackageDir() = %q, want %q", got, want) + } +} diff --git a/internal/generator/java/parity_test.go b/internal/generator/java/parity_test.go new file mode 100644 index 0000000..96c5bab --- /dev/null +++ b/internal/generator/java/parity_test.go @@ -0,0 +1,260 @@ +package java + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/opencost/bingen/pkg/util" + "github.com/opencost/bingen/tests/streamfeed" +) + +// goldenBuffer writes a fixed schema of every primitive + string + raw bytes +// using the reference go util.Buffer. The java harness in bufferParityHarness +// reads this exact schema in order, so the two must stay in lockstep. +func goldenBuffer() []byte { + b := util.NewBuffer() + b.WriteBool(true) + b.WriteInt(-123456) + b.WriteInt8(-8) + b.WriteInt16(-1600) + b.WriteInt32(-32000000) + b.WriteInt64(-9000000000000) + b.WriteUInt(4000000000) + b.WriteUInt8(200) + b.WriteUInt16(60000) + b.WriteUInt32(4000000001) + b.WriteUInt64(uint64(0xF0F1F2F3F4F5F6F7)) + b.WriteFloat32(3.5) + b.WriteFloat64(-12345.6789) + b.WriteString("hello") + b.WriteString("héllo✓") + b.WriteBytes([]byte{1, 2, 3, 255, 0}) + return b.Bytes() +} + +// bufferParityHarness reads the go-produced golden blob with the generated +// ReadBuffer, spot-checks a handful of values, then re-encodes every value with +// the generated WriteBuffer and asserts the bytes match the golden blob exactly. +// It needs no expected values baked in beyond the spot-checks: read∘write must +// reproduce the reference encoder's bytes. +const bufferParityHarness = `import com.bingen.ReadBuffer; +import com.bingen.WriteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +public final class BufferParity { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) throws Exception { + byte[] golden = Files.readAllBytes(Path.of(args[0])); + ReadBuffer rb = ReadBuffer.fromBytes(golden); + + boolean v1 = rb.readBool(); + int v2 = rb.readInt(); + byte v3 = rb.readInt8(); + short v4 = rb.readInt16(); + int v5 = rb.readInt32(); + long v6 = rb.readInt64(); + long v7 = rb.readUInt(); + int v8 = rb.readUInt8(); + int v9 = rb.readUInt16(); + long v10 = rb.readUInt32(); + long v11 = rb.readUInt64(); + float v12 = rb.readFloat32(); + double v13 = rb.readFloat64(); + String v14 = rb.readString(); + String v15 = rb.readString(); + byte[] v16 = rb.readBytes(5); + + check(v1, "readBool"); + check(v2 == -123456, "readInt"); + check(v3 == (byte) -8, "readInt8"); + check(v4 == (short) -1600, "readInt16"); + check(v5 == -32000000, "readInt32"); + check(v6 == -9000000000000L, "readInt64"); + check(v7 == 4000000000L, "readUInt"); + check(v8 == 200, "readUInt8"); + check(v9 == 60000, "readUInt16"); + check(v10 == 4000000001L, "readUInt32"); + check(v11 == 0xF0F1F2F3F4F5F6F7L, "readUInt64"); + check(v12 == 3.5f, "readFloat32"); + check(v13 == -12345.6789, "readFloat64"); + check(v14.equals("hello"), "readString ascii"); + check(v15.equals("héllo✓"), "readString utf8"); + check(Arrays.equals(v16, new byte[] {1, 2, 3, (byte) 255, 0}), "readBytes"); + + WriteBuffer wb = WriteBuffer.create(); + wb.writeBool(v1); + wb.writeInt(v2); + wb.writeInt8(v3); + wb.writeInt16(v4); + wb.writeInt32(v5); + wb.writeInt64(v6); + wb.writeUInt(v7); + wb.writeUInt8(v8); + wb.writeUInt16(v9); + wb.writeUInt32(v10); + wb.writeUInt64(v11); + wb.writeFloat32(v12); + wb.writeFloat64(v13); + wb.writeString(v14); + wb.writeString(v15); + wb.writeBytes(v16); + + byte[] out = wb.bytes(); + check(Arrays.equals(out, golden), "re-encoded bytes != golden"); + System.out.println("OK"); + } +} +` + +func TestRuntimeBufferParity(t *testing.T) { + const goPackage = "parity" + const javaPackage = "com.example" + const javaHarness = "BufferParity.java" + + checkJava(t) + + javaMain := &javaSource{ + FileName: javaHarness, + Source: bufferParityHarness, + } + + dir := createAndEmitRuntime(t, goPackage, javaPackage) + readBuffSrc := filepath.Join("com", "bingen", "ReadBuffer.java") + writeBuffSrc := filepath.Join("com", "bingen", "WriteBuffer.java") + + // write golden buffer to runtime dir + goldenPath := filepath.Join(dir, "golden.bin") + if err := os.WriteFile(goldenPath, goldenBuffer(), 0o600); err != nil { + t.Fatalf("writing golden: %v", err) + } + + // write java source to runtime dir + writeJavaSource(t, dir, javaMain) + + compileJava(t, dir, []string{ + readBuffSrc, + writeBuffSrc, + javaMain.FileName, + }) + + out, err := runJavaTest(t, dir, javaMain.HarnessName(), "golden.bin") + if err != nil { + t.Fatalf("java buffer parity harness failed: %v\n%s", err, out) + } + t.Logf("%s", string(out)) +} + +// goStreamSeq streams data with the generated go streamer and returns the same +// canonical representation the Java harness produces. +func goStreamSeq(data []byte) []string { + var seq []string + stream := streamfeed.NewFeedStream(bytes.NewReader(data)) + defer stream.Close() + + for fi, v := range stream.Stream() { + switch { + case v == nil: + seq = append(seq, fi.Name+"\t\t") + case v.Index != nil: + seq = append(seq, fmt.Sprintf("%s\t%v\t%v", fi.Name, v.Index, v.Value)) + default: + seq = append(seq, fmt.Sprintf("%s\t\t%v", fi.Name, v.Value)) + } + } + return seq +} + +// TestStreaming_GoJavaParity feeds identical encoded bytes to the Go and Java +// streamers and asserts they yield the same (field, index, value) sequence, +// proving the Java streamer reads the wire format exactly like Go's. +func TestStreaming_GoJavaParity(t *testing.T) { + // streamSeqHarness streams the go-encoded bytes with the generated Java push + // streamer and writes one canonical "field\tindex\tvalue" line per yield. + const streamSeqHarness = `import com.opencost.streamfeed.FeedStreamer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public final class StreamSeqMain { + public static void main(String[] args) throws Exception { + byte[] data = Files.readAllBytes(Path.of(args[0])); + List seq = new ArrayList<>(); + FeedStreamer.stream(data, (fi, v) -> { + String line; + if (v == null) { + line = fi.name() + "\t\t"; + } else if (v.index() != null) { + line = fi.name() + "\t" + String.valueOf(v.index()) + "\t" + String.valueOf(v.value()); + } else { + line = fi.name() + "\t\t" + String.valueOf(v.value()); + } + seq.add(line); + return true; + }); + Files.writeString(Path.of(args[1]), String.join("\n", seq)); + } +} +` + + const goPackage = "streamfeed" + const harnessName = "StreamSeqMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: streamSeqHarness, + } + + dir := buildJavaTest(t, goPackage, javaMain) + inPath := filepath.Join(dir, "feed.bin") + seqPath := filepath.Join(dir, "javaseq.txt") + + feed := &streamfeed.Feed{ + Name: "news", + Tags: []string{"a", "b", "c"}, + Count: 7, + Meta: map[string]string{"k1": "v1", "k2": "v2"}, + } + data, err := feed.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary: %v", err) + } + + if err := os.WriteFile(inPath, data, 0o600); err != nil { + t.Fatalf("writing feed.bin: %v", err) + } + + o, err := runJavaTest(t, dir, harnessName, "feed.bin", "javaseq.txt") + if err != nil { + t.Fatalf("StreamSeqMain failed: %v\n%s", err, o) + } + + javaSeq, err := os.ReadFile(seqPath) + if err != nil { + t.Fatalf("reading java sequence: %v", err) + } + + goSeq := strings.Join(goStreamSeq(data), "\n") + if goSeq != string(javaSeq) { + t.Fatalf("stream sequence mismatch:\n go:\n%s\n java:\n%s", goSeq, javaSeq) + } + + // Sanity: the sequence must actually contain the flattened elements. + if !strings.Contains(goSeq, "Tags\t0\ta") || !strings.Contains(goSeq, "Meta\tk") { + t.Fatalf("unexpected sequence content:\n%s", goSeq) + } +} diff --git a/internal/generator/java/record_test.go b/internal/generator/java/record_test.go new file mode 100644 index 0000000..4192f61 --- /dev/null +++ b/internal/generator/java/record_test.go @@ -0,0 +1,43 @@ +package java + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestGenerate_RecordCompiles(t *testing.T) { + out := t.TempDir() + opts, err := FromConfig("container", map[string]string{ + OptBasePackage: "com.opencost", + OptOutputDir: out, + }) + if err != nil { + t.Fatalf("FromConfig: %v", err) + } + + st := containerStruct() + if err := Generate(".", newTypesCollectionWith(st), opts); err != nil { + t.Fatalf("Generate: %v", err) + } + + recordPath := filepath.Join(out, "com", "opencost", "container", "Container.java") + data, err := os.ReadFile(recordPath) + if err != nil { + t.Fatalf("reading generated record: %v", err) + } + src := string(data) + for _, want := range []string{ + "public record Container(String name, List children, double value)", + "public static Builder builder()", + "public Container build()", + "import java.util.List;", + } { + if !strings.Contains(src, want) { + t.Errorf("Container.java missing %q\n---\n%s", want, src) + } + } + + compileJavaTree(t, out) +} diff --git a/internal/generator/java/roundtrip_test.go b/internal/generator/java/roundtrip_test.go new file mode 100644 index 0000000..a28609f --- /dev/null +++ b/internal/generator/java/roundtrip_test.go @@ -0,0 +1,378 @@ +package java + +import ( + "testing" + "time" + + "github.com/opencost/bingen/internal/types" + "github.com/opencost/bingen/tests/aliasnil" + "github.com/opencost/bingen/tests/container" + "github.com/opencost/bingen/tests/shape" + "github.com/opencost/bingen/tests/sttable" + "github.com/opencost/bingen/tests/timerec" +) + +// TestRoundTrip_Decoder marshals a Container in go, has java decode and +// re-encode it, and asserts the bytes are identical and the values survived. +func TestRoundTrip_Decoder(t *testing.T) { + const decodeReencodeHarness = `import com.opencost.container.Container; +import com.opencost.container.ContainerDecoder; +import com.opencost.container.ContainerEncoder; +import com.bingen.DecodingContext; +import com.bingen.EncodingContext; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class DecodeReencodeMain { + public static void main(String[] args) throws Exception { + byte[] in = Files.readAllBytes(Path.of(args[0])); + Container c = ContainerDecoder.INSTANCE.decode(DecodingContext.fromBytes(in)); + EncodingContext ctx = EncodingContext.create(); + ContainerEncoder.INSTANCE.encode(c, ctx); + Files.write(Path.of(args[1]), ctx.toBytes()); + } +} +` + + const goPackage = "container" + const harnessName = "DecodeReencodeMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: decodeReencodeHarness, + } + + testRunner := newRoundTripTestBuilder[container.Container](goPackage, javaMain). + WithAssertion(func(t *testing.T, c1, c2 *container.Container) { + if c2.Name != c1.Name || c2.Value != c1.Value || len(c2.Children) != len(c1.Children) { + t.Fatalf("values not preserved: got %+v want %+v", c2, c1) + } + }). + Build(t) + + defer testRunner.Cleanup() + + instance := &container.Container{ + Name: "TestContainer", + Children: []string{"a", "b", "c"}, + Value: 3.14, + } + + testRunner.Run(instance) +} + +// TestInterface_ShapeRoundTrip encodes a Drawing with a heterogeneous []Shape in +// go, has java decode + re-encode it through the TypeRegistry, and asserts the +// bytes are identical and the concrete types survived. +func TestRoundTripInterface_Shape(t *testing.T) { + const drawingReencodeHarness = `import com.opencost.shape.Drawing; +import com.opencost.shape.DrawingDecoder; +import com.opencost.shape.DrawingEncoder; +import com.bingen.DecodingContext; +import com.bingen.EncodingContext; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class DrawingReencodeMain { + public static void main(String[] args) throws Exception { + byte[] in = Files.readAllBytes(Path.of(args[0])); + Drawing d = DrawingDecoder.INSTANCE.decode(DecodingContext.fromBytes(in)); + EncodingContext ctx = EncodingContext.create(); + DrawingEncoder.INSTANCE.encode(d, ctx); + Files.write(Path.of(args[1]), ctx.toBytes()); + } +} +` + const goPackage = "shape" + const harnessName = "DrawingReencodeMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: drawingReencodeHarness, + } + testRunner := newRoundTripTestBuilder[shape.Drawing](goPackage, javaMain). + WithAssertion(func(t *testing.T, t1 *shape.Drawing, t2 *shape.Drawing) { + t.Helper() + + if t2.Name != t1.Name || len(t2.Shapes) != len(t1.Shapes) { + t.Fatalf("unexpected drawing: %+v", t2) + } + c, ok := t2.Shapes[0].(*shape.Circle) + if !ok || c.Radius != 2 { + t.Fatalf("Shapes[0] = %#v, want *Circle{Radius:2}", t2.Shapes[0]) + } + s, ok := t2.Shapes[1].(*shape.Square) + if !ok || s.Side != 3 { + t.Fatalf("Shapes[1] = %#v, want *Square{Side:3}", t2.Shapes[1]) + } + }). + Build(t) + + defer testRunner.Cleanup() + + instance := &shape.Drawing{ + Name: "pic", + Shapes: []shape.Shape{ + &shape.Circle{ + Radius: 2, + }, + &shape.Square{ + Side: 3, + }, + }, + } + + testRunner.Run(instance) +} + +// TestStringTable_GoToJavaToGo encodes a string-table Doc in go (repeated strings +// deduplicated into a BGST-prefixed table), has java decode + re-encode it, and +// asserts the bytes are identical and the values survived. +func TestRoundTrip_StringTable(t *testing.T) { + const docReencodeHarness = `import com.opencost.sttable.Doc; +import com.opencost.sttable.DocDecoder; +import com.opencost.sttable.DocEncoder; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class DocReencodeMain { + public static void main(String[] args) throws Exception { + byte[] in = Files.readAllBytes(Path.of(args[0])); + Doc d = DocDecoder.fromBytes(in); + Files.write(Path.of(args[1]), DocEncoder.toBytes(d)); + } +} +` + + const goPackage = "sttable" + const harnessName = "DocReencodeMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: docReencodeHarness, + } + testRunner := newRoundTripTestBuilder[sttable.Doc](goPackage, javaMain). + WithAssertion(func(t *testing.T, t1 *sttable.Doc, t2 *sttable.Doc) { + t.Helper() + + if t2.Title != t1.Title || t2.Author != t1.Author || len(t2.Tags) != len(t1.Tags) { + t.Fatalf("values not preserved: %+v", t2) + } + for i, tag := range t2.Tags { + if t1.Tags[i] != tag { + t.Fatalf("values not preserved: %+v", t2) + } + } + }). + Build(t) + + defer testRunner.Cleanup() + + instance := &sttable.Doc{ + Title: "report", + Tags: []string{ + "a", + "report", + "b", + }, + Author: "report", + } + + testRunner.Run(instance) +} + +// TestRoundTrip_Time encodes an Event with a UTC time.Time in go, has java +// decode + re-encode it through GoTime, and asserts the bytes are identical and +// the instant survived. +func TestRoundTrip_Time(t *testing.T) { + const eventReencodeHarness = `import com.opencost.timerec.Event; +import com.opencost.timerec.EventDecoder; +import com.opencost.timerec.EventEncoder; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class EventReencodeMain { + public static void main(String[] args) throws Exception { + byte[] in = Files.readAllBytes(Path.of(args[0])); + Event e = EventDecoder.fromBytes(in); + Files.write(Path.of(args[1]), EventEncoder.toBytes(e)); + } +} +` + + const goPackage = "timerec" + const harnessName = "EventReencodeMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: eventReencodeHarness, + } + + testRunner := newRoundTripTestBuilder[timerec.Event](goPackage, javaMain). + WithAssertion(func(t *testing.T, t1 *timerec.Event, t2 *timerec.Event) { + t.Helper() + + if t2.Name != t1.Name || t2.Seq != t1.Seq { + t.Fatalf("values not preserved: %+v (want %+v)", t2, t1) + } + if !t2.At.Equal(t1.At) { + t.Fatalf("Time values not preserved. Got: %s. Expected: %s", t1.At, t2.At) + } + }). + Build(t) + + defer testRunner.Cleanup() + + cases := map[string]time.Time{ + "utc_nanos": time.Date(2023, 1, 2, 3, 4, 5, 123456789, time.UTC), + "utc_flat": time.Date(2023, 1, 2, 3, 4, 5, 0, time.UTC), + "offset_ist": time.Date(2023, 1, 2, 3, 4, 5, 0, time.FixedZone("IST", 5*3600+30*60)), + "offset_pst": time.Date(2023, 1, 2, 3, 4, 5, 500, time.FixedZone("PST", -8*3600)), + } + + for name, at := range cases { + t.Run(name, func(t *testing.T) { + instance := &timerec.Event{ + Name: name, + At: at, + Seq: 9, + } + + testRunner.Run(instance) + }) + } +} + +// TestRoundTrip_NilableAlias covers an alias whose underlying type is nilable +// (Tags = []string). The nil-flag byte must be read symmetrically or the +// trailing Count field is corrupted. +func TestRoundTrip_NilableAlias(t *testing.T) { + const holderReencodeHarness = `import com.opencost.aliasnil.Holder; +import com.opencost.aliasnil.HolderDecoder; +import com.opencost.aliasnil.HolderEncoder; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class HolderReencodeMain { + public static void main(String[] args) throws Exception { + byte[] in = Files.readAllBytes(Path.of(args[0])); + Holder h = HolderDecoder.fromBytes(in); + Files.write(Path.of(args[1]), HolderEncoder.toBytes(h)); + } +} +` + const goPackage = "aliasnil" + const harnessName = "HolderReencodeMain" + + checkJava(t) + + javaMain := &javaSource{ + FileName: harnessName, + Source: holderReencodeHarness, + } + + testRunner := newRoundTripTestBuilder[aliasnil.Holder](goPackage, javaMain). + WithAssertion(func(t *testing.T, h1, h2 *aliasnil.Holder) { + if h2.Name != "h" || len(h2.Tags) != 2 || h2.Tags[0] != "a" || h2.Tags[1] != "b" || h2.Count != 7 { + t.Fatalf("values not preserved: %+v", h2) + } + }). + Build(t) + + defer testRunner.Cleanup() + + instance := &aliasnil.Holder{ + Name: "h", + Tags: aliasnil.Tags{"a", "b"}, + Count: 7, + } + + testRunner.Run(instance) +} + +// feedStruct builds a streamable Feed{Name string, Items []string, Score int}. +func feedStruct() *types.StructType { + stringT := types.BasicTypes[types.TypeString] + return &types.StructType{ + BasicType: types.NewBasicType("", "Feed", types.TypeStruct, false, false), + Fields: []*types.StructField{ + {Name: "Name", Type: stringT}, + {Name: "Items", Type: &types.SliceType{ + BasicType: types.NewBasicType("", "[]string", types.TypeSlice, false, false), + InnerType: stringT, + }}, + {Name: "Score", Type: types.BasicTypes[types.TypeInt]}, + }, + Opts: &types.GenerateTypeOpts{SetName: "Feed", SetVersion: 1, IsStreamable: true}, + } +} + +// TestStreamer_JavaPushRoundTrip encodes a Feed and streams it back through the +// generated push streamer, asserting the fields arrive in order with the Items +// slice flattened one element per callback. +func TestRoundTrip_JavaStreamPush(t *testing.T) { + const feedStreamHarness = `import com.opencost.feed.Feed; +import com.opencost.feed.FeedEncoder; +import com.opencost.feed.FeedStreamer; +import java.util.ArrayList; +import java.util.List; + +public final class FeedStreamMain { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) { + byte[] data = FeedEncoder.toBytes(new Feed("news", List.of("a", "b", "c"), 7)); + + List fields = new ArrayList<>(); + List items = new ArrayList<>(); + int[] score = {-1}; + + FeedStreamer.stream(data, (fi, v) -> { + fields.add(fi.name()); + if (fi.name().equals("Items") && v != null) { + items.add((String) v.value()); + } + if (fi.name().equals("Score") && v != null) { + score[0] = (Integer) v.value(); + } + return true; + }); + + check(fields.equals(List.of("Name", "Items", "Items", "Items", "Score")), "fields=" + fields); + check(items.equals(List.of("a", "b", "c")), "items=" + items); + check(score[0] == 7, "score=" + score[0]); + System.out.println("OK"); + } +} +` + + const goPackage = "feed" + const harnessName = "FeedStreamMain" + + checkJava(t) + + tc := newTypesCollectionWith(feedStruct()) + out := buildJavaTestFromTypes(t, ".", goPackage, BaseJavaPackage, tc, &javaSource{ + FileName: harnessName, + Source: feedStreamHarness, + }) + + o, err := runJavaTest(t, out, harnessName) + if err != nil { + t.Fatalf("FeedStreamMain failed: %v\n%s", err, o) + } + t.Logf("%s", o) +} diff --git a/internal/generator/java/stream_test.go b/internal/generator/java/stream_test.go new file mode 100644 index 0000000..92b5331 --- /dev/null +++ b/internal/generator/java/stream_test.go @@ -0,0 +1,133 @@ +package java + +import ( + "testing" +) + +// TestStreaming_Incremental proves the Java streamer consumes an InputStream +// incrementally (like Go's io.Reader), rather than requiring the whole payload +// in memory up front. +func TestStreaming_Incremental(t *testing.T) { + const incrementalHarness = `import com.opencost.streamfeed.Feed; +import com.opencost.streamfeed.FeedEncoder; +import com.opencost.streamfeed.FeedStreamer; +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public final class IncrementalMain { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) { + List tags = new ArrayList<>(); + for (int i = 0; i < 1000; i++) { + tags.add("tag-" + i); + } + byte[] data = FeedEncoder.toBytes(new Feed("N", tags, 1, Map.of())); + + ByteArrayInputStream in = new ByteArrayInputStream(data); + long[] consumedAtFirst = {-1}; + List fields = new ArrayList<>(); + + FeedStreamer.stream(in, (fi, v) -> { + if (consumedAtFirst[0] < 0) { + consumedAtFirst[0] = data.length - in.available(); + } + fields.add(fi.name()); + return true; + }); + + // The first field (Name) must be delivered after consuming only a small + // prefix of the stream -- proof it reads incrementally rather than + // loading the whole payload first. + check(consumedAtFirst[0] > 0 && consumedAtFirst[0] < data.length / 4, + "first field delivered after consuming " + consumedAtFirst[0] + " of " + data.length + " bytes"); + check(fields.get(0).equals("Name"), "first field=" + fields.get(0)); + check(Collections.frequency(fields, "Tags") == 1000, "tag count=" + Collections.frequency(fields, "Tags")); + + System.out.println("OK consumedAtFirst=" + consumedAtFirst[0] + " total=" + data.length); + } +} +` + checkJava(t) + + buildAndRunJavaTest(t, "streamfeed", &javaSource{ + FileName: "IncrementalMain", + Source: incrementalHarness, + }) +} + +// TestPullStream_Adapter exercises the virtual-thread pull adapter over the push +// streamer: full for-each iteration, the Stream() API, and early close. +func TestPullStream_Adapter(t *testing.T) { + const pullHarness = `import com.opencost.streamfeed.Feed; +import com.opencost.streamfeed.FeedEncoder; +import com.opencost.streamfeed.FeedStreamer; +import com.bingen.BingenElement; +import com.bingen.BingenPullStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class PullMain { + static void check(boolean ok, String what) { + if (!ok) { + System.err.println("FAIL: " + what); + System.exit(1); + } + } + + public static void main(String[] args) { + byte[] data = FeedEncoder.toBytes(new Feed("news", List.of("a", "b", "c"), 7, Map.of("k", "v"))); + + // Full pull iteration via for-each. + List fields = new ArrayList<>(); + try (BingenPullStream pull = BingenPullStream.of(data, FeedStreamer::stream)) { + for (BingenElement e : pull) { + fields.add(e.field().name()); + } + } + check(fields.equals(List.of("Name", "Tags", "Tags", "Tags", "Count", "Meta")), "fields=" + fields); + + // Stream() API, collecting the flattened Tags element values. + List tags = new ArrayList<>(); + try (BingenPullStream pull = BingenPullStream.of(data, FeedStreamer::stream)) { + pull.stream() + .filter(e -> e.field().name().equals("Tags")) + .forEach(e -> tags.add(e.value().value())); + } + check(tags.equals(List.of("a", "b", "c")), "tags=" + tags); + + // Early close via break must not hang (producer virtual thread interrupted). + List partial = new ArrayList<>(); + try (BingenPullStream pull = BingenPullStream.of(data, FeedStreamer::stream)) { + for (BingenElement e : pull) { + partial.add(e.field().name()); + if (partial.size() == 2) { + break; + } + } + } + check(partial.size() == 2, "partial=" + partial); + + System.out.println("OK"); + } +} +` + const goPackage = "streamfeed" + const harnessName = "PullMain" + + checkJava(t) + + buildAndRunJavaTest(t, goPackage, &javaSource{ + FileName: harnessName, + Source: pullHarness, + }) +} diff --git a/internal/generator/java/templates.go b/internal/generator/java/templates.go new file mode 100644 index 0000000..1d9cfbd --- /dev/null +++ b/internal/generator/java/templates.go @@ -0,0 +1,130 @@ +package java + +import ( + "embed" + "fmt" + "io" + "text/template" + + "github.com/opencost/bingen/internal/types" +) + +// Template file names emitted by the java exporter. Additional per-type and +// runtime templates are added as the exporter is filled in. +const ( + // PackageInfoTemplate is the package-info.java placeholder emitted for every + // generated package. + PackageInfoTemplate = "package-info.java.tmpl" + + // RecordTemplate is the immutable record + builder emitted per struct type. + RecordTemplate = "record.java.tmpl" + + // EncoderTemplate is the BinEncoder implementation emitted per struct type. + EncoderTemplate = "encoder.java.tmpl" + + // DecoderTemplate is the BinDecoder implementation emitted per struct type. + DecoderTemplate = "decoder.java.tmpl" + + // StreamerTemplate is the push streamer emitted per streamable struct type. + StreamerTemplate = "streamer.java.tmpl" + + // InterfaceTemplate is the empty marker interface emitted per go interface. + InterfaceTemplate = "interface.java.tmpl" + + // RegistryTemplate is the wire-string -> codec dispatch table. + RegistryTemplate = "registry.java.tmpl" +) + +// InterfaceParams is the template data for a generated marker interface. +type InterfaceParams struct { + Package string + Name string +} + +// RegistryEntry registers one concrete type keyed by its go wire string. +type RegistryEntry struct { + Wire string + Type string +} + +// RegistryParams is the template data for the generated TypeRegistry. +type RegistryParams struct { + Package string + RuntimePackage string + Entries []RegistryEntry +} + +// RecordParams is the template data for a generated record. +type RecordParams struct { + Package string + Imports []string + ImplementsClause string + Type *types.StructType +} + +// CodecParams is the template data for a generated encoder or decoder. +type CodecParams struct { + Package string + RuntimePackage string + Imports []string + Version uint8 + StringTable bool + PreProcess bool + PostProcess bool + Migration bool + Body string + Type *types.StructType +} + +// runtimeTemplates maps each shared-runtime output file name to the template +// that produces it. These are emitted into the runtime package on every run. +var runtimeTemplates = map[string]string{ + "ReadBuffer.java": "ReadBuffer.java.tmpl", + "WriteBuffer.java": "WriteBuffer.java.tmpl", + "BinEncoder.java": "BinEncoder.java.tmpl", + "EncodingContext.java": "EncodingContext.java.tmpl", + "BinDecoder.java": "BinDecoder.java.tmpl", + "DecodingContext.java": "DecodingContext.java.tmpl", + "StringTableWriter.java": "StringTableWriter.java.tmpl", + "StringTableReader.java": "StringTableReader.java.tmpl", + "GoTime.java": "GoTime.java.tmpl", + "BingenFieldInfo.java": "BingenFieldInfo.java.tmpl", + "BingenValue.java": "BingenValue.java.tmpl", + "BingenConsumer.java": "BingenConsumer.java.tmpl", + "BingenStreamFn.java": "BingenStreamFn.java.tmpl", + "BingenElement.java": "BingenElement.java.tmpl", + "BingenStreamException.java": "BingenStreamException.java.tmpl", + "BingenPullStream.java": "BingenPullStream.java.tmpl", +} + +// RuntimeParams is the template data for the shared-runtime templates. +type RuntimeParams struct { + RuntimePackage string +} + +//go:embed templates/java/*.tmpl +var javaTemplatesFS embed.FS + +// javaTemplates holds all parsed java templates. +var javaTemplates *template.Template + +func init() { + var err error + javaTemplates = template.New("java-bingen-templates").Funcs(template.FuncMap{ + "JavaType": JavaType, + "JavaFieldName": JavaFieldName, + }) + javaTemplates, err = javaTemplates.ParseFS(javaTemplatesFS, "templates/java/*.tmpl") + if err != nil { + panic(err) + } +} + +// writeTemplate executes the named template with the provided data into the +// writer. +func writeTemplate(writer io.Writer, name string, data any) error { + if err := javaTemplates.ExecuteTemplate(writer, name, data); err != nil { + return fmt.Errorf("executing template %q: %w", name, err) + } + return nil +} diff --git a/internal/generator/java/templates/java/BinDecoder.java.tmpl b/internal/generator/java/templates/java/BinDecoder.java.tmpl new file mode 100644 index 0000000..4ee1014 --- /dev/null +++ b/internal/generator/java/templates/java/BinDecoder.java.tmpl @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Decodes a value of type {@code T} from a {@link DecodingContext}. + */ +public interface BinDecoder { + T decode(DecodingContext ctx); +} diff --git a/internal/generator/java/templates/java/BinEncoder.java.tmpl b/internal/generator/java/templates/java/BinEncoder.java.tmpl new file mode 100644 index 0000000..44e5193 --- /dev/null +++ b/internal/generator/java/templates/java/BinEncoder.java.tmpl @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Encodes a value of type {@code T} into an {@link EncodingContext}. + */ +public interface BinEncoder { + void encode(T value, EncodingContext ctx); +} diff --git a/internal/generator/java/templates/java/BingenConsumer.java.tmpl b/internal/generator/java/templates/java/BingenConsumer.java.tmpl new file mode 100644 index 0000000..435d614 --- /dev/null +++ b/internal/generator/java/templates/java/BingenConsumer.java.tmpl @@ -0,0 +1,19 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Receives each streamed field (and each flattened collection element). Return + * {@code false} to stop streaming early, mirroring go's yield contract. A null + * {@link BingenValue} indicates a nil field value. + */ +@FunctionalInterface +public interface BingenConsumer { + boolean accept(BingenFieldInfo field, BingenValue value); +} diff --git a/internal/generator/java/templates/java/BingenElement.java.tmpl b/internal/generator/java/templates/java/BingenElement.java.tmpl new file mode 100644 index 0000000..cea955a --- /dev/null +++ b/internal/generator/java/templates/java/BingenElement.java.tmpl @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * One pulled stream element: the field it belongs to and its value (which is + * null for a nil field, and carries an index/key for flattened collections). + */ +public record BingenElement(BingenFieldInfo field, BingenValue value) { +} diff --git a/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl b/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl new file mode 100644 index 0000000..391e6aa --- /dev/null +++ b/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl @@ -0,0 +1,15 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Describes the struct field currently being streamed. + */ +public record BingenFieldInfo(String name) { +} diff --git a/internal/generator/java/templates/java/BingenPullStream.java.tmpl b/internal/generator/java/templates/java/BingenPullStream.java.tmpl new file mode 100644 index 0000000..1113325 --- /dev/null +++ b/internal/generator/java/templates/java/BingenPullStream.java.tmpl @@ -0,0 +1,153 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.concurrent.SynchronousQueue; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * Adapts a push streamer ({@code Streamer::stream}) into a pull + * {@link Iterable}/{@link Stream} of {@link BingenElement}. The push streamer + * runs on a virtual thread and hands each element across a {@link + * SynchronousQueue}, so exactly one element is in flight — the producer blocks + * until the consumer pulls, matching go's cooperative streaming. + * + *

Single use. Always close it (try-with-resources) if you do not iterate to + * the end, otherwise the producer virtual thread is left parked. + */ +public final class BingenPullStream implements Iterable, AutoCloseable { + + private static final Object DONE = new Object(); + private static final Object FAIL = new Object(); + + private final SynchronousQueue queue = new SynchronousQueue<>(); + private volatile boolean closed; + private volatile Throwable error; + private final Thread producer; + + private BingenPullStream(InputStream in, BingenStreamFn fn) { + this.producer = Thread.ofVirtual().name("bingen-pull-stream").start(() -> run(in, fn)); + } + + /** + * Creates a pull stream driving the push streamer over an in-memory payload. + */ + public static BingenPullStream of(byte[] data, BingenStreamFn fn) { + return new BingenPullStream(new ByteArrayInputStream(data), fn); + } + + /** + * Creates a pull stream driving the push streamer over a stream read + * incrementally (socket, file, ...). The caller retains ownership of the + * stream. + */ + public static BingenPullStream of(InputStream in, BingenStreamFn fn) { + return new BingenPullStream(in, fn); + } + + private void run(InputStream in, BingenStreamFn fn) { + try { + fn.stream(in, (fi, value) -> { + if (closed) { + return false; + } + try { + queue.put(new BingenElement(fi, value)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + return !closed; + }); + if (!closed) { + queue.put(DONE); + } + } catch (InterruptedException e) { + // interrupted during the terminal handoff while closing; nothing to do. + } catch (Throwable t) { + error = t; + if (!closed) { + try { + queue.put(FAIL); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + } + } + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + private BingenElement next; + private boolean done; + + @Override + public boolean hasNext() { + if (done) { + return false; + } + if (next != null) { + return true; + } + Object msg; + try { + msg = queue.take(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + done = true; + return false; + } + if (msg == DONE) { + done = true; + return false; + } + if (msg == FAIL) { + done = true; + throw new BingenStreamException(error); + } + next = (BingenElement) msg; + return true; + } + + @Override + public BingenElement next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + BingenElement element = next; + next = null; + return element; + } + }; + } + + /** + * A sequential {@link Stream}; closing it closes this pull stream. + */ + public Stream stream() { + Spliterator spliterator = + Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED); + + return StreamSupport.stream(spliterator, false).onClose(this::close); + } + + @Override + public void close() { + closed = true; + producer.interrupt(); + } +} diff --git a/internal/generator/java/templates/java/BingenStreamException.java.tmpl b/internal/generator/java/templates/java/BingenStreamException.java.tmpl new file mode 100644 index 0000000..bed8f94 --- /dev/null +++ b/internal/generator/java/templates/java/BingenStreamException.java.tmpl @@ -0,0 +1,18 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Wraps an error thrown by the underlying push streamer during pull iteration. + */ +public final class BingenStreamException extends RuntimeException { + public BingenStreamException(Throwable cause) { + super(cause); + } +} diff --git a/internal/generator/java/templates/java/BingenStreamFn.java.tmpl b/internal/generator/java/templates/java/BingenStreamFn.java.tmpl new file mode 100644 index 0000000..d534ce9 --- /dev/null +++ b/internal/generator/java/templates/java/BingenStreamFn.java.tmpl @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.io.InputStream; + +/** + * A generated {@code Streamer.stream(InputStream, BingenConsumer)} entry + * point, so a push streamer can be adapted into a pull stream (see {@link + * BingenPullStream}). + */ +@FunctionalInterface +public interface BingenStreamFn { + void stream(InputStream in, BingenConsumer consumer); +} diff --git a/internal/generator/java/templates/java/BingenValue.java.tmpl b/internal/generator/java/templates/java/BingenValue.java.tmpl new file mode 100644 index 0000000..44e5841 --- /dev/null +++ b/internal/generator/java/templates/java/BingenValue.java.tmpl @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * A streamed value, optionally carrying the index or key it had within a + * flattened collection. + */ +public record BingenValue(Object value, Object index) { + + /** + * A single value with no index or key. + */ + public static BingenValue single(Object value) { + return new BingenValue(value, null); + } + + /** + * One element of a flattened slice or map, with its index or key. + */ + public static BingenValue pair(Object index, Object value) { + return new BingenValue(value, index); + } +} diff --git a/internal/generator/java/templates/java/DecodingContext.java.tmpl b/internal/generator/java/templates/java/DecodingContext.java.tmpl new file mode 100644 index 0000000..7e2e794 --- /dev/null +++ b/internal/generator/java/templates/java/DecodingContext.java.tmpl @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.io.InputStream; + +/** + * Carries the read buffer and optional string table shared across a single + * decode or stream pass. + */ +public final class DecodingContext { + + private static final byte[] STRING_TABLE_TAG = {'B', 'G', 'S', 'T'}; + + private final ReadBuffer buffer; + private final StringTableReader table; + + private DecodingContext(ReadBuffer buffer, StringTableReader table) { + this.buffer = buffer; + this.table = table; + } + + /** + * Creates a context over an in-memory payload. + */ + public static DecodingContext fromBytes(byte[] data) { + return from(ReadBuffer.fromBytes(data)); + } + + /** + * Creates a context that consumes the stream incrementally (socket, file, + * etc). The caller retains ownership of the stream. + */ + public static DecodingContext fromStream(InputStream in) { + return from(ReadBuffer.fromStream(in)); + } + + // When the payload begins with the BGST tag, the string table is loaded + // first and the buffer is left positioned at the value payload. + private static DecodingContext from(ReadBuffer buffer) { + StringTableReader table = null; + if (buffer.startsWith(STRING_TABLE_TAG)) { + buffer.readBytes(STRING_TABLE_TAG.length); // strip the tag + table = StringTableReader.from(buffer); + } + return new DecodingContext(buffer, table); + } + + /** + * The read buffer the decoders consume from. + */ + public ReadBuffer buffer() { + return buffer; + } + + /** + * The string table, or null when string-table decoding is inactive. + */ + public StringTableReader table() { + return table; + } + + /** + * Whether string-table decoding is active. + */ + public boolean isStringTable() { + return table != null && table.len() > 0; + } +} diff --git a/internal/generator/java/templates/java/EncodingContext.java.tmpl b/internal/generator/java/templates/java/EncodingContext.java.tmpl new file mode 100644 index 0000000..eb65c67 --- /dev/null +++ b/internal/generator/java/templates/java/EncodingContext.java.tmpl @@ -0,0 +1,74 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Carries the write buffer and optional string table shared across a single + * encode pass. + */ +public final class EncodingContext { + + private final WriteBuffer buffer; + private final StringTableWriter table; + + private EncodingContext(WriteBuffer buffer, StringTableWriter table) { + this.buffer = buffer; + this.table = table; + } + + /** + * Creates a context backed by a fresh write buffer with no string table. + */ + public static EncodingContext create() { + return new EncodingContext(WriteBuffer.create(), null); + } + + /** + * Creates a context whose string fields are indexed into a string table. + */ + public static EncodingContext withStringTable() { + return new EncodingContext(WriteBuffer.create(), new StringTableWriter()); + } + + /** + * The write buffer the encoders emit into. + */ + public WriteBuffer buffer() { + return buffer; + } + + /** + * The string table, or null when string-table encoding is inactive. + */ + public StringTableWriter table() { + return table; + } + + /** + * Whether string-table encoding is active. + */ + public boolean isStringTable() { + return table != null; + } + + /** + * Returns the fully-encoded payload. When a string table is active, it is + * written (with its tag) ahead of the payload. + */ + public byte[] toBytes() { + byte[] payload = buffer.bytes(); + if (table == null) { + return payload; + } + WriteBuffer out = WriteBuffer.create(); + table.writeTo(out); + out.writeBytes(payload); + return out.bytes(); + } +} diff --git a/internal/generator/java/templates/java/GoTime.java.tmpl b/internal/generator/java/templates/java/GoTime.java.tmpl new file mode 100644 index 0000000..044e5e0 --- /dev/null +++ b/internal/generator/java/templates/java/GoTime.java.tmpl @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +/** + * Encodes/decodes a go {@code time.Time} the way bingen wraps it: a length + * prefix (little-endian, via the buffers) followed by the payload of go's own + * {@code time.Time.MarshalBinary}, which is big-endian. + * + *

The payload preserves the instant and the zone offset (not a named zone), + * so it maps to {@link OffsetDateTime}. A zero offset is written as go's UTC + * sentinel (-1 minutes); a genuine fixed +00:00 zone that is not UTC is the only + * value that will not re-encode byte-for-byte, and its instant is still exact. + */ +public final class GoTime { + + // Seconds between Jan 1, year 1 (go's absolute epoch) and the unix epoch. + private static final long UNIX_TO_INTERNAL = 62135596800L; + + private GoTime() { + } + + /** Writes the length-prefixed go time payload. */ + public static void encode(OffsetDateTime t, WriteBuffer buff) { + byte[] payload = marshal(t); + buff.writeInt(payload.length); + buff.writeBytes(payload); + } + + /** Reads a length-prefixed go time payload. */ + public static OffsetDateTime decode(ReadBuffer buff) { + int len = buff.readInt(); + return unmarshal(buff.readBytes(len)); + } + + static byte[] marshal(OffsetDateTime t) { + Instant instant = t.toInstant(); + long sec = instant.getEpochSecond() + UNIX_TO_INTERNAL; + int nsec = instant.getNano(); + int offset = t.getOffset().getTotalSeconds(); + + int version = 1; + int offsetSec = 0; + int offsetMin; + if (offset == 0) { + offsetMin = -1; // UTC sentinel + } else { + if (offset % 60 != 0) { + version = 2; + offsetSec = offset % 60; + } + offsetMin = offset / 60; + } + + byte[] enc = new byte[version == 2 ? 16 : 15]; + enc[0] = (byte) version; + putLongBE(enc, 1, sec); + putIntBE(enc, 9, nsec); + putShortBE(enc, 13, offsetMin); + if (version == 2) { + enc[15] = (byte) offsetSec; + } + return enc; + } + + static OffsetDateTime unmarshal(byte[] b) { + int version = b[0]; + if (version != 1 && version != 2) { + throw new IllegalArgumentException("GoTime: unsupported version " + version); + } + long sec = getLongBE(b, 1); + int nsec = getIntBE(b, 9); + int offsetMin = getShortBE(b, 13); + + ZoneOffset zone; + if (offsetMin == -1) { + zone = ZoneOffset.UTC; + } else { + int total = offsetMin * 60; + if (version == 2) { + total += b[15]; // signed sub-minute seconds + } + zone = ZoneOffset.ofTotalSeconds(total); + } + + return Instant.ofEpochSecond(sec - UNIX_TO_INTERNAL, nsec).atOffset(zone); + } + + //-------------------------------------------------------------------------- + // Big Endian Helpers + //-------------------------------------------------------------------------- + + private static void putLongBE(byte[] b, int off, long v) { + for (int i = 0; i < 8; i++) { + b[off + i] = (byte) (v >>> (56 - 8 * i)); + } + } + + private static long getLongBE(byte[] b, int off) { + long v = 0; + for (int i = 0; i < 8; i++) { + v = (v << 8) | (b[off + i] & 0xFFL); + } + return v; + } + + private static void putIntBE(byte[] b, int off, int v) { + b[off] = (byte) (v >>> 24); + b[off + 1] = (byte) (v >>> 16); + b[off + 2] = (byte) (v >>> 8); + b[off + 3] = (byte) v; + } + + private static int getIntBE(byte[] b, int off) { + return ((b[off] & 0xFF) << 24) + | ((b[off + 1] & 0xFF) << 16) + | ((b[off + 2] & 0xFF) << 8) + | (b[off + 3] & 0xFF); + } + + private static void putShortBE(byte[] b, int off, int v) { + b[off] = (byte) (v >>> 8); + b[off + 1] = (byte) v; + } + + private static int getShortBE(byte[] b, int off) { + return (short) (((b[off] & 0xFF) << 8) | (b[off + 1] & 0xFF)); + } +} diff --git a/internal/generator/java/templates/java/ReadBuffer.java.tmpl b/internal/generator/java/templates/java/ReadBuffer.java.tmpl new file mode 100644 index 0000000..dcaa784 --- /dev/null +++ b/internal/generator/java/templates/java/ReadBuffer.java.tmpl @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.BufferUnderflowException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/** + * Little-endian binary read buffer over an {@link InputStream}. Backing the + * buffer with a stream (rather than a byte array) is what lets decoders and + * streamers consume data incrementally from a socket or file. + * + *

Not thread-safe. + */ +public final class ReadBuffer { + + private final InputStream in; + + private ReadBuffer(InputStream in) { + this.in = in; + } + + /** + * Creates a read buffer that takes ownership of the provided byte array. + * The caller must not modify the array after this call. + */ + public static ReadBuffer fromBytes(byte[] bytes) { + return new ReadBuffer(new ByteArrayInputStream(bytes)); + } + + /** + * Creates a read buffer that consumes the stream incrementally. The stream is + * wrapped so it supports the small look-ahead used for header detection; the + * caller retains ownership and is responsible for closing it. + */ + public static ReadBuffer fromStream(InputStream stream) { + InputStream in = stream.markSupported() ? stream : new BufferedInputStream(stream); + return new ReadBuffer(in); + } + + /** + * Creates a read buffer from all bytes written to the given {@link WriteBuffer}. + */ + public static ReadBuffer from(WriteBuffer wb) { + return fromBytes(wb.bytes()); + } + + // ------------------------------------------------------------------------- + // Read API + // ------------------------------------------------------------------------- + + public boolean readBool() { + return readRawByte() != 0; + } + + /** Reads a 32-bit signed integer (same as readInt32). */ + public int readInt() { + return readInt32(); + } + + public byte readInt8() { + return readRawByte(); + } + + public short readInt16() { + byte b0 = readRawByte(); + byte b1 = readRawByte(); + return (short) ((b0 & 0xFF) | ((b1 & 0xFF) << 8)); + } + + public int readInt32() { + byte b0 = readRawByte(); + byte b1 = readRawByte(); + byte b2 = readRawByte(); + byte b3 = readRawByte(); + return (b0 & 0xFF) | ((b1 & 0xFF) << 8) | ((b2 & 0xFF) << 16) | ((b3 & 0xFF) << 24); + } + + public long readInt64() { + byte b0 = readRawByte(); + byte b1 = readRawByte(); + byte b2 = readRawByte(); + byte b3 = readRawByte(); + byte b4 = readRawByte(); + byte b5 = readRawByte(); + byte b6 = readRawByte(); + byte b7 = readRawByte(); + return (b0 & 0xFFL) + | ((b1 & 0xFFL) << 8) + | ((b2 & 0xFFL) << 16) + | ((b3 & 0xFFL) << 24) + | ((b4 & 0xFFL) << 32) + | ((b5 & 0xFFL) << 40) + | ((b6 & 0xFFL) << 48) + | ((b7 & 0xFFL) << 56); + } + + /** + * Reads a 32-bit unsigned value, returned as a long. + */ + public long readUInt() { + return readInt32() & 0xFFFFFFFFL; + } + + /** + * Reads an 8-bit unsigned value (0–255), returned as int. + */ + public int readUInt8() { + return readRawByte() & 0xFF; + } + + /** + * Reads a 16-bit unsigned value (0–65535), returned as int. + */ + public int readUInt16() { + return readInt16() & 0xFFFF; + } + + /** + * Reads a 32-bit unsigned value (0–4294967295), returned as long. + */ + public long readUInt32() { + return readInt32() & 0xFFFFFFFFL; + } + + /** + * Reads a 64-bit unsigned value (same bit pattern as signed long). + */ + public long readUInt64() { + return readInt64(); + } + + /** + * Reads a 32-bit floating point value (IEEE 754). + */ + public float readFloat32() { + return Float.intBitsToFloat(readInt32()); + } + + /** + * Reads a 64-bit floating point value (IEEE 754). + */ + public double readFloat64() { + return Double.longBitsToDouble(readInt64()); + } + + /** + * Reads a uint16 length prefix, then reads exactly that many UTF-8 bytes and + * returns the decoded string. + */ + public String readString() { + int len = readUInt16(); + byte[] strBytes = readBytes(len); + return new String(strBytes, StandardCharsets.UTF_8); + } + + /** + * Reads exactly {@code length} bytes from the buffer. + */ + public byte[] readBytes(int length) { + byte[] result = new byte[length]; + int remaining = length; + int pos = 0; + while (remaining > 0) { + int n; + try { + n = in.read(result, pos, remaining); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + if (n < 0) { + throw new BufferUnderflowException(); + } + pos += n; + remaining -= n; + } + return result; + } + + /** + * Returns true if the next bytes match {@code tag} without consuming them. + * Used to detect the optional string-table header. + */ + public boolean startsWith(byte[] tag) { + try { + in.mark(tag.length); + byte[] head = new byte[tag.length]; + int pos = 0; + while (pos < tag.length) { + int n = in.read(head, pos, tag.length - pos); + if (n < 0) { + break; + } + pos += n; + } + in.reset(); + return pos == tag.length && Arrays.equals(head, tag); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + // ------------------------------------------------------------------------- + // Internal helpers + // ------------------------------------------------------------------------- + + private byte readRawByte() { + int b; + try { + b = in.read(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + if (b < 0) { + throw new BufferUnderflowException(); + } + return (byte) b; + } +} diff --git a/internal/generator/java/templates/java/StringTableReader.java.tmpl b/internal/generator/java/templates/java/StringTableReader.java.tmpl new file mode 100644 index 0000000..df3b89f --- /dev/null +++ b/internal/generator/java/templates/java/StringTableReader.java.tmpl @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +/** + * Pre-loaded string table providing index-based lookup, mirroring the go + * slice-backed reader. + */ +public final class StringTableReader { + + private final String[] table; + + private StringTableReader(String[] table) { + this.table = table; + } + + /** + * Reads the string count followed by that many strings from the buffer, + * which must be positioned immediately after the {@code BGST} tag. + */ + public static StringTableReader from(ReadBuffer buff) { + int count = buff.readInt(); + String[] table = new String[count]; + for (int i = 0; i < count; i++) { + table[i] = buff.readString(); + } + return new StringTableReader(table); + } + + /** + * Returns the string at {@code index}. + */ + public String at(int index) { + return table[index]; + } + + /** + * Returns the number of strings in the table. + */ + public int len() { + return table.length; + } +} diff --git a/internal/generator/java/templates/java/StringTableWriter.java.tmpl b/internal/generator/java/templates/java/StringTableWriter.java.tmpl new file mode 100644 index 0000000..e199f1e --- /dev/null +++ b/internal/generator/java/templates/java/StringTableWriter.java.tmpl @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Assigns each distinct string an insertion-ordered index and writes the table, + * prefixed with the {@code BGST} tag, ahead of the payload. + */ +public final class StringTableWriter { + + private static final byte[] TAG = {'B', 'G', 'S', 'T'}; + + private final Map indices = new LinkedHashMap<>(); + private int next = 0; + + /** + * Returns the existing index for {@code s}, or assigns and returns a new one. + */ + public int addOrGet(String s) { + Integer existing = indices.get(s); + if (existing != null) { + return existing; + } + int current = next++; + indices.put(s, current); + return current; + } + + /** + * Writes the tag, the string count, and each string in index order. + */ + public void writeTo(WriteBuffer buff) { + buff.writeBytes(TAG); + + String[] ordered = new String[next]; + for (Map.Entry entry : indices.entrySet()) { + ordered[entry.getValue()] = entry.getKey(); + } + + buff.writeInt(ordered.length); + for (String s : ordered) { + buff.writeString(s); + } + } +} diff --git a/internal/generator/java/templates/java/WriteBuffer.java.tmpl b/internal/generator/java/templates/java/WriteBuffer.java.tmpl new file mode 100644 index 0000000..e5c7327 --- /dev/null +++ b/internal/generator/java/templates/java/WriteBuffer.java.tmpl @@ -0,0 +1,169 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .RuntimePackage }}; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; + +/** + * Little-endian binary write buffer backed by a {@link ByteArrayOutputStream}. + * + *

Not thread-safe. + */ +public final class WriteBuffer { + private static final int MAX_STRING_BYTES = 0xFFFF; + + private final ByteArrayOutputStream bos; + + private WriteBuffer() { + this.bos = new ByteArrayOutputStream(64); + } + + /** + * Creates a new empty write buffer. + */ + public static WriteBuffer create() { + return new WriteBuffer(); + } + + // ------------------------------------------------------------------------- + // Write API + // ------------------------------------------------------------------------- + + /** + * Writes a boolean as a single byte (0 or 1). + */ + public void writeBool(boolean v) { + bos.write(v ? 1 : 0); + } + + /** + * Writes a 32-bit signed integer (same as writeInt32). + */ + public void writeInt(int v) { + writeInt32(v); + } + + /** + * Writes a single byte + */ + public void writeInt8(byte v) { + bos.write(v); + } + + /** + * Writes a 16-bit signed integer + */ + public void writeInt16(short v) { + bos.write(v & 0xFF); + bos.write((v >>> 8) & 0xFF); + } + + /** + * Writes a 32-bit signed integer + */ + public void writeInt32(int v) { + bos.write(v & 0xFF); + bos.write((v >>> 8) & 0xFF); + bos.write((v >>> 16) & 0xFF); + bos.write((v >>> 24) & 0xFF); + } + + /** + * Writes a 64-bit signed integer + */ + public void writeInt64(long v) { + bos.write((int) (v & 0xFF)); + bos.write((int) ((v >>> 8) & 0xFF)); + bos.write((int) ((v >>> 16) & 0xFF)); + bos.write((int) ((v >>> 24) & 0xFF)); + bos.write((int) ((v >>> 32) & 0xFF)); + bos.write((int) ((v >>> 40) & 0xFF)); + bos.write((int) ((v >>> 48) & 0xFF)); + bos.write((int) ((v >>> 56) & 0xFF)); + } + + /** + * Writes a 32-bit unsigned value (accepts long to cover full 0–4294967295 range). + */ + public void writeUInt(long v) { + writeInt32((int) (v & 0xFFFFFFFFL)); + } + + /** + * Writes an 8-bit unsigned value (0–255). + */ + public void writeUInt8(int v) { + bos.write(v); + } + + /** + * Writes a 16-bit unsigned value (0–65535). + */ + public void writeUInt16(int v) { + writeInt16((short) (v & 0xFFFF)); + } + + /** + * Writes a 32-bit unsigned value. + */ + public void writeUInt32(long v) { + writeInt32((int) (v & 0xFFFFFFFFL)); + } + + /** + * Writes a 64-bit unsigned value (same bit pattern as signed long). + */ + public void writeUInt64(long v) { + writeInt64(v); + } + + /** + * Writes a 32-bit float. + */ + public void writeFloat32(float v) { + writeInt32(Float.floatToRawIntBits(v)); + } + + /** + * Writes a 64-bit float. + */ + public void writeFloat64(double v) { + writeInt64(Double.doubleToRawLongBits(v)); + } + + /** + * Writes the string as a uint16 length prefix followed by UTF-8 bytes. + * Strings longer than 65535 bytes are silently truncated at the byte boundary. + */ + public void writeString(String s) { + byte[] strBytes = s.getBytes(StandardCharsets.UTF_8); + int len = Math.min(strBytes.length, MAX_STRING_BYTES); + writeUInt16(len); + bos.write(strBytes, 0, len); + } + + /** + * Writes the raw byte array contents into the buffer. + */ + public void writeBytes(byte[] bytes) { + bos.write(bytes, 0, bytes.length); + } + + // ------------------------------------------------------------------------- + // Utility + // ------------------------------------------------------------------------- + + /** + * Returns a copy of all bytes written so far. + */ + public byte[] bytes() { + return bos.toByteArray(); + } +} diff --git a/internal/generator/java/templates/java/decoder.java.tmpl b/internal/generator/java/templates/java/decoder.java.tmpl new file mode 100644 index 0000000..c9523e0 --- /dev/null +++ b/internal/generator/java/templates/java/decoder.java.tmpl @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .Package }}; + +import {{ .RuntimePackage }}.BinDecoder; +import {{ .RuntimePackage }}.DecodingContext; +import {{ .RuntimePackage }}.ReadBuffer; +import java.io.InputStream; +{{- range .Imports }} +import {{ . }}; +{{- end }} + +/** + * Generated binary decoder for {@link {{ .Type.Name }}}. + */ +public final class {{ .Type.Name }}Decoder implements BinDecoder<{{ .Type.Name }}> { + + public static final {{ .Type.Name }}Decoder INSTANCE = new {{ .Type.Name }}Decoder(); + + private static final int VERSION = {{ .Version }}; + + /** + * Decodes a {@link {{ .Type.Name }}} from a standalone byte array. + */ + public static {{ .Type.Name }} fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** + * Decodes a {@link {{ .Type.Name }}} read incrementally from a stream. + */ + public static {{ .Type.Name }} fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public {{ .Type.Name }} decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding {{ .Type.Name }}: expected " + VERSION + " or less, got " + version); + } + + {{ .Type.Name }}.Builder builder = {{ .Type.Name }}.builder(); +{{ .Body }} + {{ .Type.Name }} result = builder.build(); +{{- if .Migration }} + if (version != VERSION) { + result = {{ .Type.Name }}Hooks.migrate(result, version, VERSION); + } +{{- end }} +{{- if .PostProcess }} + result = {{ .Type.Name }}Hooks.postProcess(result); +{{- end }} + return result; + } +} diff --git a/internal/generator/java/templates/java/encoder.java.tmpl b/internal/generator/java/templates/java/encoder.java.tmpl new file mode 100644 index 0000000..e476a13 --- /dev/null +++ b/internal/generator/java/templates/java/encoder.java.tmpl @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .Package }}; + +import {{ .RuntimePackage }}.BinEncoder; +import {{ .RuntimePackage }}.EncodingContext; +import {{ .RuntimePackage }}.WriteBuffer; +{{- range .Imports }} +import {{ . }}; +{{- end }} + +/** + * Generated binary encoder for {@link {{ .Type.Name }}}. + */ +public final class {{ .Type.Name }}Encoder implements BinEncoder<{{ .Type.Name }}> { + + public static final {{ .Type.Name }}Encoder INSTANCE = new {{ .Type.Name }}Encoder(); + + private static final int VERSION = {{ .Version }}; + private static final boolean STRING_TABLE = {{ .StringTable }}; + + /** + * Encodes {@code value} to a standalone byte array. + */ + public static byte[] toBytes({{ .Type.Name }} value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode({{ .Type.Name }} value, EncodingContext ctx) { +{{- if .PreProcess }} + value = {{ .Type.Name }}Hooks.preProcess(value); +{{- end }} + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version +{{ .Body }} + } +} diff --git a/internal/generator/java/templates/java/interface.java.tmpl b/internal/generator/java/templates/java/interface.java.tmpl new file mode 100644 index 0000000..df99d8f --- /dev/null +++ b/internal/generator/java/templates/java/interface.java.tmpl @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .Package }}; + +/** + * Marker interface for the {@code {{ .Name }}} go interface. Concrete + * implementations are dispatched by the generated {@code TypeRegistry}. + */ +public interface {{ .Name }} { +} diff --git a/internal/generator/java/templates/java/package-info.java.tmpl b/internal/generator/java/templates/java/package-info.java.tmpl new file mode 100644 index 0000000..11f3b47 --- /dev/null +++ b/internal/generator/java/templates/java/package-info.java.tmpl @@ -0,0 +1,12 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Binary codecs generated by bingen for the {@code {{ .GoPackage }}} go package. + */ +package {{ .JavaPackage }}; diff --git a/internal/generator/java/templates/java/record.java.tmpl b/internal/generator/java/templates/java/record.java.tmpl new file mode 100644 index 0000000..e7fc558 --- /dev/null +++ b/internal/generator/java/templates/java/record.java.tmpl @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .Package }}; +{{ range .Imports }} +import {{ . }}; +{{- end }} + +/** + * Generated data type for the {@code {{ .Type.Name }}} go struct. + */ +public record {{ .Type.Name }}({{ range $i, $f := .Type.Fields }}{{ if $i }}, {{ end }}{{ JavaType $f.Type }} {{ JavaFieldName $f.Name }}{{ end }}){{ .ImplementsClause }} { + + /** + * Creates a new builder for {@link {{ .Type.Name }}}. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ + public static final class Builder { +{{- range .Type.Fields }} + private {{ JavaType .Type }} {{ JavaFieldName .Name }}; +{{- end }} + +{{- range .Type.Fields }} + public Builder {{ JavaFieldName .Name }}({{ JavaType .Type }} {{ JavaFieldName .Name }}) { + this.{{ JavaFieldName .Name }} = {{ JavaFieldName .Name }}; + return this; + } +{{- end }} + + public {{ .Type.Name }} build() { + return new {{ .Type.Name }}({{ range $i, $f := .Type.Fields }}{{ if $i }}, {{ end }}{{ JavaFieldName $f.Name }}{{ end }}); + } + } +} diff --git a/internal/generator/java/templates/java/registry.java.tmpl b/internal/generator/java/templates/java/registry.java.tmpl new file mode 100644 index 0000000..6c92a0e --- /dev/null +++ b/internal/generator/java/templates/java/registry.java.tmpl @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .Package }}; + +import {{ .RuntimePackage }}.BinDecoder; +import {{ .RuntimePackage }}.BinEncoder; +import {{ .RuntimePackage }}.DecodingContext; +import {{ .RuntimePackage }}.EncodingContext; +import java.util.HashMap; +import java.util.Map; + +/** + * Maps go wire type strings to the generated codecs for interface dispatch, + * replacing go's reflection-based type map. + */ +public final class TypeRegistry { + + private static final Map> DECODERS = new HashMap<>(); + private static final Map, String> WIRE_NAMES = new HashMap<>(); + private static final Map, BinEncoder> ENCODERS = new HashMap<>(); + + static { +{{- range .Entries }} + register("{{ .Wire }}", {{ .Type }}.class, {{ .Type }}Encoder.INSTANCE, {{ .Type }}Decoder.INSTANCE); +{{- end }} + } + + private TypeRegistry() { + } + + private static void register(String wire, Class cls, BinEncoder enc, BinDecoder dec) { + DECODERS.put(wire, dec); + DECODERS.put(stripStar(wire), dec); + WIRE_NAMES.put(cls, wire); + ENCODERS.put(cls, enc); + } + + /** + * Writes the wire type string + compatibility marker, then the value body. + */ + @SuppressWarnings("unchecked") + public static void encode(Object value, EncodingContext ctx) { + String wire = WIRE_NAMES.get(value.getClass()); + if (wire == null) { + throw new IllegalArgumentException("bingen: unregistered interface type " + value.getClass().getName()); + } + BinEncoder enc = (BinEncoder) ENCODERS.get(value.getClass()); + ctx.buffer().writeString(wire); + ctx.buffer().writeInt(0); // [compatibility, unused] + enc.encode(value, ctx); + } + + /** + * Reads the compatibility marker, then decodes the concrete value. + */ + public static Object decode(String wire, DecodingContext ctx) { + BinDecoder dec = DECODERS.get(wire); + if (dec == null) { + dec = DECODERS.get(stripStar(wire)); + } + if (dec == null) { + throw new IllegalArgumentException("bingen: unknown wire type " + wire); + } + ctx.buffer().readInt(); // [compatibility, unused] + return dec.decode(ctx); + } + + private static String stripStar(String s) { + return s.startsWith("*") ? s.substring(1) : s; + } +} diff --git a/internal/generator/java/templates/java/streamer.java.tmpl b/internal/generator/java/templates/java/streamer.java.tmpl new file mode 100644 index 0000000..07f4863 --- /dev/null +++ b/internal/generator/java/templates/java/streamer.java.tmpl @@ -0,0 +1,59 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package {{ .Package }}; + +import {{ .RuntimePackage }}.BingenConsumer; +import {{ .RuntimePackage }}.BingenFieldInfo; +import {{ .RuntimePackage }}.BingenValue; +import {{ .RuntimePackage }}.DecodingContext; +import {{ .RuntimePackage }}.ReadBuffer; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +{{- range .Imports }} +import {{ . }}; +{{- end }} + +/** + * Generated push streamer for {@link {{ .Type.Name }}}. Each field is delivered to + * the consumer; slices and maps are flattened one depth (one element per call). + * Return false from the consumer to stop early. + */ +public final class {{ .Type.Name }}Streamer { + + private static final int VERSION = {{ .Version }}; + + private {{ .Type.Name }}Streamer() { + } + + /** + * Streams the fields of an encoded {@link {{ .Type.Name }}} held in memory. + */ + public static void stream(byte[] data, BingenConsumer consumer) { + stream(new ByteArrayInputStream(data), consumer); + } + + /** + * Streams the fields of an encoded {@link {{ .Type.Name }}} read incrementally + * from {@code in} (socket, file, ...). The caller retains ownership of the + * stream and is responsible for closing it. + */ + public static void stream(InputStream in, BingenConsumer consumer) { + DecodingContext ctx = DecodingContext.fromStream(in); + ReadBuffer buff = ctx.buffer(); + + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version streaming {{ .Type.Name }}: expected " + VERSION + " or less, got " + version); + } + + BingenFieldInfo fi = null; +{{ .Body }} + } +} diff --git a/internal/generator/java/validate.go b/internal/generator/java/validate.go new file mode 100644 index 0000000..725f335 --- /dev/null +++ b/internal/generator/java/validate.go @@ -0,0 +1,113 @@ +package java + +import ( + "fmt" + "strings" +) + +var javaReserved []string = []string{ + "abstract", + "assert", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extends", + "final", + "finally", + "float", + "for", + "goto", + "if", + "implements", + "import", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "strictfp", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "try", + "void", + "volatile", + "while", + "true", + "false", + "null", + "_", +} + +// javaReservedWords are the Java keywords (and literals) that may not appear as +// a package segment. +var javaReservedWords map[string]bool + +func init() { + javaReservedWords = make(map[string]bool, len(javaReserved)) + for _, word := range javaReserved { + javaReservedWords[word] = true + } +} + +// validateJavaPackage ensures every segment is a legal Java identifier that is +// not a reserved word. +func validateJavaPackage(pkg string) error { + for seg := range strings.SplitSeq(pkg, ".") { + if !isJavaIdentifier(seg) { + return fmt.Errorf("segment %q is not a valid java identifier", seg) + } + if javaReservedWords[seg] { + return fmt.Errorf("segment %q is a reserved word", seg) + } + } + return nil +} + +// isJavaIdentifier reports whether s is a syntactically valid Java identifier. +func isJavaIdentifier(s string) bool { + if s == "" { + return false + } + for i, r := range s { + if i == 0 { + if !isJavaIdentStart(r) { + return false + } + continue + } + if !isJavaIdentStart(r) && (r < '0' || r > '9') { + return false + } + } + return true +} + +func isJavaIdentStart(r rune) bool { + return r == '_' || r == '$' || + (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') +} diff --git a/internal/generator/templates.go b/internal/generator/templates.go deleted file mode 100644 index 0263fc8..0000000 --- a/internal/generator/templates.go +++ /dev/null @@ -1,208 +0,0 @@ -package generator - -import ( - "embed" - "fmt" - "io" - "text/template" - - "github.com/opencost/bingen/internal/generator/vars" - "github.com/opencost/bingen/internal/meta" - "github.com/opencost/bingen/internal/types" - "golang.org/x/text/cases" - "golang.org/x/text/language" -) - -const ( - // BingenSupportTemplate is the template name for supporting bingen code, including the file - // header, package declaration, imports, and various utilities. - BingenSupportTemplate = "support.go.tmpl" - - // BingenMarshallerTemplate is the template name for the binary marshalling generation. It contains - // the MarshalBinary() implementation as well as various sub-templates for writing different types. - BingenMarshallerTemplate = "marshaller.go.tmpl" - - // BingenUnmarshallerTemplate is the template name for the binary unmarshalling generation. It contains - // the UnmarshalBinary() implementation as well as various sub-templates for reading different types. - BingenUnmarshallerTemplate = "unmarshaller.go.tmpl" - - // BingenStreamerTemplate is the template name for the binary streaming generation. It contains variations - // to the unmarshalling generation as well as calls into the unmarshalling template. - BingenStreamerTemplate = "streamer.go.tmpl" -) - -//go:embed templates/go/*.tmpl -var goBingenTemplatesFS embed.FS - -var ( - goBingenTemplates *template.Template - titleCaser cases.Caser = cases.Title(language.Und, cases.NoLower) -) - -// initialize the templating engine with the go template files, provide external support via -// func maps -func init() { - var err error - - goBingenTemplates = template.New("go-bingen-templates") - goBingenTemplates = goBingenTemplates.Funcs(template.FuncMap{ - "AsTarget": vars.AsTarget, - "NewFieldTarget": vars.NewFieldTarget, - "NewIndexedTarget": vars.NewIndexedTarget, - "NewTypeCastedTarget": vars.NewTypeCastedTarget, - "NewCastedTarget": vars.NewCastedTarget, - "ToWriteParams": ToWriteParams, - "ToReadParams": ToReadParams, - "ToStreamParams": ToStreamParams, - "ToTitle": titleCaser.String, - "ToDefaultValue": ToDefaultValue, - "Map": MakeMap, - }) - - goBingenTemplates, err = goBingenTemplates.ParseFS(goBingenTemplatesFS, "templates/go/*.tmpl") - if err != nil { - panic(err) - } -} - -// MarshallerParams contains the general set of parameters to pass to any type marshalling generator. -// It contains the current generator context, the type currently being marshalled, and the name of the -// target to write from. -type MarshallerParams struct { - Context GeneratorContext - Type types.GenType - Target vars.Target -} - -// UnmarshallerParams contains the general set of parameters to pass to any type unmarshalling generator. -// It contains the current generator context, the type currently being unmarshalled, the target to read -// into, and whether or not that target requires initialization (Set should be false if the target already -// exists). -type UnmarshallerParams struct { - Context GeneratorContext - Type types.GenType - Target vars.Target - Set bool -} - -// StreamParams contains the general set of parameters to pass to any type streaming generator. It contains -// the current generator context and the type currently being generated. -type StreamParams struct { - Context GeneratorContext - Type types.GenType -} - -// SupportParams contains the general set of parameters to pass to the support generator. This includes code -// that supports all bingen operations. -type SupportParams struct { - Package string - Imports []string - BufferImport string - VersionSets []meta.VersionSet - Types []types.GenType - StreamableTypes []*types.StructType -} - -// ToWriteParams is a helper function made available to the templating engine to create MarshallerParams inline. -func ToWriteParams(context GeneratorContext, t types.GenType, target vars.Target) MarshallerParams { - return MarshallerParams{ - Context: context, - Type: t, - Target: target, - } -} - -// ToReadParams is a helper function made available to the templating engine to create UnmarshallerParams inline. -func ToReadParams(context GeneratorContext, t types.GenType, target vars.Target, set bool) UnmarshallerParams { - return UnmarshallerParams{ - Context: context, - Type: t, - Target: target, - Set: set, - } -} - -// ToStreamParams is a helper function made available to the templating engine to create StreamParams inline. -func ToStreamParams(context GeneratorContext, t types.GenType) StreamParams { - return StreamParams{ - Context: context, - Type: t, - } -} - -// MakeMap is a helper function made available to the templating engine to create dynamic parameters to pass -// to various templates. ie: (Map "Context" .Context "Type" .Type.InnerType) -// -// Templates accept a single object called a "pipeline". From that object, all properties can be accessed via -// . notation. So, for the above pipeline, .Context and .Type. In scenarios where templates create parameters -// on the fly, in order to pass those parameters to different templates, you can use this func to build the pipeline. -func MakeMap(kvPairs ...any) map[string]any { - m := make(map[string]any) - for i := 0; i < len(kvPairs); i += 2 { - key, ok := kvPairs[i].(string) - value := kvPairs[i+1] - - if !ok { - continue - } - m[key] = value - } - return m -} - -// default type format mapping with specific casts -var defaultValues map[uint8]string = map[uint8]string{ - types.TypeInt: "int(%s)", - types.TypeInt8: "int8(%s)", - types.TypeInt16: "int16(%s)", - types.TypeInt32: "int32(%s)", - types.TypeInt64: "int64(%s)", - types.TypeUInt: "uint(%s)", - types.TypeUInt8: "uint8(%s)", - types.TypeUInt16: "uint16(%s)", - types.TypeUInt32: "uint32(%s)", - types.TypeUInt64: "uint64(%s)", - types.TypeFloat32: "float32(%s)", - types.TypeFloat64: "float64(%s)", -} - -// ToDefaultValue provides a primitive default value mapping to string formatters for -// quickly generating the type casted default value for a type and default. -func ToDefaultValue(typeCode uint8, value string) string { - if typeCode == types.TypeString { - return fmt.Sprintf("\"%s\"", value) - } - - if typeCode == types.TypeBool { - if value == "" { - return "false" - } - return value - } - - if value == "" { - return fmt.Sprintf(defaultValues[typeCode], "0") - } - return fmt.Sprintf(defaultValues[typeCode], value) -} - -// WriteSupportTemplate writes the file header, package declaration, imports, and all supporting bingen -// code to the provided `io.Writer` -func WriteSupportTemplate(writer io.Writer, params SupportParams) error { - return goBingenTemplates.ExecuteTemplate(writer, BingenSupportTemplate, params) -} - -// WriteMarshallerTemplate writes the binary marshalling code to the provided `io.Writer` -func WriteMarshallerTemplate(writer io.Writer, params MarshallerParams) error { - return goBingenTemplates.ExecuteTemplate(writer, BingenMarshallerTemplate, params) -} - -// WriteUnmarshallerTemplate writes the binary unmarshalling code to the provided `io.Writer` -func WriteUnmarshallerTemplate(writer io.Writer, params UnmarshallerParams) error { - return goBingenTemplates.ExecuteTemplate(writer, BingenUnmarshallerTemplate, params) -} - -// WriteStreamerTemplate writes all of the streaming unmarshalling code to the provided `io.Writer` -func WriteStreamerTemplate(writer io.Writer, params StreamParams) error { - return goBingenTemplates.ExecuteTemplate(writer, BingenStreamerTemplate, params) -} diff --git a/internal/generator/templates/go/marshaller.go.tmpl b/internal/generator/templates/go/marshaller.go.tmpl deleted file mode 100644 index 7057130..0000000 --- a/internal/generator/templates/go/marshaller.go.tmpl +++ /dev/null @@ -1,340 +0,0 @@ -{{/* - writePrimitive handles writing of primitive types to the buffer. It checks if the type is a pointer and dereferences - it if necessary before writing the value using the appropriate buffer method based on the type code. - */}} -{{- define "writePrimitive" -}} - {{- $newTarget := .Target -}} - {{- if .Type.IsPtr -}} - {{- $newTarget = .Target.Deref -}} - {{- end -}} - - {{/* types.TypeBool */ -}} - {{- if eq .Type.Code 0 -}} - buff.WriteBool({{ $newTarget }}) // write bool - {{/* types.TypeInt */ -}} - {{- else if eq .Type.Code 1 -}} - buff.WriteInt({{ $newTarget }}) // write int - {{/* types.TypeInt8 */ -}} - {{- else if eq .Type.Code 2 -}} - buff.WriteInt8({{ $newTarget }}) // write int8 - {{/* types.TypeInt16 */ -}} - {{- else if eq .Type.Code 3 -}} - buff.WriteInt16({{ $newTarget }}) // write int16 - {{/* types.TypeInt32 */ -}} - {{- else if eq .Type.Code 4 -}} - buff.WriteInt32({{ $newTarget }}) // write int32 - {{/* types.TypeInt64 */ -}} - {{- else if eq .Type.Code 5 -}} - buff.WriteInt64({{ $newTarget }}) // write int64 - {{/* types.TypeUInt */ -}} - {{- else if eq .Type.Code 6 -}} - buff.WriteUInt({{ $newTarget }}) // write uint - {{/* types.TypeUInt8 */ -}} - {{- else if eq .Type.Code 7 -}} - buff.WriteUInt8({{ $newTarget }}) // write uint8 - {{/* types.TypeUInt16 */ -}} - {{- else if eq .Type.Code 8 -}} - buff.WriteUInt16({{ $newTarget }}) // write uint16 - {{/* types.TypeUInt32 */ -}} - {{- else if eq .Type.Code 9 -}} - buff.WriteUInt32({{ $newTarget }}) // write uint32 - {{/* types.TypeUInt64 */ -}} - {{- else if eq .Type.Code 10 -}} - buff.WriteUInt64({{ $newTarget }}) // write uint64 - {{/* types.TypeFloat32 */ -}} - {{- else if eq .Type.Code 11 -}} - buff.WriteFloat32({{ $newTarget }}) // write float32 - {{/* types.TypeFloat64 */ -}} - {{- else if eq .Type.Code 12 -}} - buff.WriteFloat64({{ $newTarget }}) // write float64 - {{/* types.TypeString */ -}} - {{- else if eq .Type.Code 13 -}} - {{- $tableIndexVar := .Context.NextVar -}} - if ctx.IsStringTable() { - {{ $tableIndexVar }} := ctx.Table.AddOrGet({{ $newTarget }}) - buff.WriteInt({{ $tableIndexVar }}) // write table index - } else { - buff.WriteString({{ $newTarget }}) // write string - } - {{- end -}} -{{- end -}} - -{{/* - writeSlice handles the writing of slice types. It first writes the length of the slice to the buffer, and then iterates - and writes each element of the slice using the appropriate method based on the element type. The loop variable is generated - using the context to ensure uniqueness. - */}} -{{- define "writeSlice" -}} - // --- [begin][write][slice]({{ .Type.TypeName }}) --- - {{ $loopVar := .Context.NextLoopVar -}} - buff.WriteInt(len({{ .Target }})) // slice length - for {{ $loopVar }} := range {{ .Target }} { - {{- $elementTarget := NewIndexedTarget .Target $loopVar -}} - {{ template "writeType" (ToWriteParams .Context .Type.InnerType $elementTarget) }} - } - // --- [end][write][slice]({{ .Type.TypeName }}) --- -{{- end -}} - -{{/* - writeMap handles the writing of map types. It first writes the length of the map to the buffer, and then iterates over - the map using a range loop. For each key-value pair, it writes the key and value to the buffer using the appropriate method - based on their types. The key and value variables are generated using the context to ensure uniqueness. - */}} -{{- define "writeMap" -}} - // --- [begin][write][map]({{ .Type.TypeName }}) --- - {{ $keyVar := .Context.NextMapVar -}} - {{ $valVar := .Context.NextMapVar -}} - buff.WriteInt(len({{ .Target }})) // map length - for {{ $keyVar }}, {{ $valVar }} := range {{ .Target }} { - {{- template "writeType" (ToWriteParams .Context .Type.KeyType (AsTarget $keyVar)) }} - {{- template "writeType" (ToWriteParams .Context .Type.ValueType (AsTarget $valVar)) }} - } - // --- [end][write][map]({{ .Type.TypeName }}) --- -{{- end -}} - -{{/* - writeStruct handles the writing of struct types. It assumes that the struct type implements the BinEncoder interface, which requires - a MarshalBinaryWithContext method. This leverages the current generate context to call the MarshalBinaryWithContext method of the struct - to write its internal properties to the buffer. If there is an error during marshaling, it returns the error. - - Note that this method is called when the struct type is known, or marked by the generator as a type that will have it's full struct generated. - */}} -{{- define "writeStruct" -}} - // --- [begin][write][struct]({{ .Type.Name }}) --- - {{ $errVar := .Context.NextErrVar -}} - buff.WriteInt(0) // [compatibility, unused] - {{ $errVar }} := {{ .Target }}.MarshalBinaryWithContext(ctx) - if {{ $errVar }} != nil { - return {{ $errVar }} - } - // --- [end][write][struct]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - writeReference handles the writing of "reference" types. In this context, a reference type is a type that does not have generated definition, or - is considered to be an externally defined type. For such types, we require that they implement the MarshalBinary() method in order to be encoded - as part of our binary format. - - We create two new variables, one for storing the byte array returned by the MarshalBinary() method, and another for storing any error that may - occur during marshaling. On an error, we return the error immediately. If marshaling is successful, we write the length of the resulting byte array - to the buffer, followed by the byte array itself. - */}} -{{- define "writeReference" -}} - // --- [begin][write][reference]({{ .Type.Name }}) --- - {{ $nvar := .Context.NextVar -}} - {{ $errVar := .Context.NextErrVar -}} - {{ $nvar }}, {{ $errVar }} := {{ .Target }}.MarshalBinary() - if {{ $errVar }} != nil { - return {{ $errVar }} - } - buff.WriteInt(len({{ $nvar }})) - buff.WriteBytes({{ $nvar }}) - // --- [end][write][reference]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - writeInterface handles the writing of interface types. It requires that the underlying type of the interface implements the BinEncoder interface, - and therefore, marked as a generated bingen type. In order to be able to recreate the underlying concrete type during unmarshalling, we write - the type name as a string, followed by a compatibility byte, followed by the marshalled binary data of the underlying concrete type. - - An error is returned if the concrete type does not implement the BinEncoder interface, or if there is an error during marshaling. - */}} -{{- define "writeInterface" -}} - // --- [begin][write][interface]({{ .Type.Name }}) --- - {{ $interfaceVar := .Context.NextVar -}} - {{ $binaryMarshalerVar := .Context.NextVar -}} - {{ $interfaceOKVar := .Context.NextOKVar -}} - {{ $errVar := .Context.NextErrVar -}} - - {{ $interfaceVar }} := reflect.ValueOf({{ .Target }}).Interface() - {{ $binaryMarshalerVar }}, {{ $interfaceOKVar }} := {{ $interfaceVar }}.(BinEncoder) - if !{{ $interfaceOKVar }} { - return fmt.Errorf("type: %s does not implement %s.BinEncoder", typeToString({{ .Target }}), GeneratorPackageName) - } - buff.WriteString(typeToString({{ .Target }})) - buff.WriteInt(0) // [compatibility, unused] - - {{ $errVar }} := {{ $binaryMarshalerVar }}.MarshalBinaryWithContext(ctx) - if {{ $errVar }} != nil { - return {{ $errVar }} - } - // --- [end][write][interface]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - writeAlias handles the writing of alias types marked as generated by bingen. If an alias is defined externally, it will be treated as - a referenced type (required to implement MarshalBinary). If the alias is defined internally, we can simple reroute the writing to the aliased - type. In order to keep the alias typed correctly throughout use, a new target is created by casting the original target to the alias type. - */}} -{{- define "writeAlias" -}} - // --- [begin][write][alias]({{ .Type.Name }}) --- - {{- /* - pointer types need to be disambiguated for the go parser: ie: ((*TypePtr)(var)) - because the following would be illegal syntax: *TypePtr(var) -> treated as *(TypePtr(var)) - which is incorrect - */ -}} - {{- if .Type.Alias.IsPtr }} - {{- $innerTarget := .Target }} - {{- if .Type.IsPtr }} - {{- $innerTarget = $innerTarget.Deref }} - {{- end }} - {{- $aliasTarget := NewTypeCastedTarget .Type.Alias.TypeName $innerTarget }} - {{ template "writeType" (ToWriteParams .Context .Type.Alias $aliasTarget) }} - {{- else }} - {{- $innerTarget := .Target }} - {{- if .Type.IsPtr }} - {{- $innerTarget = $innerTarget.Deref }} - {{- end }} - {{- $aliasTarget := NewCastedTarget .Type.Alias.TypeName $innerTarget }} - {{ template "writeType" (ToWriteParams .Context .Type.Alias $aliasTarget) }} - {{- end }} - // --- [end][write][alias]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - writeFullStruct handles the writing of a full struct type. The "full" implies that the type has been marked with a - "generate" command annotation, and it is local to the current package. This is different than the "writeStruct" - template which assumes that the binary marshaller has already been generated (or already exists) for the type. - - For writing the full struct, we iterate over and write each field of the struct using the appropriate method based on - its type. - */}} -{{- define "writeFullStruct" -}} - {{- if .Context.IsPreProcess }} - // execute pre-processing func - preProcess{{ .Type.Name }}(target) - {{- end }} - - {{- $context := .Context }} - {{- range .Type.Fields }} - {{- $target := NewFieldTarget "target" .Name }} - {{ template "writeType" (ToWriteParams $context .Type $target) -}} - {{- end }} -{{- end -}} - -{{/* - writeType is the main entry point for writing any type. Nilable types can be written as a single 0 byte if the value is nil. Otherwise, we - write a 1 byte followed by the encoding format for the type (denoted the "rawType"). If the type is non-nilable, we can just write the raw type - encoding directly. - */}} -{{- define "writeType" -}} - {{- if .Type.IsNilable -}} - if {{ .Target }} == nil { - buff.WriteUInt8(uint8(0)) // write nil byte - } else { - buff.WriteUInt8(uint8(1)) // write non-nil byte - - {{ template "writeTypeRaw" . }} - } - {{- else }} - {{ template "writeTypeRaw" . }} - {{- end -}} -{{- end -}} - -{{/* - writeTypeRaw handles the writing of the type without any nilable checks. We check the type code of the type, and - route to the appropriate write method based on the type. For reference types, we first Resolve() the type to determine - if we can resolve it to a known generated struct type, or if it references an externally defined type. - */}} -{{- define "writeTypeRaw" -}} - {{/* types.BasicType */ -}} - {{- if le .Type.Code 13 -}} - {{ template "writePrimitive" . }} - {{/* types.MapType */ -}} - {{- else if eq .Type.Code 14 -}} - {{ template "writeMap" . }} - {{/* types.SliceType */ -}} - {{- else if eq .Type.Code 15 -}} - {{ template "writeSlice" . }} - {{/* types.InterfaceType */ -}} - {{- else if eq .Type.Code 16 -}} - {{ template "writeInterface" . }} - {{/* types.StructType */ -}} - {{- else if eq .Type.Code 17 -}} - {{ template "writeStruct" . }} - {{/* types.ReferenceType */ -}} - {{- else if eq .Type.Code 18 -}} - {{- $resolvedType := call .Type.Resolve }} - {{- if ne $resolvedType nil }} - {{ template "writeTypeRaw" (ToWriteParams .Context $resolvedType .Target) }} - {{- else }} - {{ template "writeReference" . }} - {{- end }} - {{/* types.AliasType */ -}} - {{- else if eq .Type.Code 19 -}} - {{ template "writeAlias" . }} - {{- end -}} -{{- end -}} - -//-------------------------------------------------------------------------- -// {{ .Type.Name }} -//-------------------------------------------------------------------------- - -// MarshalBinary serializes the internal properties of this {{ .Type.Name }} instance -// into a byte array -func (target *{{ .Type.Name }}) MarshalBinary() (data []byte, err error) { -{{- if .Context.IsStringTable }} - ctx := NewEncodingContext(stringtable.NewIndexedStringTableWriter()) -{{- else }} - ctx := NewEncodingContext(nil) -{{- end }} - - e := target.MarshalBinaryWithContext(ctx) - if e != nil { - return nil, e - } - - return ctx.ToBytes(), nil -} - -// MarshalBinary serializes the internal properties of this {{ .Type.Name }} instance -// into an io.Writer. -func (target *{{ .Type.Name }}) MarshalBinaryTo(writer io.Writer) error { - buff := util.NewBufferFromWriter(writer) - defer buff.Flush() - -{{ if .Context.IsStringTable }} - // run a pre-pass to collect all strings into the string table and discard all writes to the main - // buffer. Then, we write the string table, sorted by number of repeated uses (descending), to the - // main buffer, and use the resulting table as part of the context for the main pass. - prepass := stringtable.NewPrepassStringTableWriter() - prepassCtx := NewEncodingContextFromWriter(io.Discard, prepass) - - e := target.MarshalBinaryWithContext(prepassCtx) - if e != nil { - return e - } - - tableWriter := prepass.WriteSortedTo(buff) - ctx := NewEncodingContextFromBuffer(buff, tableWriter) -{{- else }} - ctx := NewEncodingContextFromBuffer(buff, nil) -{{- end }} - - return target.MarshalBinaryWithContext(ctx) -} - -// MarshalBinaryWithContext serializes the internal properties of this {{ .Type.Name }} instance -// into a byte array leveraging a predefined context. -func (target *{{ .Type.Name }}) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { - // panics are recovered and propagated as errors - defer func() { - if r := recover(); r != nil { - if e, ok := r.(error); ok { - err = e - } else if s, ok := r.(string); ok { - err = fmt.Errorf("unexpected panic: %s", s) - } else { - err = fmt.Errorf("unexpected panic: %+v", r) - } - } - }() - - buff := ctx.Buffer - buff.WriteUInt8({{ .Context.VersionSetConst }}) // version - - {{ template "writeFullStruct" . }} - - return nil -} - diff --git a/internal/generator/templates/go/streamer.go.tmpl b/internal/generator/templates/go/streamer.go.tmpl deleted file mode 100644 index 7a6c9e7..0000000 --- a/internal/generator/templates/go/streamer.go.tmpl +++ /dev/null @@ -1,294 +0,0 @@ -{{/* - streamYieldNil is a helper template for yielding a nil value to the stream iterator. This is used for - nilable types when the value is determined to be nil during unmarshalling. - */}} -{{- define "streamYieldNil" -}} - if !yield(fi, nil) { - return - } -{{- end -}} - -{{/* - streamYieldSingle is a helper template for yielding a single value to the stream iterator. This is used for - basic types, struct fields, and any other time we want to yield a single value in the stream. - */}} -{{- define "streamYieldSingle" -}} - if !yield(fi, bstream.SingleV({{ .Value }})) { - return - } -{{- end -}} - -{{/* - streamYieldIndexed is a helper template for yielding an indexed or keyed value to the stream iterator. This is used for - slices and maps when we want to yield each element individually with its corresponding index or key. - */}} -{{- define "streamYieldIndexed" -}} - if !yield(fi, bstream.PairV({{ .Index }}, {{ .Value }})) { - return - } -{{- end -}} - -{{/* - streamReadSlice handles the reading of slice types in a streaming fashion. We first read the length of the slice, and - then iterate over each element, reading it and yielding it to the stream individually. This allows us to handle large slices - without needing to read the entire slice into memory at once. - */}} -{{- define "streamReadSlice" -}} - // --- [begin][read][streaming-slice]({{ .Type.Name }}) --- - {{ $lenVar := .Context.NextVar }} - {{- $loopVar := .Context.NextLoopVar }} - {{- $innerVar := .Context.NextVar -}} - - {{ $lenVar }} := buff.ReadInt() // slice len - for {{ $loopVar }} := range {{ $lenVar }} { - {{- $target := (AsTarget $innerVar) }} - {{ template "readType" (ToReadParams .Context .Type.InnerType $target true) }} - {{ template "streamYieldIndexed" (Map "Index" $loopVar "Value" $innerVar) }} - } - // --- [end][read][streaming-slice]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - streamReadMap handles the reading of map types in a streaming fashion. We first read the length of the map, and then iterate - over each key-value pair, reading them and yielding them to the stream individually. This allows us to handle large maps without - needing to read the entire map into memory at once. - */}} -{{- define "streamReadMap" -}} - // --- [begin][read][streaming-map]({{ .Type.Name }}) --- - {{ $lenVar := .Context.NextVar }} - {{- $keyVar := .Context.NextMapVar }} - {{- $valVar := .Context.NextMapVar -}} - - {{ $lenVar }} := buff.ReadInt() // map len - for range {{ $lenVar }} { - {{- $keyTarget := (AsTarget $keyVar) }} - {{- $valTarget := (AsTarget $valVar) -}} - {{ template "readType" (ToReadParams .Context .Type.KeyType $keyTarget true) }} - {{ template "readType" (ToReadParams .Context .Type.ValueType $valTarget true) }} - {{ template "streamYieldIndexed" (Map "Index" $keyVar "Value" $valVar) }} - } - // --- [end][read][streaming-map]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - streamReadAlias handles the reading of alias types in a streaming fashion. If the alias is for a map or slice, we route to the - appropriate streaming read method. If the alias is for a basic type or struct, we read the value and yield it as a single value in - the stream. - - We need a special case for alias types in the event that we have an alias for map or slice, we need to stream it. Alias types add a - single depth of indirection, so we just ensure that we can route to the correct streaming method for the underlying type. If the alias - is for a basic type or struct, we can just read and yield as normal. - */}} -{{- define "streamReadAlias" -}} - // --- [begin][read][streaming-alias]({{ .Type.Name }}) --- - {{/* types.MapType */ -}} - {{- if eq .Type.Alias.Code 14 -}} - {{ template "streamReadMap" (ToStreamParams .Context .Type.Alias) }} - {{/* types.SliceType */ -}} - {{- else if eq .Type.Alias.Code 15 -}} - {{ template "streamReadSlice" (ToStreamParams .Context .Type.Alias) }} - {{- else -}} - {{- $target := (AsTarget .Context.NextVar) -}} - {{ template "readType" (ToReadParams .Context .Type.Alias $target true) }} - {{- $value := ($target.CastAs .Type.Name) }} - {{- if .Type.IsPtr }} - {{- $tempVar := .Context.NextVar -}} - {{ $tempVar }} := {{ $value }} - {{- $value = (AsTarget $tempVar).Ref }} - {{- end }} - {{ template "streamYieldSingle" (Map "Value" $value) }} - {{- end }} - // --- [end][read][streaming-alias]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - streamSetDefault handles the setting of default values for fields that are tagged with a version that is greater than the version being unmarshalled. - For nilable types, we can just yield a nil value to the stream. For non-nilable types, we need to determine the default value based on the annotations, or - set it to the zero value for that type if no default is specified. - */}} -{{- define "streamSetDefault" -}} - {{- if .Type.IsNilable }} - {{ template "streamYieldNil" }} - {{- else }} - {{- $defaultValue := "" }} - {{- if .Opts }} - {{- $defaultValue = .Opts.Default }} - {{- end -}} - - {{/* types.BasicType */ -}} - {{- if le .Type.Code 13 -}} - {{- $targetVar := .Context.NextVar -}} - var {{ $targetVar }} {{ .Type.TypeName }} = {{ ToDefaultValue .Type.Code $defaultValue }} // default - {{ template "streamYieldSingle" (Map "Value" $targetVar) }} - {{- else -}} - {{- if ne $defaultValue "" -}} - {{- $targetVar := .Context.NextVar -}} - var {{ $targetVar }} {{ .Type.TypeName }} = {{ $defaultValue }} // default - {{ template "streamYieldSingle" (Map "Value" $targetVar) }} - {{- end }} - {{- end }} - {{- end }} -{{- end -}} - -{{/* - streamReadFullStruct handles the reading of a full struct in a streaming fashion, including field version checks and default value setting. For each field - in the struct, we check if there is a version tag, and if so, we compare that to the version being unmarshalled. If the field version is less than or equal - to the unmarshalling version, we read the field as normal. If the field version is greater than the unmarshalling version, we set the default value for that - field. - - The major addition for the streaming variant is the `BingenFieldInfo` struct that is created for each field, and yielded to the stream iterator along with the - related value. This info is what allows the stream caller to determine which field is being read, what type, and handle appropriately. - - The "full" implies that the type has been marked with a "generate" command annotation, and it is local to the current package. This is different than - the "streamReadStruct" template which assumes that the binary unmarshaller has already been generated (or already exists) for the type. - */}} -{{- define "streamReadFullStruct" -}} - {{- $context := .Context }} - {{- range .Type.Fields }} - {{- $fieldVersion := 0 }} - {{- if .Opts }} - {{- $fieldVersion = .Opts.Version }} - {{- end }} - - fi = bstream.BingenFieldInfo{ - Type: reflect.TypeFor[{{ .Type.TypeName }}](), - Name: "{{ .Name }}", - } - - {{- if gt $fieldVersion 0 }} - // field version check - if uint8({{ $fieldVersion }}) <= version { - {{ template "streamReadType" (ToStreamParams $context .Type) }} - } else { - {{ template "streamSetDefault" (Map "Context" $context "Opts" .Opts "Type" .Type) }} - } - {{- else -}} - {{ template "streamReadType" (ToStreamParams $context .Type) }} - {{- end -}} - {{- end }} -{{- end -}} - -{{/* - streamReadType handles the reading of a type in a streaming fashion, including nilable types. For nilable types, we first check if the value is nil by reading a - uint8 from the buffer. If it is nil, we yield a nil value to the stream. Otherwise, we read the value as normal. - */}} -{{- define "streamReadType" -}} - {{- if .Type.IsNilable }} - if buff.ReadUInt8() == uint8(0) { - {{ template "streamYieldNil" }} - } else { - {{ template "streamReadTypeRaw" . }} - } - {{ else }} - {{ template "streamReadTypeRaw" . }} - {{ end -}} -{{- end -}} - -{{/* - streamReadTypeRaw handles the reading of the type without any nilable checks. We check the type code of the type, and - route to the appropriate read method based on the type. For reference types, we first Resolve() the type to determine - if we can resolve it to a known generated struct type, or if it references an externally defined type. - - The only difference between the streamReadTypeRaw and readTypeRaw is that the streamReadTypeRaw templates will route to - the streaming read methods for maps, slices, and aliases. And instead of reading values and setting to fields, we yield - values to the stream iterator. - */}} -{{- define "streamReadTypeRaw" -}} - {{/* types.BasicType */ -}} - {{- if le .Type.Code 13 -}} - {{- $targetVar := .Context.NextVar }} - {{- $target := (AsTarget $targetVar) }} - {{ template "readPrimitive" (ToReadParams .Context .Type $target true) }} - {{ template "streamYieldSingle" (Map "Value" $targetVar) }} - {{/* types.MapType */ -}} - {{- else if eq .Type.Code 14 -}} - {{ template "streamReadMap" . }} - {{/* types.SliceType */ -}} - {{- else if eq .Type.Code 15 -}} - {{ template "streamReadSlice" . }} - {{/* types.InterfaceType */ -}} - {{- else if eq .Type.Code 16 -}} - {{- $targetVar := .Context.NextVar }} - {{- $target := (AsTarget $targetVar) }} - {{ template "readInterface" (ToReadParams .Context .Type $target true) }} - {{ template "streamYieldSingle" (Map "Value" $targetVar) }} - {{/* types.StructType */ -}} - {{- else if eq .Type.Code 17 -}} - {{- $targetVar := .Context.NextVar }} - {{- $target := (AsTarget $targetVar) }} - {{ template "readStruct" (ToReadParams .Context .Type $target true) }} - {{ template "streamYieldSingle" (Map "Value" $targetVar) }} - {{/* types.ReferenceType */ -}} - {{- else if eq .Type.Code 18 -}} - {{- $resolvedType := call .Type.Resolve }} - {{- if ne $resolvedType nil }} - {{ template "streamReadTypeRaw" (ToStreamParams .Context $resolvedType) }} - {{- else }} - {{- $targetVar := .Context.NextVar }} - {{- $target := (AsTarget $targetVar) }} - {{ template "readReference" (ToReadParams .Context .Type $target true) }} - {{ template "streamYieldSingle" (Map "Value" $targetVar) }} - {{- end }} - {{/* types.AliasType */ -}} - {{- else if eq .Type.Code 19 -}} - {{ template "streamReadAlias" . }} - {{- end -}} -{{- end -}} - - -//-------------------------------------------------------------------------- -// {{ .Type.Name }}Stream -//-------------------------------------------------------------------------- - -// {{ .Type.Name }}Stream is a single use field stream for the contents of an {{ .Type.Name }} instance. Instead of creating an instance and populating -// the fields on that instance, we provide a streaming iterator which yields (BingenFieldInfo, *BingenValue) tuples for each -// streamable element. All slices and maps will be flattened one depth and each element streamed individually. -type {{ .Type.Name }}Stream struct { - reader io.Reader - ctx *DecodingContext - err error -} - -// Closes closes the internal io.Reader used to read and parse the {{ .Type.Name }} fields. -// This should be called once the stream is no longer needed. -func (stream *{{ .Type.Name }}Stream) Close() { - if closer, ok := stream.reader.(io.Closer); ok { - closer.Close() - } - stream.ctx.Close() -} - -// Error returns an error if one occurred during the process of streaming the {{ .Type.Name }} -// This can be checked after iterating through the Stream(). -func (stream *{{ .Type.Name }}Stream) Error() error { - return stream.err -} - -// New{{ .Type.Name }}Stream creates a new {{ .Type.Name }}Stream, which uses the io.Reader data to stream all internal fields of an {{ .Type.Name }} instance -func New{{ .Type.Name }}Stream(reader io.Reader) bstream.BingenStream { - ctx := NewDecodingContextFromReader(reader) - - return &{{ .Type.Name }}Stream{ - ctx: ctx, - reader: reader, - } -} - -// Stream returns the iterator which will stream each field of the target type. -func (stream *{{ .Type.Name }}Stream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstream.BingenValue] { - return func(yield func(bstream.BingenFieldInfo, *bstream.BingenValue) bool) { - var fi bstream.BingenFieldInfo - - ctx := stream.ctx - buff := ctx.Buffer - version := buff.ReadUInt8() - - if version > {{ .Context.VersionSetConst }} { - stream.err = fmt.Errorf("Invalid Version Unmarshalling {{ .Type.Name }}. Expected %d or less, got %d", {{ .Context.VersionSetConst }}, version) - return - } - - {{ template "streamReadFullStruct" . }} - } -} - diff --git a/internal/generator/templates/go/unmarshaller.go.tmpl b/internal/generator/templates/go/unmarshaller.go.tmpl deleted file mode 100644 index 5f7ee93..0000000 --- a/internal/generator/templates/go/unmarshaller.go.tmpl +++ /dev/null @@ -1,413 +0,0 @@ -{{/* - SetOpFor is a helper template that returns whether or not to use a declaration operator (:=) or an assignment operator (=) when setting a variable. - This is used in the unmarshaller when we need to conditionally declare a new variable for a field external to the read call. - */}} -{{- define "SetOpFor" -}} - {{ if . }}:={{ else }}={{ end }} -{{- end -}} - -{{/* - readPrimitive handles the reading of primitive (or built-in) go types, which are defined as any type with a type code less than or equal to 13. - The supported primitive types include bool, int variants, uint variants, float variants, and string. for pointer types, we read the value into a non-pointer, - and then take the address of that new variable. - */}} -{{- define "readPrimitive" -}} - {{- $varName := .Context.NextVar }} - {{- $resultVar := $varName }} - {{- if .Type.IsPtr }} - {{- $resultVar = printf "&%s" $resultVar -}} - {{- end -}} - - {{- if .Set -}} - var {{ .Target }} {{ .Type.TypeName }} - {{- end }} - {{/* types.TypeBool */ -}} - {{- if eq .Type.Code 0 -}} - {{ $varName }} := buff.ReadBool() // read bool - {{/* types.TypeInt */ -}} - {{- else if eq .Type.Code 1 -}} - {{ $varName }} := buff.ReadInt() // read int - {{/* types.TypeInt8 */ -}} - {{- else if eq .Type.Code 2 -}} - {{ $varName }} := buff.ReadInt8() // read int8 - {{/* types.TypeInt16 */ -}} - {{- else if eq .Type.Code 3 -}} - {{ $varName }} := buff.ReadInt16() // read int16 - {{/* types.TypeInt32 */ -}} - {{- else if eq .Type.Code 4 -}} - {{ $varName }} := buff.ReadInt32() // read int32 - {{/* types.TypeInt64 */ -}} - {{- else if eq .Type.Code 5 -}} - {{ $varName }} := buff.ReadInt64() // read int64 - {{/* types.TypeUInt */ -}} - {{- else if eq .Type.Code 6 -}} - {{ $varName }} := buff.ReadUInt() // read uint - {{/* types.TypeUInt8 */ -}} - {{- else if eq .Type.Code 7 -}} - {{ $varName }} := buff.ReadUInt8() // read uint8 - {{/* types.TypeUInt16 */ -}} - {{- else if eq .Type.Code 8 -}} - {{ $varName }} := buff.ReadUInt16() // read uint16 - {{/* types.TypeUInt32 */ -}} - {{- else if eq .Type.Code 9 -}} - {{ $varName }} := buff.ReadUInt32() // read uint32 - {{/* types.TypeUInt64 */ -}} - {{- else if eq .Type.Code 10 -}} - {{ $varName }} := buff.ReadUInt64() // read uint64 - {{/* types.TypeFloat32 */ -}} - {{- else if eq .Type.Code 11 -}} - {{ $varName }} := buff.ReadFloat32() // read float32 - {{/* types.TypeFloat64 */ -}} - {{- else if eq .Type.Code 12 -}} - {{ $varName }} := buff.ReadFloat64() // read float64 - {{/* types.TypeString */ -}} - {{- else if eq .Type.Code 13 -}} - {{ $tempVar := .Context.NextVar }} - {{- $tableIndexVar := .Context.NextVar -}} - - var {{ $tempVar }} string - if ctx.IsStringTable() { - {{ $tableIndexVar }} := buff.ReadInt() // read string index - {{ $tempVar }} = ctx.Table.At({{ $tableIndexVar }}) - } else { - {{ $tempVar }} = buff.ReadString() // read string - } - {{ $varName }} := {{ $tempVar }} - {{ end -}} - {{ .Target }} = {{ $resultVar }} -{{- end -}} - -{{/* - readSlice handles the reading of slice types. It first reads the length of the slice, then iterates over the length to - read each element deterministically based on the inner type of the slice. - */}} -{{- define "readSlice" -}} - // --- [begin][read][slice]({{ .Type.Name }}) --- - {{ $sliceVar := .Context.NextVar }} - {{- $lenVar := .Context.NextVar }} - {{- $loopVar := .Context.NextLoopVar }} - {{- $innerVar := .Context.NextVar -}} - - {{ $lenVar }} := buff.ReadInt() // slice len - {{ $sliceVar }} := make({{ .Type.Name }}, {{ $lenVar }}) - for {{ $loopVar }} := range {{ $lenVar }} { - {{- $innerTarget := AsTarget $innerVar -}} - {{ template "readType" (ToReadParams .Context .Type.InnerType $innerTarget true) }} - {{ $sliceVar }}[{{ $loopVar }}] = {{ $innerVar }} - } - {{ .Target }} {{ template "SetOpFor" .Set }} {{ $sliceVar }} - // --- [end][read][slice]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - readMap handles the reading of map types. It first reads the length of the map, then iterates over the length to - deterministically read each key-value pair based on the key type and value types of the map. - */}} -{{- define "readMap" -}} - // --- [begin][read][map]({{ .Type.Name }}) --- - {{ $mapVar := .Context.NextVar }} - {{- $lenVar := .Context.NextVar }} - {{- $keyVar := .Context.NextMapVar }} - {{- $valVar := .Context.NextMapVar -}} - - {{ $lenVar }} := buff.ReadInt() // map len - {{ $mapVar }} := make(map[{{ .Type.KeyType.TypeName }}]{{ .Type.ValueType.TypeName }}, {{ $lenVar }}) - for range {{ $lenVar }} { - {{- $keyTarget := AsTarget $keyVar -}} - {{- $valTarget := AsTarget $valVar -}} - {{ template "readType" (ToReadParams .Context .Type.KeyType $keyTarget true) -}} - {{ template "readType" (ToReadParams .Context .Type.ValueType $valTarget true) -}} - {{ $mapVar }}[{{ $keyVar }}] = {{ $valVar }} - } - {{ .Target }} {{template "SetOpFor" .Set }} {{ $mapVar }} - // --- [end][read][map]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - readStruct handles the reading of struct types. It creates a new variable of the struct type, then leverages the current generator - context to call the UnmarshalBinaryWithContext method on that variable to read in the fields. - - One nuance with reading/unmarshalling types is that the error code generation is handled by the context via `HandleError`. This is - because we using a completely different error handling strategy for streaming unmarshalling, and since we re-use read methods - defined here, our context will dictate how errors are handled. - */}} -{{- define "readStruct" -}} - // --- [begin][read][struct]({{ .Type.Name }}) --- - {{ $ubVar := .Context.NextVar }} - {{- $errVar := .Context.NextErrVar -}} - - {{ $ubVar }} := new({{ .Type.Name }}) - buff.ReadInt() // [compatibility, unused] - {{ $errVar }} := {{ $ubVar }}.UnmarshalBinaryWithContext(ctx) - if {{ $errVar }} != nil { - {{ .Context.HandleError $errVar }} - } - {{- if .Type.IsPtr }} - {{ .Target }} {{ template "SetOpFor" .Set }} {{ $ubVar }} - {{- else }} - {{ .Target }} {{ template "SetOpFor" .Set }} *{{ $ubVar }} - {{- end }} - // --- [end][read][struct]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - readReference handles the reading of reference types. A reference type is a type that does not have a generated definition, or - is considered to be an externally defined type. - */}} -{{- define "readReference" -}} - // --- [begin][read][reference]({{ .Type.Name }}) --- - {{ $ubVar := .Context.NextVar }} - {{- $blVar := .Context.NextVar }} - {{- $baVar := .Context.NextVar }} - {{- $errVar := .Context.NextErrVar -}} - - {{ $ubVar }} := new({{ .Type.Name }}) - {{ $blVar }} := buff.ReadInt() // byte array length - {{ $baVar }} := buff.ReadBytes({{ $blVar }}) - {{ $errVar }} := {{ $ubVar }}.UnmarshalBinary({{ $baVar }}) - if {{ $errVar }} != nil { - {{ .Context.HandleError $errVar }} - } - {{ if .Type.IsPtr -}} - {{ .Target }} {{ template "SetOpFor" .Set }} {{ $ubVar }} - {{ else -}} - {{ .Target }} {{ template "SetOpFor" .Set }} *{{ $ubVar }} - {{ end -}} - // --- [end][read][reference]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - readInterface handles the reading of interface types. It requires that the underlying type be a generated type with a known type name. - This is because the format reads a type name string during unmarshalling. Once the concrete type is determined, we can use that specific - type's UnmarshalBinaryWithContext method to read in the data. - */}} -{{- define "readInterface" -}} - // --- [begin][read][interface]({{ .Type.Name }}) --- - {{ $tNameVar := .Context.NextVar }} - {{- $nameVar := .Context.NextVar }} - {{- $interfaceOKVar := .Context.NextOKVar }} - {{- $ubVar := .Context.NextVar }} - {{- $errVar := .Context.NextErrVar -}} - {{ $tNameVar }} := buff.ReadString() - _, {{ $nameVar }}, _ := resolveType({{ $tNameVar }}) - if _, ok := typeMap[{{ $nameVar }}]; !ok { - {{ .Context.HandleError (printf "fmt.Errorf(\"Unknown Type: %%s\", %s)" $nameVar) }} - } - - {{ $ubVar }}, {{ $interfaceOKVar }} := reflect.New(typeMap[{{ $nameVar }}]).Interface().(BinDecoder) - if !{{ $interfaceOKVar }} { - {{ .Context.HandleError (printf "fmt.Errorf(\"Type: %%s does not implement %%s.BinDecoder.\", %s, GeneratorPackageName)" $nameVar) }} - } - - buff.ReadInt() // [compatibility, unused] - {{ $errVar }} := {{ $ubVar }}.UnmarshalBinaryWithContext(ctx) - if {{ $errVar }} != nil { - {{ .Context.HandleError $errVar }} - } - {{ .Target }} {{ template "SetOpFor" .Set }} {{ $ubVar }}.({{ .Type.Name }}) - // --- [end][read][interface]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - readAlias handles the reading of alias types marked as generated by bingen. If an alias is defined externally, it will be treated as - a referenced type (required to implement UnmarshalBinary). If the alias is defined internally, we can simply reroute the reading to the aliased - type. In order to keep the alias typed correctly throughout use, a new target is created by casting the original target to the alias type. - */}} -{{- define "readAlias" -}} - // --- [begin][read][alias]({{ .Type.Name }}) --- - {{- $varName := .Context.NextVar -}} - {{- $varTarget := (AsTarget $varName) -}} - - {{ template "readType" (ToReadParams .Context .Type.Alias $varTarget true) }} - {{- if .Type.IsPtr }} - {{- $tempVar := .Context.NextVar -}} - {{ $tempVar }} := {{ .Type.Name }}({{ $varName }}) - {{ .Target }} {{ template "SetOpFor" .Set }} &{{ $tempVar }} - {{- else }} - {{ .Target }} {{ template "SetOpFor" .Set }} {{ .Type.Name }}({{ $varName }}) - {{- end }} - // --- [end][read][alias]({{ .Type.Name }}) --- -{{- end -}} - -{{/* - For fields that are tagged with a version that is greater than the version being unmarshalled, we need to set a default value. This template - handles the logic for determining if the default value can be read from the annotations, or if it should just be set to the zero value for that type. - */}} -{{- define "readSetDefault" -}} - {{- if .Type.IsNilable }} - {{ .Target }} = nil - {{- else }} - {{- $defaultValue := "" }} - {{- if .Opts }} - {{- $defaultValue = .Opts.Default }} - {{- end -}} - - {{/* types.BasicType */ -}} - {{- if le .Type.Code 13 -}} - {{ .Target }} = {{ ToDefaultValue .Type.Code $defaultValue }} // default - {{- else -}} - {{- if ne $defaultValue "" -}} - {{ .Target }} = {{ $defaultValue }} // default - {{- end }} - {{- end }} - {{- end }} -{{- end -}} - -{{/* - readFullStruct handles the reading of a full struct, including field version checks and default value setting. For each field in the struct, - we check if there is a version tag, and if so, we compare that to the version being unmarshalled. If the field version is less than or equal to the - unmarshalling version, we read the field as normal. If the field version is greater than the unmarshalling version, we set the default value for that field. - - The "full" implies that the type has been marked with a "generate" command annotation, and it is local to the current package. This is different than - the "readStruct" template which assumes that the binary unmarshaller has already been generated (or already exists) for the type. - */}} -{{- define "readFullStruct" -}} - {{- $context := .Context }} - {{- range .Type.Fields }} - {{- $fieldVersion := 0 }} - {{- if .Opts }} - {{- $fieldVersion = .Opts.Version }} - {{- end }} - - {{- $fieldTarget := NewFieldTarget "target" .Name -}} - {{- if gt $fieldVersion 0 }} - // field version check - if uint8({{ $fieldVersion }}) <= version { - {{- template "readType" (ToReadParams $context .Type $fieldTarget false) }} - } else { - {{- template "readSetDefault" (Map "Context" $context "Opts" .Opts "Type" .Type "Target" $fieldTarget) }} - } - {{- else -}} - {{- template "readType" (ToReadParams $context .Type $fieldTarget false) }} - {{- end -}} - {{- end }} - - {{ if .Context.IsMigration -}} - // execute migration func if version delta detected - if version != {{ .Context.VersionSetConst }} { - migrate{{ .Type.Name }}(target, version, {{ .Context.VersionSetConst }}) - } - {{- end }} - - {{ if .Context.IsPostProcess -}} - // execute post-processing func - postProcess{{ .Type.Name }}(target) - {{- end }} -{{- end -}} - -{{/* - readType is the main entry point for reading any type. Nilable types can be read by first reading a single byte to determine - if the value is nil (0) or non-nil (1). If the value is non-nil, we read the value based on the type's encoding format (denoted as "rawType"). - If the type is non-nilable, we can just read the raw type directly. - */}} -{{- define "readType" -}} - {{- $setVar := .Set }} - {{- if .Type.IsNilable }} - {{- if .Set }} - var {{ .Target }} {{ .Type.TypeName }} - {{- $setVar = false -}} - {{- end }} - if buff.ReadUInt8() == uint8(0) { - {{ .Target }} = nil - } else { - {{ template "readTypeRaw" (ToReadParams .Context .Type .Target $setVar) }} - } - {{ else }} - {{ template "readTypeRaw" (ToReadParams .Context .Type .Target $setVar) }} - {{ end -}} -{{- end -}} - -{{/* - readTypeRaw handles the reading of the type without any nilable checks. We check the type code of the type, and - route to the appropriate read method based on the type. For reference types, we first Resolve() the type to determine - if we can resolve it to a known generated struct type, or if it references an externally defined type. - */}} -{{- define "readTypeRaw" -}} - {{/* types.BasicType */ -}} - {{- if le .Type.Code 13 -}} - {{ template "readPrimitive" . }} - {{/* types.MapType */ -}} - {{- else if eq .Type.Code 14 -}} - {{ template "readMap" . }} - {{/* types.SliceType */ -}} - {{- else if eq .Type.Code 15 -}} - {{ template "readSlice" . }} - {{/* types.InterfaceType */ -}} - {{- else if eq .Type.Code 16 -}} - {{ template "readInterface" . }} - {{/* types.StructType */ -}} - {{- else if eq .Type.Code 17 -}} - {{ template "readStruct" . }} - {{/* types.ReferenceType */ -}} - {{- else if eq .Type.Code 18 -}} - {{- $resolvedType := call .Type.Resolve }} - {{- if ne $resolvedType nil }} - {{ template "readTypeRaw" (ToReadParams .Context $resolvedType .Target .Set) }} - {{- else }} - {{ template "readReference" . }} - {{- end }} - {{/* types.AliasType */ -}} - {{- else if eq .Type.Code 19 -}} - {{ template "readAlias" . }} - {{- end -}} -{{- end -}} - - - - -// UnmarshalBinary uses the data passed byte array to set all the internal properties of -// the {{ .Type.Name }} type -func (target *{{ .Type.Name }}) UnmarshalBinary(data []byte) error { - ctx := NewDecodingContextFromBytes(data) - defer ctx.Close() - - err := target.UnmarshalBinaryWithContext(ctx) - if err != nil { - return err - } - - return nil -} - -// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of -// the {{ .Type.Name }} type -func (target *{{ .Type.Name }}) UnmarshalBinaryFromReader(reader io.Reader) error { - ctx := NewDecodingContextFromReader(reader) - defer ctx.Close() - - err := target.UnmarshalBinaryWithContext(ctx) - if err != nil { - return err - } - - return nil -} - -// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of -// the {{ .Type.Name }} type -func (target *{{ .Type.Name }}) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { - // panics are recovered and propagated as errors - defer func() { - if r := recover(); r != nil { - if e, ok := r.(error); ok { - err = e - } else if s, ok := r.(string); ok { - err = fmt.Errorf("unexpected panic: %s", s) - } else { - err = fmt.Errorf("unexpected panic: %+v", r) - } - } - }() - - buff := ctx.Buffer - version := buff.ReadUInt8() - - if version > {{ .Context.VersionSetConst }} { - return fmt.Errorf("Invalid Version Unmarshalling {{ .Type.Name }}. Expected %d or less, got %d", {{ .Context.VersionSetConst }}, version) - } - - {{ template "readFullStruct" . }} - - return nil -} - diff --git a/internal/generator/vars/vars.go b/internal/generator/vars/vars.go deleted file mode 100644 index 92440a6..0000000 --- a/internal/generator/vars/vars.go +++ /dev/null @@ -1,215 +0,0 @@ -package vars - -import ( - "fmt" - "strings" -) - -// Target is used to reference a target property or identifier -type Target string - -// Deref returns a dereferenced target. -func (t Target) Deref() Target { - return "*" + t -} - -// Ref returns a reference to the target. -func (t Target) Ref() Target { - return "&" + t -} - -// CastAs returns the target casted as a specific type. -func (t Target) CastAs(typeName string) Target { - return Target(fmt.Sprintf("%s(%s)", typeName, t)) -} - -// String returns the string representation of the Target -func (t Target) String() string { - return string(t) -} - -func AsTarget(name string) Target { - return Target(name) -} - -// NewFieldTarget creates and returns an . Target -func NewFieldTarget(obj string, field string) Target { - return Target(fmt.Sprintf("%s.%s", obj, field)) -} - -func NewIndexedTarget(target Target, idx string) Target { - return Target(fmt.Sprintf("%s[%s]", target, idx)) -} - -func NewCastedTarget(cast string, target Target) Target { - return Target(fmt.Sprintf("%s(%s)", cast, target)) -} - -func NewTypeCastedTarget(cast string, target Target) Target { - return Target(fmt.Sprintf("((%s)(%s))", cast, target)) -} - -// VarNames generates variable names -type VarNames interface { - // Generates a returns the next variable name - Next() string -} - -// Alpha Var Runes -const ( - A rune = iota + 97 - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z -) - -// string of all lowercase alpha -const alphaChars string = "abcdefghijklmnopqrstuvwxyz" - -// AlphaCharFor returns the lower case alpha character for a rune -func AlphaCharFor(r rune) string { - if r < A || r > Z { - return "" - } - - i := int32(r - A) - return alphaChars[i : i+1] -} - -// ToAlphaChars accepts a var list of runes and returns the strings -func ToAlphaChars(rs ...rune) []string { - s := []string{} - for _, r := range rs { - c := AlphaCharFor(r) - if c != "" { - s = append(s, c) - } - } - return s -} - -// All Alpha Runes -func AllAlphaRunes() []rune { - var alpha []rune - for i := A; i <= Z; i++ { - alpha = append(alpha, i) - } - return alpha -} - -// OnlyAlphaRunes returns a skip list to pass omitting all but the provided runes -func SkipAllBut(allow ...rune) []rune { - var skip []rune - alphas := AllAlphaRunes() - for _, r := range alphas { - found := false - for _, ar := range allow { - if ar == r { - found = true - break - } - } - if !found { - skip = append(skip, r) - } - } - return skip -} - -// runeSet is used to store runes -type runeSet map[rune]bool - -// creates a new rune set provided the slice of runes -func newRuneSet(runes []rune) runeSet { - m := make(map[rune]bool) - for _, r := range runes { - m[r] = true - } - - return runeSet(m) -} - -// Has returns true if the rune set contains the rune -func (rs runeSet) Has(r rune) bool { - return rs[r] -} - -// VarNames implementation which creates vars a-z, aa-zz, aaa-zzz, etc... -type alphaVarNames struct { - inc int32 - cycle int - skipSet runeSet -} - -// NewAlphaVarNames returns a new VarNames implementation capable of ignoring specific runes. -func NewAlphaVarNames(skip ...rune) VarNames { - avn := &alphaVarNames{ - inc: 0, - cycle: 1, - skipSet: newRuneSet(skip), - } - - avn.skip() - return avn -} - -// Next returns a valid string representing the next variable name. -func (vn *alphaVarNames) Next() string { - varName := strings.Repeat(vn.current(), vn.cycle) - vn.incrementAndSkip() - - return varName -} - -// current string for the current rune -func (vn *alphaVarNames) current() string { - return string([]rune{vn.currentRune()}) -} - -// current rune given position -func (vn *alphaVarNames) currentRune() rune { - return rune(A + vn.inc) -} - -// skip any ignored runes -func (vn *alphaVarNames) skip() { - for vn.skipSet.Has(rune(A + vn.inc)) { - vn.increment() - } -} - -// skip any ignored runes and increment the position if necessary -func (vn *alphaVarNames) incrementAndSkip() { - vn.increment() - vn.skip() -} - -// increment the rune position and cycle if necessary -func (vn *alphaVarNames) increment() { - vn.inc = (vn.inc + 1) % 26 - if vn.inc == 0 { - vn.cycle++ - } -} diff --git a/internal/types/types.go b/internal/types/types.go index 2735d6b..2c19437 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -58,6 +58,22 @@ var BasicTypes = []*BasicType{ NewBasicType("", "string", TypeString, false, false), } +//-------------------------------------------------------------------------- +// Type Code Helpers +//-------------------------------------------------------------------------- + +// IsNumericalPrimitive returns true if the value is within the int -> float64 type +// range +func IsNumericalPrimitive(code uint8) bool { + return code > TypeBool && code < TypeString +} + +// IsNonStringPrimitive returns true if the value is within the bool -> float64 type +// range +func IsNonStringPrimitive(code uint8) bool { + return code >= TypeBool && code < TypeString +} + //-------------------------------------------------------------------------- // AnnotatedTypeOpts //-------------------------------------------------------------------------- diff --git a/internal/types/walk.go b/internal/types/walk.go new file mode 100644 index 0000000..f963ea8 --- /dev/null +++ b/internal/types/walk.go @@ -0,0 +1,27 @@ +package types + +// WalkType invokes visit for t and for every element type nested within it, +// descending into slice elements, map keys and values, alias targets, and +// resolved references. References that do not resolve are visited as-is (the +// leaf reference), letting callers decide how to treat external types. +// +// It centralizes the structural recursion shared by the code generators so that +// adding a new nested kind is a single change. +func WalkType(t GenType, visit func(GenType)) { + visit(t) + + switch t.Code() { + case TypeSlice: + WalkType(t.(*SliceType).InnerType, visit) + case TypeMap: + m := t.(*MapType) + WalkType(m.KeyType, visit) + WalkType(m.ValueType, visit) + case TypeAlias: + WalkType(t.(*AliasType).Alias, visit) + case TypeReference: + if resolved := t.(*ReferenceType).Resolve(); resolved != nil { + WalkType(resolved, visit) + } + } +} diff --git a/tests/aliases/aliases_codecs.go b/tests/aliases/aliases_codecs.go index 4f12374..f9158a9 100644 --- a/tests/aliases/aliases_codecs.go +++ b/tests/aliases/aliases_codecs.go @@ -389,13 +389,12 @@ func (target *Info) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { buff.WriteUInt8(DefaultCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Name) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Name) // write string } - - buff.WriteUInt(target.Age) // write uint + buff.WriteUInt(target.Age) return nil } @@ -451,18 +450,17 @@ func (target *Info) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) return fmt.Errorf("Invalid Version Unmarshalling Info. Expected %d or less, got %d", DefaultCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Name = a - - d := buff.ReadUInt() // read uint - target.Age = d + target.Name = v0 + var v2 uint + v2 = buff.ReadUInt() + target.Age = v2 return nil } @@ -530,230 +528,186 @@ func (target *Parent) MarshalBinaryWithContext(ctx *EncodingContext) (err error) buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][alias](shared.Name) --- - if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(string(*target.Name)) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(string(*target.Name)) + buff.WriteInt(v0) // write table index } else { buff.WriteString(string(*target.Name)) // write string } - // --- [end][write][alias](shared.Name) --- } if target.Age == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][alias](shared.Age) --- if ((*int)(*target.Age)) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - - buff.WriteInt(*((*int)(*target.Age))) // write int - + buff.WriteInt(*((*int)(*target.Age))) } // --- [end][write][alias](shared.Age) --- } - // --- [begin][write][alias](Child) --- - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(string(target.FirstChild)) - buff.WriteInt(b) // write table index + v1 := ctx.Table.AddOrGet(string(target.FirstChild)) + buff.WriteInt(v1) // write table index } else { buff.WriteString(string(target.FirstChild)) // write string } - // --- [end][write][alias](Child) --- - // --- [begin][write][alias](ChildInfo) --- if ((*Info)(target.FirstChildInfo)) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](Info) --- buff.WriteInt(0) // [compatibility, unused] - errA := ((*Info)(target.FirstChildInfo)).MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v2 := ((*Info)(target.FirstChildInfo)).MarshalBinaryWithContext(ctx) + if v2 != nil { + return v2 } // --- [end][write][struct](Info) --- - } // --- [end][write][alias](ChildInfo) --- if target.Children == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]Child) --- buff.WriteInt(len(target.Children)) // slice length - for i := range target.Children { + for v3 := range target.Children { // --- [begin][write][alias](Child) --- - if ctx.IsStringTable() { - c := ctx.Table.AddOrGet(string(target.Children[i])) - buff.WriteInt(c) // write table index + v4 := ctx.Table.AddOrGet(string(target.Children[v3])) + buff.WriteInt(v4) // write table index } else { - buff.WriteString(string(target.Children[i])) // write string + buff.WriteString(string(target.Children[v3])) // write string } - // --- [end][write][alias](Child) --- } // --- [end][write][slice]([]Child) --- - } - // --- [begin][write][alias](OtherChildInfo) --- if []ChildInfo(target.ChildrenInfo) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]ChildInfo) --- buff.WriteInt(len([]ChildInfo(target.ChildrenInfo))) // slice length - for j := range []ChildInfo(target.ChildrenInfo) { + for v5 := range []ChildInfo(target.ChildrenInfo) { // --- [begin][write][alias](ChildInfo) --- - if ((*Info)([]ChildInfo(target.ChildrenInfo)[j])) == nil { + if ((*Info)([]ChildInfo(target.ChildrenInfo)[v5])) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](Info) --- buff.WriteInt(0) // [compatibility, unused] - errB := ((*Info)([]ChildInfo(target.ChildrenInfo)[j])).MarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v6 := ((*Info)([]ChildInfo(target.ChildrenInfo)[v5])).MarshalBinaryWithContext(ctx) + if v6 != nil { + return v6 } // --- [end][write][struct](Info) --- - } // --- [end][write][alias](ChildInfo) --- } // --- [end][write][slice]([]ChildInfo) --- - } // --- [end][write][alias](OtherChildInfo) --- - // --- [begin][write][alias](shared.FloatList) --- if []float64(target.FavoriteNumbers) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]float64) --- buff.WriteInt(len([]float64(target.FavoriteNumbers))) // slice length - for ii := range []float64(target.FavoriteNumbers) { - buff.WriteFloat64([]float64(target.FavoriteNumbers)[ii]) // write float64 - + for v7 := range []float64(target.FavoriteNumbers) { + buff.WriteFloat64([]float64(target.FavoriteNumbers)[v7]) } // --- [end][write][slice]([]float64) --- - } // --- [end][write][alias](shared.FloatList) --- - // --- [begin][write][alias](shared.StrMap) --- if map[string]int(target.NameMap) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]int) --- buff.WriteInt(len(map[string]int(target.NameMap))) // map length - for v, z := range map[string]int(target.NameMap) { + for v8, v9 := range map[string]int(target.NameMap) { if ctx.IsStringTable() { - d := ctx.Table.AddOrGet(v) - buff.WriteInt(d) // write table index + v10 := ctx.Table.AddOrGet(v8) + buff.WriteInt(v10) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v8) // write string } - - buff.WriteInt(z) // write int - + buff.WriteInt(v9) } // --- [end][write][map](map[string]int) --- - } // --- [end][write][alias](shared.StrMap) --- - // --- [begin][write][alias](shared.UIntPtrList) --- if []*uint32(target.U32s) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]*uint32) --- buff.WriteInt(len([]*uint32(target.U32s))) // slice length - for jj := range []*uint32(target.U32s) { - if []*uint32(target.U32s)[jj] == nil { + for v11 := range []*uint32(target.U32s) { + if []*uint32(target.U32s)[v11] == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - - buff.WriteUInt32(*[]*uint32(target.U32s)[jj]) // write uint32 - + buff.WriteUInt32(*[]*uint32(target.U32s)[v11]) } } // --- [end][write][slice]([]*uint32) --- - } // --- [end][write][alias](shared.UIntPtrList) --- - // --- [begin][write][alias](shared.DoubleSlice) --- if [][]map[string]*int(target.Slices) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([][]map[string]*int) --- buff.WriteInt(len([][]map[string]*int(target.Slices))) // slice length - for iii := range [][]map[string]*int(target.Slices) { - if [][]map[string]*int(target.Slices)[iii] == nil { + for v12 := range [][]map[string]*int(target.Slices) { + if [][]map[string]*int(target.Slices)[v12] == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]map[string]*int) --- - buff.WriteInt(len([][]map[string]*int(target.Slices)[iii])) // slice length - for jjj := range [][]map[string]*int(target.Slices)[iii] { - if [][]map[string]*int(target.Slices)[iii][jjj] == nil { + buff.WriteInt(len([][]map[string]*int(target.Slices)[v12])) // slice length + for v13 := range [][]map[string]*int(target.Slices)[v12] { + if [][]map[string]*int(target.Slices)[v12][v13] == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]*int) --- - buff.WriteInt(len([][]map[string]*int(target.Slices)[iii][jjj])) // map length - for vv, zz := range [][]map[string]*int(target.Slices)[iii][jjj] { + buff.WriteInt(len([][]map[string]*int(target.Slices)[v12][v13])) // map length + for v14, v15 := range [][]map[string]*int(target.Slices)[v12][v13] { if ctx.IsStringTable() { - e := ctx.Table.AddOrGet(vv) - buff.WriteInt(e) // write table index + v16 := ctx.Table.AddOrGet(v14) + buff.WriteInt(v16) // write table index } else { - buff.WriteString(vv) // write string + buff.WriteString(v14) // write string } - if zz == nil { + if v15 == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - - buff.WriteInt(*zz) // write int - + buff.WriteInt(*v15) } } // --- [end][write][map](map[string]*int) --- - } } // --- [end][write][slice]([]map[string]*int) --- - } } // --- [end][write][slice]([][]map[string]*int) --- - } // --- [end][write][alias](shared.DoubleSlice) --- @@ -811,301 +765,254 @@ func (target *Parent) UnmarshalBinaryWithContext(ctx *DecodingContext) (err erro return fmt.Errorf("Invalid Version Unmarshalling Parent. Expected %d or less, got %d", DefaultCodecVersion, version) } + var v0 *shared.Name if buff.ReadUInt8() == uint8(0) { - target.Name = nil + v0 = nil } else { // --- [begin][read][alias](shared.Name) --- - var a string - var c string + var v1 string if ctx.IsStringTable() { - d := buff.ReadInt() // read string index - c = ctx.Table.At(d) + v2 := buff.ReadInt() // read string index + v1 = ctx.Table.At(v2) } else { - c = buff.ReadString() // read string + v1 = buff.ReadString() // read string } - b := c - a = b - - e := shared.Name(a) - target.Name = &e + v3 := shared.Name(v1) + v0 = &v3 // --- [end][read][alias](shared.Name) --- } - + target.Name = v0 + var v4 *shared.Age if buff.ReadUInt8() == uint8(0) { - target.Age = nil + v4 = nil } else { // --- [begin][read][alias](shared.Age) --- - var f *int + var v5 *int if buff.ReadUInt8() == uint8(0) { - f = nil + v5 = nil } else { - - g := buff.ReadInt() // read int - f = &g - + v6 := buff.ReadInt() + v5 = &v6 } - h := shared.Age(f) - target.Age = &h + v7 := shared.Age(v5) + v4 = &v7 // --- [end][read][alias](shared.Age) --- } - + target.Age = v4 + var v8 Child // --- [begin][read][alias](Child) --- - var l string - var n string + var v9 string if ctx.IsStringTable() { - o := buff.ReadInt() // read string index - n = ctx.Table.At(o) + v10 := buff.ReadInt() // read string index + v9 = ctx.Table.At(v10) } else { - n = buff.ReadString() // read string + v9 = buff.ReadString() // read string } - m := n - l = m - - target.FirstChild = Child(l) + v8 = Child(v9) // --- [end][read][alias](Child) --- - + target.FirstChild = v8 + var v11 ChildInfo // --- [begin][read][alias](ChildInfo) --- - var p *Info + var v12 *Info if buff.ReadUInt8() == uint8(0) { - p = nil + v12 = nil } else { // --- [begin][read][struct](Info) --- - q := new(Info) + v13 := new(Info) buff.ReadInt() // [compatibility, unused] - errA := q.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v14 := v13.UnmarshalBinaryWithContext(ctx) + if v14 != nil { + return v14 } - p = q + v12 = v13 // --- [end][read][struct](Info) --- - } - - target.FirstChildInfo = ChildInfo(p) + v11 = ChildInfo(v12) // --- [end][read][alias](ChildInfo) --- - + target.FirstChildInfo = v11 + var v15 []Child if buff.ReadUInt8() == uint8(0) { - target.Children = nil + v15 = nil } else { // --- [begin][read][slice]([]Child) --- - s := buff.ReadInt() // slice len - r := make([]Child, s) - for i := range s { + v16 := buff.ReadInt() // slice len + v15 = make([]Child, v16) + for v17 := range v16 { + var v18 Child // --- [begin][read][alias](Child) --- - var u string - var x string + var v19 string if ctx.IsStringTable() { - y := buff.ReadInt() // read string index - x = ctx.Table.At(y) + v20 := buff.ReadInt() // read string index + v19 = ctx.Table.At(v20) } else { - x = buff.ReadString() // read string + v19 = buff.ReadString() // read string } - w := x - u = w - - t := Child(u) + v18 = Child(v19) // --- [end][read][alias](Child) --- - - r[i] = t + v15[v17] = v18 } - target.Children = r // --- [end][read][slice]([]Child) --- - } - + target.Children = v15 + var v21 OtherChildInfo // --- [begin][read][alias](OtherChildInfo) --- - var aa []ChildInfo + var v22 []ChildInfo if buff.ReadUInt8() == uint8(0) { - aa = nil + v22 = nil } else { // --- [begin][read][slice]([]ChildInfo) --- - cc := buff.ReadInt() // slice len - bb := make([]ChildInfo, cc) - for j := range cc { + v23 := buff.ReadInt() // slice len + v22 = make([]ChildInfo, v23) + for v24 := range v23 { + var v25 ChildInfo // --- [begin][read][alias](ChildInfo) --- - var ee *Info + var v26 *Info if buff.ReadUInt8() == uint8(0) { - ee = nil + v26 = nil } else { // --- [begin][read][struct](Info) --- - ff := new(Info) + v27 := new(Info) buff.ReadInt() // [compatibility, unused] - errB := ff.UnmarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v28 := v27.UnmarshalBinaryWithContext(ctx) + if v28 != nil { + return v28 } - ee = ff + v26 = v27 // --- [end][read][struct](Info) --- - } - - dd := ChildInfo(ee) + v25 = ChildInfo(v26) // --- [end][read][alias](ChildInfo) --- - - bb[j] = dd + v22[v24] = v25 } - aa = bb // --- [end][read][slice]([]ChildInfo) --- - } - - target.ChildrenInfo = OtherChildInfo(aa) + v21 = OtherChildInfo(v22) // --- [end][read][alias](OtherChildInfo) --- - + target.ChildrenInfo = v21 + var v29 shared.FloatList // --- [begin][read][alias](shared.FloatList) --- - var gg []float64 + var v30 []float64 if buff.ReadUInt8() == uint8(0) { - gg = nil + v30 = nil } else { // --- [begin][read][slice]([]float64) --- - ll := buff.ReadInt() // slice len - hh := make([]float64, ll) - for ii := range ll { - var mm float64 - nn := buff.ReadFloat64() // read float64 - mm = nn - - hh[ii] = mm + v31 := buff.ReadInt() // slice len + v30 = make([]float64, v31) + for v32 := range v31 { + var v33 float64 + v33 = buff.ReadFloat64() + v30[v32] = v33 } - gg = hh // --- [end][read][slice]([]float64) --- - } - - target.FavoriteNumbers = shared.FloatList(gg) + v29 = shared.FloatList(v30) // --- [end][read][alias](shared.FloatList) --- - + target.FavoriteNumbers = v29 + var v34 shared.StrMap // --- [begin][read][alias](shared.StrMap) --- - var oo map[string]int + var v35 map[string]int if buff.ReadUInt8() == uint8(0) { - oo = nil + v35 = nil } else { // --- [begin][read][map](map[string]int) --- - qq := buff.ReadInt() // map len - pp := make(map[string]int, qq) - for range qq { - var v string - var ss string + v36 := buff.ReadInt() // map len + v35 = make(map[string]int, v36) + for range v36 { + var v37 string if ctx.IsStringTable() { - tt := buff.ReadInt() // read string index - ss = ctx.Table.At(tt) + v38 := buff.ReadInt() // read string index + v37 = ctx.Table.At(v38) } else { - ss = buff.ReadString() // read string + v37 = buff.ReadString() // read string } - rr := ss - v = rr - - var z int - uu := buff.ReadInt() // read int - z = uu - - pp[v] = z + var v39 int + v39 = buff.ReadInt() + v35[v37] = v39 } - oo = pp // --- [end][read][map](map[string]int) --- - } - - target.NameMap = shared.StrMap(oo) + v34 = shared.StrMap(v35) // --- [end][read][alias](shared.StrMap) --- - + target.NameMap = v34 + var v40 shared.UIntPtrList // --- [begin][read][alias](shared.UIntPtrList) --- - var ww []*uint32 + var v41 []*uint32 if buff.ReadUInt8() == uint8(0) { - ww = nil + v41 = nil } else { // --- [begin][read][slice]([]*uint32) --- - yy := buff.ReadInt() // slice len - xx := make([]*uint32, yy) - for jj := range yy { - var aaa *uint32 + v42 := buff.ReadInt() // slice len + v41 = make([]*uint32, v42) + for v43 := range v42 { + var v44 *uint32 if buff.ReadUInt8() == uint8(0) { - aaa = nil + v44 = nil } else { - - bbb := buff.ReadUInt32() // read uint32 - aaa = &bbb - + v45 := buff.ReadUInt32() + v44 = &v45 } - - xx[jj] = aaa + v41[v43] = v44 } - ww = xx // --- [end][read][slice]([]*uint32) --- - } - - target.U32s = shared.UIntPtrList(ww) + v40 = shared.UIntPtrList(v41) // --- [end][read][alias](shared.UIntPtrList) --- - + target.U32s = v40 + var v46 shared.DoubleSlice // --- [begin][read][alias](shared.DoubleSlice) --- - var ccc [][]map[string]*int + var v47 [][]map[string]*int if buff.ReadUInt8() == uint8(0) { - ccc = nil + v47 = nil } else { // --- [begin][read][slice]([][]map[string]*int) --- - eee := buff.ReadInt() // slice len - ddd := make([][]map[string]*int, eee) - for iii := range eee { - var fff []map[string]*int + v48 := buff.ReadInt() // slice len + v47 = make([][]map[string]*int, v48) + for v49 := range v48 { + var v50 []map[string]*int if buff.ReadUInt8() == uint8(0) { - fff = nil + v50 = nil } else { // --- [begin][read][slice]([]map[string]*int) --- - hhh := buff.ReadInt() // slice len - ggg := make([]map[string]*int, hhh) - for jjj := range hhh { - var lll map[string]*int + v51 := buff.ReadInt() // slice len + v50 = make([]map[string]*int, v51) + for v52 := range v51 { + var v53 map[string]*int if buff.ReadUInt8() == uint8(0) { - lll = nil + v53 = nil } else { // --- [begin][read][map](map[string]*int) --- - nnn := buff.ReadInt() // map len - mmm := make(map[string]*int, nnn) - for range nnn { - var vv string - var ppp string + v54 := buff.ReadInt() // map len + v53 = make(map[string]*int, v54) + for range v54 { + var v55 string if ctx.IsStringTable() { - qqq := buff.ReadInt() // read string index - ppp = ctx.Table.At(qqq) + v56 := buff.ReadInt() // read string index + v55 = ctx.Table.At(v56) } else { - ppp = buff.ReadString() // read string + v55 = buff.ReadString() // read string } - ooo := ppp - vv = ooo - - var zz *int + var v57 *int if buff.ReadUInt8() == uint8(0) { - zz = nil + v57 = nil } else { - - rrr := buff.ReadInt() // read int - zz = &rrr - + v58 := buff.ReadInt() + v57 = &v58 } - mmm[vv] = zz + v53[v55] = v57 } - lll = mmm // --- [end][read][map](map[string]*int) --- - } - - ggg[jjj] = lll + v50[v52] = v53 } - fff = ggg // --- [end][read][slice]([]map[string]*int) --- - } - - ddd[iii] = fff + v47[v49] = v50 } - ccc = ddd // --- [end][read][slice]([][]map[string]*int) --- - } - - target.Slices = shared.DoubleSlice(ccc) + v46 = shared.DoubleSlice(v47) // --- [end][read][alias](shared.DoubleSlice) --- + target.Slices = v46 return nil } @@ -1171,26 +1078,22 @@ func (stream *ParentStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstream return } } else { - // --- [begin][read][streaming-alias](shared.Name) --- - - var a string - var c string + var v0 *shared.Name + // --- [begin][read][alias](shared.Name) --- + var v1 string if ctx.IsStringTable() { - d := buff.ReadInt() // read string index - c = ctx.Table.At(d) + v2 := buff.ReadInt() // read string index + v1 = ctx.Table.At(v2) } else { - c = buff.ReadString() // read string + v1 = buff.ReadString() // read string } - b := c - a = b - - e := shared.Name(a) - if !yield(fi, bstream.SingleV(&e)) { + v3 := shared.Name(v1) + v0 = &v3 + // --- [end][read][alias](shared.Name) --- + if !yield(fi, bstream.SingleV(v0)) { return } - // --- [end][read][streaming-alias](shared.Name) --- } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[*shared.Age](), Name: "Age", @@ -1200,75 +1103,66 @@ func (stream *ParentStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstream return } } else { - // --- [begin][read][streaming-alias](shared.Age) --- - - var f *int + var v4 *shared.Age + // --- [begin][read][alias](shared.Age) --- + var v5 *int if buff.ReadUInt8() == uint8(0) { - f = nil + v5 = nil } else { - - g := buff.ReadInt() // read int - f = &g - + v6 := buff.ReadInt() + v5 = &v6 } - h := shared.Age(f) - if !yield(fi, bstream.SingleV(&h)) { + v7 := shared.Age(v5) + v4 = &v7 + // --- [end][read][alias](shared.Age) --- + if !yield(fi, bstream.SingleV(v4)) { return } - // --- [end][read][streaming-alias](shared.Age) --- } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[Child](), Name: "FirstChild", } - // --- [begin][read][streaming-alias](Child) --- - - var l string - var n string + var v8 Child + // --- [begin][read][alias](Child) --- + var v9 string if ctx.IsStringTable() { - o := buff.ReadInt() // read string index - n = ctx.Table.At(o) + v10 := buff.ReadInt() // read string index + v9 = ctx.Table.At(v10) } else { - n = buff.ReadString() // read string + v9 = buff.ReadString() // read string } - m := n - l = m - - if !yield(fi, bstream.SingleV(Child(l))) { + v8 = Child(v9) + // --- [end][read][alias](Child) --- + if !yield(fi, bstream.SingleV(v8)) { return } - // --- [end][read][streaming-alias](Child) --- - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[ChildInfo](), Name: "FirstChildInfo", } - // --- [begin][read][streaming-alias](ChildInfo) --- - - var p *Info + var v11 ChildInfo + // --- [begin][read][alias](ChildInfo) --- + var v12 *Info if buff.ReadUInt8() == uint8(0) { - p = nil + v12 = nil } else { // --- [begin][read][struct](Info) --- - q := new(Info) + v13 := new(Info) buff.ReadInt() // [compatibility, unused] - errA := q.UnmarshalBinaryWithContext(ctx) - if errA != nil { - stream.err = errA + v14 := v13.UnmarshalBinaryWithContext(ctx) + if v14 != nil { + stream.err = v14 return - } - p = q + v12 = v13 // --- [end][read][struct](Info) --- - } - - if !yield(fi, bstream.SingleV(ChildInfo(p))) { + v11 = ChildInfo(v12) + // --- [end][read][alias](ChildInfo) --- + if !yield(fi, bstream.SingleV(v11)) { return } - // --- [end][read][streaming-alias](ChildInfo) --- - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[[]Child](), Name: "Children", @@ -1279,212 +1173,159 @@ func (stream *ParentStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstream } } else { // --- [begin][read][streaming-slice]([]Child) --- - r := buff.ReadInt() // slice len - for i := range r { - + v15 := buff.ReadInt() // slice len + for v16 := range v15 { + var v17 Child // --- [begin][read][alias](Child) --- - var t string - var w string + var v18 string if ctx.IsStringTable() { - x := buff.ReadInt() // read string index - w = ctx.Table.At(x) + v19 := buff.ReadInt() // read string index + v18 = ctx.Table.At(v19) } else { - w = buff.ReadString() // read string + v18 = buff.ReadString() // read string } - u := w - t = u - - s := Child(t) + v17 = Child(v18) // --- [end][read][alias](Child) --- - - if !yield(fi, bstream.PairV(i, s)) { + if !yield(fi, bstream.PairV(v16, v17)) { return } } // --- [end][read][streaming-slice]([]Child) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[OtherChildInfo](), Name: "ChildrenInfo", } - // --- [begin][read][streaming-alias](OtherChildInfo) --- // --- [begin][read][streaming-slice]([]ChildInfo) --- - y := buff.ReadInt() // slice len - for j := range y { - + v20 := buff.ReadInt() // slice len + for v21 := range v20 { + var v22 ChildInfo // --- [begin][read][alias](ChildInfo) --- - var bb *Info + var v23 *Info if buff.ReadUInt8() == uint8(0) { - bb = nil + v23 = nil } else { // --- [begin][read][struct](Info) --- - cc := new(Info) + v24 := new(Info) buff.ReadInt() // [compatibility, unused] - errB := cc.UnmarshalBinaryWithContext(ctx) - if errB != nil { - stream.err = errB + v25 := v24.UnmarshalBinaryWithContext(ctx) + if v25 != nil { + stream.err = v25 return - } - bb = cc + v23 = v24 // --- [end][read][struct](Info) --- - } - - aa := ChildInfo(bb) + v22 = ChildInfo(v23) // --- [end][read][alias](ChildInfo) --- - - if !yield(fi, bstream.PairV(j, aa)) { + if !yield(fi, bstream.PairV(v21, v22)) { return } } // --- [end][read][streaming-slice]([]ChildInfo) --- - // --- [end][read][streaming-alias](OtherChildInfo) --- - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[shared.FloatList](), Name: "FavoriteNumbers", } - // --- [begin][read][streaming-alias](shared.FloatList) --- // --- [begin][read][streaming-slice]([]float64) --- - dd := buff.ReadInt() // slice len - for ii := range dd { - - var ee float64 - ff := buff.ReadFloat64() // read float64 - ee = ff - - if !yield(fi, bstream.PairV(ii, ee)) { + v26 := buff.ReadInt() // slice len + for v27 := range v26 { + var v28 float64 + v28 = buff.ReadFloat64() + if !yield(fi, bstream.PairV(v27, v28)) { return } } // --- [end][read][streaming-slice]([]float64) --- - // --- [end][read][streaming-alias](shared.FloatList) --- - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[shared.StrMap](), Name: "NameMap", } - // --- [begin][read][streaming-alias](shared.StrMap) --- // --- [begin][read][streaming-map](map[string]int) --- - gg := buff.ReadInt() // map len - for range gg { - var v string - var ll string + v29 := buff.ReadInt() // map len + for range v29 { + var v30 string if ctx.IsStringTable() { - mm := buff.ReadInt() // read string index - ll = ctx.Table.At(mm) + v31 := buff.ReadInt() // read string index + v30 = ctx.Table.At(v31) } else { - ll = buff.ReadString() // read string + v30 = buff.ReadString() // read string } - hh := ll - v = hh - - var z int - nn := buff.ReadInt() // read int - z = nn - - if !yield(fi, bstream.PairV(v, z)) { + var v32 int + v32 = buff.ReadInt() + if !yield(fi, bstream.PairV(v30, v32)) { return } } // --- [end][read][streaming-map](map[string]int) --- - - // --- [end][read][streaming-alias](shared.StrMap) --- - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[shared.UIntPtrList](), Name: "U32s", } - // --- [begin][read][streaming-alias](shared.UIntPtrList) --- // --- [begin][read][streaming-slice]([]*uint32) --- - oo := buff.ReadInt() // slice len - for jj := range oo { - - var pp *uint32 + v33 := buff.ReadInt() // slice len + for v34 := range v33 { + var v35 *uint32 if buff.ReadUInt8() == uint8(0) { - pp = nil + v35 = nil } else { - - qq := buff.ReadUInt32() // read uint32 - pp = &qq - + v36 := buff.ReadUInt32() + v35 = &v36 } - - if !yield(fi, bstream.PairV(jj, pp)) { + if !yield(fi, bstream.PairV(v34, v35)) { return } } // --- [end][read][streaming-slice]([]*uint32) --- - // --- [end][read][streaming-alias](shared.UIntPtrList) --- - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[shared.DoubleSlice](), Name: "Slices", } - // --- [begin][read][streaming-alias](shared.DoubleSlice) --- // --- [begin][read][streaming-slice]([][]map[string]*int) --- - rr := buff.ReadInt() // slice len - for iii := range rr { - - var ss []map[string]*int + v37 := buff.ReadInt() // slice len + for v38 := range v37 { + var v39 []map[string]*int if buff.ReadUInt8() == uint8(0) { - ss = nil + v39 = nil } else { // --- [begin][read][slice]([]map[string]*int) --- - uu := buff.ReadInt() // slice len - tt := make([]map[string]*int, uu) - for jjj := range uu { - var ww map[string]*int + v40 := buff.ReadInt() // slice len + v39 = make([]map[string]*int, v40) + for v41 := range v40 { + var v42 map[string]*int if buff.ReadUInt8() == uint8(0) { - ww = nil + v42 = nil } else { // --- [begin][read][map](map[string]*int) --- - yy := buff.ReadInt() // map len - xx := make(map[string]*int, yy) - for range yy { - var vv string - var bbb string + v43 := buff.ReadInt() // map len + v42 = make(map[string]*int, v43) + for range v43 { + var v44 string if ctx.IsStringTable() { - ccc := buff.ReadInt() // read string index - bbb = ctx.Table.At(ccc) + v45 := buff.ReadInt() // read string index + v44 = ctx.Table.At(v45) } else { - bbb = buff.ReadString() // read string + v44 = buff.ReadString() // read string } - aaa := bbb - vv = aaa - - var zz *int + var v46 *int if buff.ReadUInt8() == uint8(0) { - zz = nil + v46 = nil } else { - - ddd := buff.ReadInt() // read int - zz = &ddd - + v47 := buff.ReadInt() + v46 = &v47 } - xx[vv] = zz + v42[v44] = v46 } - ww = xx // --- [end][read][map](map[string]*int) --- - } - - tt[jjj] = ww + v39[v41] = v42 } - ss = tt // --- [end][read][slice]([]map[string]*int) --- - } - - if !yield(fi, bstream.PairV(iii, ss)) { + if !yield(fi, bstream.PairV(v38, v39)) { return } } // --- [end][read][streaming-slice]([][]map[string]*int) --- - // --- [end][read][streaming-alias](shared.DoubleSlice) --- - } } diff --git a/tests/aliasnil/aliasnil.go b/tests/aliasnil/aliasnil.go new file mode 100644 index 0000000..27b92ee --- /dev/null +++ b/tests/aliasnil/aliasnil.go @@ -0,0 +1,13 @@ +package aliasnil + +// Tags is an alias whose underlying type (a slice) is nilable. It exercises the +// alias-of-nilable path: the nil-flag byte must be written and read symmetrically. +type Tags []string + +// Holder embeds a Tags field between two scalars so any nil-flag misalignment +// corrupts the trailing field. +type Holder struct { + Name string + Tags Tags + Count int +} diff --git a/tests/aliasnil/aliasnil_codecs.go b/tests/aliasnil/aliasnil_codecs.go new file mode 100644 index 0000000..95117c2 --- /dev/null +++ b/tests/aliasnil/aliasnil_codecs.go @@ -0,0 +1,469 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package aliasnil + +import ( + "fmt" + "io" + "os" + "sync" + + "reflect" + "strings" + + stringtable "github.com/opencost/bingen/pkg/table" + util "github.com/opencost/bingen/pkg/util" +) + +const ( + // GeneratorPackageName is the package the generator is targetting + GeneratorPackageName string = "aliasnil" + + // DefaultCodecVersion is used for any resources listed in the Default version set + DefaultCodecVersion uint8 = 1 +) + +//-------------------------------------------------------------------------- +// Configuration +//-------------------------------------------------------------------------- + +var ( + bingenConfigLock sync.RWMutex + bingenConfig *BingenConfiguration = DefaultBingenConfiguration() +) + +// BingenConfiguration is used to set any custom configuration in the way files are encoded +// or decoded. +type BingenConfiguration struct { + // FileBackedStringTableEnabled enables the use of file-backed string tables for streaming + // bingen decoding. + FileBackedStringTableEnabled bool + + // FileBackedStringTableDir is the directory to write the string table files for reading. + FileBackedStringTableDir string + + // FileBackedStringTableMemoMaxBytes limits in-memory memoization for file-backed table lookups. + // 0 disables memoization. + FileBackedStringTableMemoMaxBytes int64 +} + +// DefaultBingenConfiguration creates the default implementation of the bingen configuration +// and returns it. +func DefaultBingenConfiguration() *BingenConfiguration { + return &BingenConfiguration{ + FileBackedStringTableEnabled: false, + FileBackedStringTableDir: os.TempDir(), + FileBackedStringTableMemoMaxBytes: 0, + } +} + +// ConfigureBingen accepts a new *BingenConfiguration instance which updates the internal decoder +// and encoder behavior. +func ConfigureBingen(config *BingenConfiguration) { + bingenConfigLock.Lock() + defer bingenConfigLock.Unlock() + + if config == nil { + config = DefaultBingenConfiguration() + } + bingenConfig = config +} + +// IsBingenFileBackedStringTableEnabled accessor for file backed string table configuration +func IsBingenFileBackedStringTableEnabled() bool { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableEnabled +} + +// BingenFileBackedStringTableDir returns the directory configured for file backed string tables. +func BingenFileBackedStringTableDir() string { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableDir +} + +// BingenFileBackedStringTableMemoMaxBytes returns the maximum bytes used for file-backed memo cache. +func BingenFileBackedStringTableMemoMaxBytes() int64 { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableMemoMaxBytes +} + +//-------------------------------------------------------------------------- +// Type Map +//-------------------------------------------------------------------------- + +// Generated type map for resolving interface implementations to to concrete types +var typeMap map[string]reflect.Type = map[string]reflect.Type{ + "Holder": reflect.TypeFor[Holder](), +} + +//-------------------------------------------------------------------------- +// Type Helpers +//-------------------------------------------------------------------------- + +// isBinaryTag returns true when the first bytes in the provided binary matches the tag +func isBinaryTag(data []byte, tag string) bool { + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// isReaderBinaryTag is used to peek the header for an io.Reader Buffer +func isReaderBinaryTag(buff *util.Buffer, tag string) bool { + data, err := buff.Peek(len(tag)) + if err != nil && err != io.EOF { + panic(fmt.Sprintf("called Peek() on a non buffered reader: %s", err)) + } + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// typeToString determines the basic properties of the type, the qualifier, package path, and +// type name, and returns the qualified type +func typeToString(f interface{}) string { + qual := "" + t := reflect.TypeOf(f) + if t.Kind() == reflect.Ptr { + t = t.Elem() + qual = "*" + } + + return fmt.Sprintf("%s%s.%s", qual, t.PkgPath(), t.Name()) +} + +// resolveType uses the name of a type and returns the package, base type name, and whether +// or not it's a pointer. +func resolveType(t string) (pkg string, name string, isPtr bool) { + isPtr = t[:1] == "*" + if isPtr { + t = t[1:] + } + + slashIndex := strings.LastIndex(t, "/") + if slashIndex >= 0 { + t = t[slashIndex+1:] + } + parts := strings.Split(t, ".") + if parts[0] == GeneratorPackageName { + parts[0] = "" + } + + pkg = parts[0] + name = parts[1] + return +} + +//-------------------------------------------------------------------------- +// Codec Context +//-------------------------------------------------------------------------- + +// EncodingContext is a context object passed to the encoders to ensure reuse of buffer +// and table data +type EncodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableWriter +} + +// NewEncodingContext creates a new EncodingContext instance that will create a new []byte buffer +// for writing, and return the context +func NewEncodingContext(tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBuffer(), + Table: tableWriter, + } +} + +// NewEncodingContextFromWriter creates a new EncodingContext instance that will create a new Buffer +// from the provided io.Writer and StringTableWriter. +func NewEncodingContextFromWriter(writer io.Writer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBufferFromWriter(writer), + Table: tableWriter, + } +} + +// NewEncodingContextFromBuffer creates a new EncodingContext instance that will leverage an existing +// Buffer and StringTableWriter. +func NewEncodingContextFromBuffer(buffer *util.Buffer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: buffer, + Table: tableWriter, + } +} + +// ToBytes returns the encoded string table bytes (if applicable) combined with the encoded buffer bytes. If +// a string table is being used, the string table bytes will be written first to ensure correct ordering for +// decoding. +func (ec *EncodingContext) ToBytes() []byte { + encBytes := ec.Buffer.Bytes() + if ec.Table != nil { + buff := util.NewBuffer() + ec.Table.WriteTo(buff) + buff.WriteBytes(encBytes) + return buff.Bytes() + } + + return encBytes +} + +// IsStringTable returns true if the table is available +func (ec *EncodingContext) IsStringTable() bool { + return ec.Table != nil +} + +// DecodingContext is a context object passed to the decoders to ensure parent objects +// reuse as much data as possible +type DecodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableReader +} + +// NewDecodingContextFromBytes creates a new DecodingContext instance using an byte slice +func NewDecodingContextFromBytes(data []byte) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromBytes(data) + + // string table header validation + if isBinaryTag(data, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // always use a slice string table with a byte array since the + // data is already in memory + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// NewDecodingContextFromReader creates a new DecodingContext instance using an io.Reader +// implementation +func NewDecodingContextFromReader(reader io.Reader) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromReader(reader) + + if isReaderBinaryTag(buff, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // create correct string table implementation + if IsBingenFileBackedStringTableEnabled() { + table = stringtable.NewFileStringTableReaderFrom(buff, BingenFileBackedStringTableDir(), GeneratorPackageName, BingenFileBackedStringTableMemoMaxBytes()) + } else { + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// IsStringTable returns true if the table is available +func (dc *DecodingContext) IsStringTable() bool { + return dc.Table != nil && dc.Table.Len() > 0 +} + +// Close will ensure that any string table resources and buffer resources are +// cleaned up. +func (dc *DecodingContext) Close() { + if dc.Table != nil { + _ = dc.Table.Close() + dc.Table = nil + } +} + +//-------------------------------------------------------------------------- +// Binary Codec +//-------------------------------------------------------------------------- + +// BinEncoder is an encoding interface which defines a context based marshal contract. +type BinEncoder interface { + MarshalBinaryWithContext(*EncodingContext) error +} + +// BinDecoder is a decoding interface which defines a context based unmarshal contract. +type BinDecoder interface { + UnmarshalBinaryWithContext(*DecodingContext) error +} + +//-------------------------------------------------------------------------- +// Holder +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Holder instance +// into a byte array +func (target *Holder) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(nil) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Holder instance +// into an io.Writer. +func (target *Holder) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + ctx := NewEncodingContextFromBuffer(buff, nil) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Holder instance +// into a byte array leveraging a predefined context. +func (target *Holder) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + if ctx.IsStringTable() { + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) + } else { + buff.WriteString(target.Name) + } + if []string(target.Tags) == nil { + buff.WriteUInt8(uint8(0)) + } else { + buff.WriteUInt8(uint8(1)) + buff.WriteInt(len([]string(target.Tags))) + for v1 := range []string(target.Tags) { + if ctx.IsStringTable() { + v2 := ctx.Table.AddOrGet([]string(target.Tags)[v1]) + buff.WriteInt(v2) + } else { + buff.WriteString([]string(target.Tags)[v1]) + } + } + } + buff.WriteInt(target.Count) + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Holder type +func (target *Holder) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Holder type +func (target *Holder) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Holder type +func (target *Holder) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Holder. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 string + if ctx.IsStringTable() { + v1 := buff.ReadInt() + v0 = ctx.Table.At(v1) + } else { + v0 = buff.ReadString() + } + target.Name = v0 + var v2 Tags + var v3 []string + if buff.ReadUInt8() == uint8(0) { + v3 = nil + } else { + v4 := buff.ReadInt() + v3 = make([]string, v4) + for v5 := range v4 { + var v6 string + if ctx.IsStringTable() { + v7 := buff.ReadInt() + v6 = ctx.Table.At(v7) + } else { + v6 = buff.ReadString() + } + v3[v5] = v6 + } + } + v2 = Tags(v3) + target.Tags = v2 + var v8 int + v8 = buff.ReadInt() + target.Count = v8 + + return nil +} diff --git a/tests/aliasnil/bingen.go b/tests/aliasnil/bingen.go new file mode 100644 index 0000000..a859797 --- /dev/null +++ b/tests/aliasnil/bingen.go @@ -0,0 +1,4 @@ +package aliasnil + +// @bingen:generate:Tags +// @bingen:generate:Holder diff --git a/tests/container/container_codecs.go b/tests/container/container_codecs.go index cf40ea1..f5bd88b 100644 --- a/tests/container/container_codecs.go +++ b/tests/container/container_codecs.go @@ -358,33 +358,28 @@ func (target *Container) MarshalBinaryWithContext(ctx *EncodingContext) (err err buff.WriteUInt8(ContainerExampleCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Name) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Name) // write string } - if target.Children == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Children)) // slice length - for i := range target.Children { + for v1 := range target.Children { if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(target.Children[i]) - buff.WriteInt(b) // write table index + v2 := ctx.Table.AddOrGet(target.Children[v1]) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(target.Children[i]) // write string + buff.WriteString(target.Children[v1]) // write string } - } // --- [end][write][slice]([]string) --- - } - - buff.WriteFloat64(target.Value) // write float64 + buff.WriteFloat64(target.Value) return nil } @@ -440,43 +435,37 @@ func (target *Container) UnmarshalBinaryWithContext(ctx *DecodingContext) (err e return fmt.Errorf("Invalid Version Unmarshalling Container. Expected %d or less, got %d", ContainerExampleCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Name = a - + target.Name = v0 + var v2 []string if buff.ReadUInt8() == uint8(0) { - target.Children = nil + v2 = nil } else { // --- [begin][read][slice]([]string) --- - e := buff.ReadInt() // slice len - d := make([]string, e) - for i := range e { - var f string - var h string + v3 := buff.ReadInt() // slice len + v2 = make([]string, v3) + for v4 := range v3 { + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - f = g - - d[i] = f + v2[v4] = v5 } - target.Children = d // --- [end][read][slice]([]string) --- - } - - m := buff.ReadFloat64() // read float64 - target.Value = m + target.Children = v2 + var v7 float64 + v7 = buff.ReadFloat64() + target.Value = v7 return nil } diff --git a/tests/containerv2/containerv2_codecs.go b/tests/containerv2/containerv2_codecs.go index ef393d8..5b799f0 100644 --- a/tests/containerv2/containerv2_codecs.go +++ b/tests/containerv2/containerv2_codecs.go @@ -386,41 +386,33 @@ func (target *Container) MarshalBinaryWithContext(ctx *EncodingContext) (err err buff.WriteUInt8(ContainerExampleCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Name) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Name) // write string } - if target.Children == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Children)) // slice length - for i := range target.Children { + for v1 := range target.Children { if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(target.Children[i]) - buff.WriteInt(b) // write table index + v2 := ctx.Table.AddOrGet(target.Children[v1]) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(target.Children[i]) // write string + buff.WriteString(target.Children[v1]) // write string } - } // --- [end][write][slice]([]string) --- - } - - buff.WriteFloat64(target.oldValue) // write float64 - + buff.WriteFloat64(target.oldValue) if target.Value == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - - buff.WriteFloat64(*target.Value) // write float64 - + buff.WriteFloat64(*target.Value) } return nil @@ -477,55 +469,46 @@ func (target *Container) UnmarshalBinaryWithContext(ctx *DecodingContext) (err e return fmt.Errorf("Invalid Version Unmarshalling Container. Expected %d or less, got %d", ContainerExampleCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Name = a - + target.Name = v0 + var v2 []string if buff.ReadUInt8() == uint8(0) { - target.Children = nil + v2 = nil } else { // --- [begin][read][slice]([]string) --- - e := buff.ReadInt() // slice len - d := make([]string, e) - for i := range e { - var f string - var h string + v3 := buff.ReadInt() // slice len + v2 = make([]string, v3) + for v4 := range v3 { + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - f = g - - d[i] = f + v2[v4] = v5 } - target.Children = d // --- [end][read][slice]([]string) --- - } - - m := buff.ReadFloat64() // read float64 - target.oldValue = m - - // field version check + target.Children = v2 + var v7 float64 + v7 = buff.ReadFloat64() + target.oldValue = v7 if uint8(2) <= version { + var v8 *float64 if buff.ReadUInt8() == uint8(0) { - target.Value = nil + v8 = nil } else { - - n := buff.ReadFloat64() // read float64 - target.Value = &n - + v9 := buff.ReadFloat64() + v8 = &v9 } - + target.Value = v8 } else { target.Value = nil } @@ -594,21 +577,16 @@ func (stream *ContainerStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstr Type: reflect.TypeFor[string](), Name: "Name", } - - var a string - var c string + var v0 string if ctx.IsStringTable() { - d := buff.ReadInt() // read string index - c = ctx.Table.At(d) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - c = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - b := c - a = b - if !yield(fi, bstream.SingleV(a)) { + if !yield(fi, bstream.SingleV(v0)) { return } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[[]string](), Name: "Children", @@ -619,64 +597,48 @@ func (stream *ContainerStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstr } } else { // --- [begin][read][streaming-slice]([]string) --- - e := buff.ReadInt() // slice len - for i := range e { - - var f string - var h string + v2 := buff.ReadInt() // slice len + for v3 := range v2 { + var v4 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v5 := buff.ReadInt() // read string index + v4 = ctx.Table.At(v5) } else { - h = buff.ReadString() // read string + v4 = buff.ReadString() // read string } - g := h - f = g - - if !yield(fi, bstream.PairV(i, f)) { + if !yield(fi, bstream.PairV(v3, v4)) { return } } // --- [end][read][streaming-slice]([]string) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[float64](), Name: "oldValue", } - - var m float64 - n := buff.ReadFloat64() // read float64 - m = n - if !yield(fi, bstream.SingleV(m)) { + var v6 float64 + v6 = buff.ReadFloat64() + if !yield(fi, bstream.SingleV(v6)) { return } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[*float64](), Name: "Value", } - // field version check if uint8(2) <= version { - if buff.ReadUInt8() == uint8(0) { if !yield(fi, nil) { return } } else { - - var o *float64 - p := buff.ReadFloat64() // read float64 - o = &p - if !yield(fi, bstream.SingleV(o)) { + var v7 *float64 + v8 := buff.ReadFloat64() + v7 = &v8 + if !yield(fi, bstream.SingleV(v7)) { return } - } - } else { - if !yield(fi, nil) { return } diff --git a/tests/generator_test.go b/tests/generator_test.go index 981d4a5..67c39f5 100644 --- a/tests/generator_test.go +++ b/tests/generator_test.go @@ -9,7 +9,8 @@ import ( "sync" "testing" - "github.com/opencost/bingen/internal/generator" + "github.com/opencost/bingen/internal/generator/golang" + javagen "github.com/opencost/bingen/internal/generator/java" "github.com/opencost/bingen/internal/types" ) @@ -87,10 +88,32 @@ func runGenerator(dir string, pkg string) error { return err } - generator.Generate(dir, pkg, BinGenUtil, tc) + golang.Generate(dir, pkg, BinGenUtil, tc) return nil } +func runJavaGenerator(dir string, pkg string) error { + codecPath := filepath.Join(dir, "java") + _ = os.RemoveAll(codecPath) + + tc, err := types.LoadTypes(dir, pkg, V) + if err != nil { + return err + } + + conf, err := javagen.FromConfig(pkg, map[string]string{ + javagen.OptBasePackage: "com.opencost", + javagen.OptOutputDir: codecPath, + }) + if err != nil { + return err + } + + conf.GoPackage = pkg + + return javagen.Generate(dir, tc, conf) +} + func TestGenerateAliasBinCodecs(t *testing.T) { td := getTestDir() @@ -121,6 +144,11 @@ func TestGenerateOpencostBinCodecs(t *testing.T) { if err != nil { t.Errorf("\n%s", err) } + + err = runJavaGenerator(filepath.Join(td, "opencost"), "opencost") + if err != nil { + t.Errorf("\n%s", err) + } } func TestGenerateFailingBinCodecs(t *testing.T) { diff --git a/tests/opencost/java/com/bingen/BinDecoder.java b/tests/opencost/java/com/bingen/BinDecoder.java new file mode 100644 index 0000000..44337a3 --- /dev/null +++ b/tests/opencost/java/com/bingen/BinDecoder.java @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * Decodes a value of type {@code T} from a {@link DecodingContext}. + */ +public interface BinDecoder { + T decode(DecodingContext ctx); +} diff --git a/tests/opencost/java/com/bingen/BinEncoder.java b/tests/opencost/java/com/bingen/BinEncoder.java new file mode 100644 index 0000000..468d28b --- /dev/null +++ b/tests/opencost/java/com/bingen/BinEncoder.java @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * Encodes a value of type {@code T} into an {@link EncodingContext}. + */ +public interface BinEncoder { + void encode(T value, EncodingContext ctx); +} diff --git a/tests/opencost/java/com/bingen/BingenConsumer.java b/tests/opencost/java/com/bingen/BingenConsumer.java new file mode 100644 index 0000000..169532e --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenConsumer.java @@ -0,0 +1,19 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * Receives each streamed field (and each flattened collection element). Return + * {@code false} to stop streaming early, mirroring go's yield contract. A null + * {@link BingenValue} indicates a nil field value. + */ +@FunctionalInterface +public interface BingenConsumer { + boolean accept(BingenFieldInfo field, BingenValue value); +} diff --git a/tests/opencost/java/com/bingen/BingenElement.java b/tests/opencost/java/com/bingen/BingenElement.java new file mode 100644 index 0000000..d4f8f8d --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenElement.java @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * One pulled stream element: the field it belongs to and its value (which is + * null for a nil field, and carries an index/key for flattened collections). + */ +public record BingenElement(BingenFieldInfo field, BingenValue value) { +} diff --git a/tests/opencost/java/com/bingen/BingenFieldInfo.java b/tests/opencost/java/com/bingen/BingenFieldInfo.java new file mode 100644 index 0000000..4d2462a --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenFieldInfo.java @@ -0,0 +1,13 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** Describes the struct field currently being streamed. */ +public record BingenFieldInfo(String name) { +} diff --git a/tests/opencost/java/com/bingen/BingenPullStream.java b/tests/opencost/java/com/bingen/BingenPullStream.java new file mode 100644 index 0000000..6f601ba --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenPullStream.java @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.concurrent.SynchronousQueue; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * Adapts a push streamer ({@code Streamer::stream}) into a pull + * {@link Iterable}/{@link Stream} of {@link BingenElement}. The push streamer + * runs on a virtual thread and hands each element across a {@link + * SynchronousQueue}, so exactly one element is in flight — the producer blocks + * until the consumer pulls, matching go's cooperative streaming. + * + *

Single use. Always close it (try-with-resources) if you do not iterate to + * the end, otherwise the producer virtual thread is left parked. + */ +public final class BingenPullStream implements Iterable, AutoCloseable { + + private static final Object DONE = new Object(); + private static final Object FAIL = new Object(); + + private final SynchronousQueue queue = new SynchronousQueue<>(); + private volatile boolean closed; + private volatile Throwable error; + private final Thread producer; + + private BingenPullStream(InputStream in, BingenStreamFn fn) { + this.producer = Thread.ofVirtual().name("bingen-pull-stream").start(() -> run(in, fn)); + } + + /** Creates a pull stream driving the push streamer over an in-memory payload. */ + public static BingenPullStream of(byte[] data, BingenStreamFn fn) { + return new BingenPullStream(new ByteArrayInputStream(data), fn); + } + + /** + * Creates a pull stream driving the push streamer over a stream read + * incrementally (socket, file, ...). The caller retains ownership of the + * stream. + */ + public static BingenPullStream of(InputStream in, BingenStreamFn fn) { + return new BingenPullStream(in, fn); + } + + private void run(InputStream in, BingenStreamFn fn) { + try { + fn.stream(in, (fi, value) -> { + if (closed) { + return false; + } + try { + queue.put(new BingenElement(fi, value)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + return !closed; + }); + if (!closed) { + queue.put(DONE); + } + } catch (InterruptedException e) { + // interrupted during the terminal handoff while closing; nothing to do. + } catch (Throwable t) { + error = t; + if (!closed) { + try { + queue.put(FAIL); + } catch (InterruptedException ignored) { + Thread.currentThread().interrupt(); + } + } + } + } + + @Override + public Iterator iterator() { + return new Iterator<>() { + private BingenElement next; + private boolean done; + + @Override + public boolean hasNext() { + if (done) { + return false; + } + if (next != null) { + return true; + } + Object msg; + try { + msg = queue.take(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + done = true; + return false; + } + if (msg == DONE) { + done = true; + return false; + } + if (msg == FAIL) { + done = true; + throw new BingenStreamException(error); + } + next = (BingenElement) msg; + return true; + } + + @Override + public BingenElement next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + BingenElement element = next; + next = null; + return element; + } + }; + } + + /** A sequential {@link Stream}; closing it closes this pull stream. */ + public Stream stream() { + Spliterator spliterator = + Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED); + return StreamSupport.stream(spliterator, false).onClose(this::close); + } + + @Override + public void close() { + closed = true; + producer.interrupt(); + } +} diff --git a/tests/opencost/java/com/bingen/BingenStreamException.java b/tests/opencost/java/com/bingen/BingenStreamException.java new file mode 100644 index 0000000..6155266 --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenStreamException.java @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** Wraps an error thrown by the underlying push streamer during pull iteration. */ +public final class BingenStreamException extends RuntimeException { + public BingenStreamException(Throwable cause) { + super(cause); + } +} diff --git a/tests/opencost/java/com/bingen/BingenStreamFn.java b/tests/opencost/java/com/bingen/BingenStreamFn.java new file mode 100644 index 0000000..4438ef2 --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenStreamFn.java @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.io.InputStream; + +/** + * A generated {@code Streamer.stream(InputStream, BingenConsumer)} entry + * point, so a push streamer can be adapted into a pull stream (see {@link + * BingenPullStream}). + */ +@FunctionalInterface +public interface BingenStreamFn { + void stream(InputStream in, BingenConsumer consumer); +} diff --git a/tests/opencost/java/com/bingen/BingenValue.java b/tests/opencost/java/com/bingen/BingenValue.java new file mode 100644 index 0000000..955ebad --- /dev/null +++ b/tests/opencost/java/com/bingen/BingenValue.java @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * A streamed value, optionally carrying the index or key it had within a + * flattened collection. + */ +public record BingenValue(Object value, Object index) { + + /** A single value with no index or key. */ + public static BingenValue single(Object value) { + return new BingenValue(value, null); + } + + /** One element of a flattened slice or map, with its index or key. */ + public static BingenValue pair(Object index, Object value) { + return new BingenValue(value, index); + } +} diff --git a/tests/opencost/java/com/bingen/DecodingContext.java b/tests/opencost/java/com/bingen/DecodingContext.java new file mode 100644 index 0000000..67b8e6d --- /dev/null +++ b/tests/opencost/java/com/bingen/DecodingContext.java @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.io.InputStream; + +/** + * Carries the read buffer and optional string table shared across a single + * decode or stream pass. + */ +public final class DecodingContext { + + private static final byte[] STRING_TABLE_TAG = {'B', 'G', 'S', 'T'}; + + private final ReadBuffer buffer; + private final StringTableReader table; + + private DecodingContext(ReadBuffer buffer, StringTableReader table) { + this.buffer = buffer; + this.table = table; + } + + /** Creates a context over an in-memory payload. */ + public static DecodingContext fromBytes(byte[] data) { + return from(ReadBuffer.fromBytes(data)); + } + + /** + * Creates a context that consumes the stream incrementally (socket, file, + * etc). The caller retains ownership of the stream. + */ + public static DecodingContext fromStream(InputStream in) { + return from(ReadBuffer.fromStream(in)); + } + + // When the payload begins with the BGST tag, the string table is loaded + // first and the buffer is left positioned at the value payload. + private static DecodingContext from(ReadBuffer buffer) { + StringTableReader table = null; + if (buffer.startsWith(STRING_TABLE_TAG)) { + buffer.readBytes(STRING_TABLE_TAG.length); // strip the tag + table = StringTableReader.from(buffer); + } + return new DecodingContext(buffer, table); + } + + /** The read buffer the decoders consume from. */ + public ReadBuffer buffer() { + return buffer; + } + + /** The string table, or null when string-table decoding is inactive. */ + public StringTableReader table() { + return table; + } + + /** Whether string-table decoding is active. */ + public boolean isStringTable() { + return table != null && table.len() > 0; + } +} diff --git a/tests/opencost/java/com/bingen/EncodingContext.java b/tests/opencost/java/com/bingen/EncodingContext.java new file mode 100644 index 0000000..62e8941 --- /dev/null +++ b/tests/opencost/java/com/bingen/EncodingContext.java @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * Carries the write buffer and optional string table shared across a single + * encode pass. + */ +public final class EncodingContext { + + private final WriteBuffer buffer; + private final StringTableWriter table; + + private EncodingContext(WriteBuffer buffer, StringTableWriter table) { + this.buffer = buffer; + this.table = table; + } + + /** Creates a context backed by a fresh write buffer with no string table. */ + public static EncodingContext create() { + return new EncodingContext(WriteBuffer.create(), null); + } + + /** Creates a context whose string fields are indexed into a string table. */ + public static EncodingContext withStringTable() { + return new EncodingContext(WriteBuffer.create(), new StringTableWriter()); + } + + /** The write buffer the encoders emit into. */ + public WriteBuffer buffer() { + return buffer; + } + + /** The string table, or null when string-table encoding is inactive. */ + public StringTableWriter table() { + return table; + } + + /** Whether string-table encoding is active. */ + public boolean isStringTable() { + return table != null; + } + + /** + * Returns the fully-encoded payload. When a string table is active, it is + * written (with its tag) ahead of the payload. + */ + public byte[] toBytes() { + byte[] payload = buffer.bytes(); + if (table == null) { + return payload; + } + WriteBuffer out = WriteBuffer.create(); + table.writeTo(out); + out.writeBytes(payload); + return out.bytes(); + } +} diff --git a/tests/opencost/java/com/bingen/GoTime.java b/tests/opencost/java/com/bingen/GoTime.java new file mode 100644 index 0000000..72a6c41 --- /dev/null +++ b/tests/opencost/java/com/bingen/GoTime.java @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +/** + * Encodes/decodes a go {@code time.Time} the way bingen wraps it: a length + * prefix (little-endian, via the buffers) followed by the payload of go's own + * {@code time.Time.MarshalBinary}, which is big-endian. + * + *

The payload preserves the instant and the zone offset (not a named zone), + * so it maps to {@link OffsetDateTime}. A zero offset is written as go's UTC + * sentinel (-1 minutes); a genuine fixed +00:00 zone that is not UTC is the only + * value that will not re-encode byte-for-byte, and its instant is still exact. + */ +public final class GoTime { + + // Seconds between Jan 1, year 1 (go's absolute epoch) and the unix epoch. + private static final long UNIX_TO_INTERNAL = 62135596800L; + + private GoTime() { + } + + /** Writes the length-prefixed go time payload. */ + public static void encode(OffsetDateTime t, WriteBuffer buff) { + byte[] payload = marshal(t); + buff.writeInt(payload.length); + buff.writeBytes(payload); + } + + /** Reads a length-prefixed go time payload. */ + public static OffsetDateTime decode(ReadBuffer buff) { + int len = buff.readInt(); + return unmarshal(buff.readBytes(len)); + } + + static byte[] marshal(OffsetDateTime t) { + Instant instant = t.toInstant(); + long sec = instant.getEpochSecond() + UNIX_TO_INTERNAL; + int nsec = instant.getNano(); + int offset = t.getOffset().getTotalSeconds(); + + int version = 1; + int offsetSec = 0; + int offsetMin; + if (offset == 0) { + offsetMin = -1; // UTC sentinel + } else { + if (offset % 60 != 0) { + version = 2; + offsetSec = offset % 60; + } + offsetMin = offset / 60; + } + + byte[] enc = new byte[version == 2 ? 16 : 15]; + enc[0] = (byte) version; + putLongBE(enc, 1, sec); + putIntBE(enc, 9, nsec); + putShortBE(enc, 13, offsetMin); + if (version == 2) { + enc[15] = (byte) offsetSec; + } + return enc; + } + + static OffsetDateTime unmarshal(byte[] b) { + int version = b[0]; + if (version != 1 && version != 2) { + throw new IllegalArgumentException("GoTime: unsupported version " + version); + } + long sec = getLongBE(b, 1); + int nsec = getIntBE(b, 9); + int offsetMin = getShortBE(b, 13); + + ZoneOffset zone; + if (offsetMin == -1) { + zone = ZoneOffset.UTC; + } else { + int total = offsetMin * 60; + if (version == 2) { + total += b[15]; // signed sub-minute seconds + } + zone = ZoneOffset.ofTotalSeconds(total); + } + + return Instant.ofEpochSecond(sec - UNIX_TO_INTERNAL, nsec).atOffset(zone); + } + + //-------------------------------------------------------------------------- + // Big Endian Helpers + //-------------------------------------------------------------------------- + + private static void putLongBE(byte[] b, int off, long v) { + for (int i = 0; i < 8; i++) { + b[off + i] = (byte) (v >>> (56 - 8 * i)); + } + } + + private static long getLongBE(byte[] b, int off) { + long v = 0; + for (int i = 0; i < 8; i++) { + v = (v << 8) | (b[off + i] & 0xFFL); + } + return v; + } + + private static void putIntBE(byte[] b, int off, int v) { + b[off] = (byte) (v >>> 24); + b[off + 1] = (byte) (v >>> 16); + b[off + 2] = (byte) (v >>> 8); + b[off + 3] = (byte) v; + } + + private static int getIntBE(byte[] b, int off) { + return ((b[off] & 0xFF) << 24) + | ((b[off + 1] & 0xFF) << 16) + | ((b[off + 2] & 0xFF) << 8) + | (b[off + 3] & 0xFF); + } + + private static void putShortBE(byte[] b, int off, int v) { + b[off] = (byte) (v >>> 8); + b[off + 1] = (byte) v; + } + + private static int getShortBE(byte[] b, int off) { + return (short) (((b[off] & 0xFF) << 8) | (b[off + 1] & 0xFF)); + } +} diff --git a/tests/opencost/java/com/bingen/ReadBuffer.java b/tests/opencost/java/com/bingen/ReadBuffer.java new file mode 100644 index 0000000..9ad2660 --- /dev/null +++ b/tests/opencost/java/com/bingen/ReadBuffer.java @@ -0,0 +1,213 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.BufferUnderflowException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/** + * Little-endian binary read buffer over an {@link InputStream}. Backing the + * buffer with a stream (rather than a byte array) is what lets decoders and + * streamers consume data incrementally from a socket or file. + * + *

Not thread-safe. + */ +public final class ReadBuffer { + + private final InputStream in; + + private ReadBuffer(InputStream in) { + this.in = in; + } + + /** + * Creates a read buffer that takes ownership of the provided byte array. + * The caller must not modify the array after this call. + */ + public static ReadBuffer fromBytes(byte[] bytes) { + return new ReadBuffer(new ByteArrayInputStream(bytes)); + } + + /** + * Creates a read buffer that consumes the stream incrementally. The stream is + * wrapped so it supports the small look-ahead used for header detection; the + * caller retains ownership and is responsible for closing it. + */ + public static ReadBuffer fromStream(InputStream stream) { + InputStream in = stream.markSupported() ? stream : new BufferedInputStream(stream); + return new ReadBuffer(in); + } + + /** + * Creates a read buffer from all bytes written to the given {@link WriteBuffer}. + */ + public static ReadBuffer from(WriteBuffer wb) { + return fromBytes(wb.bytes()); + } + + // ------------------------------------------------------------------------- + // Read API + // ------------------------------------------------------------------------- + + public boolean readBool() { + return readRawByte() != 0; + } + + /** Reads a 32-bit signed integer (same as readInt32). */ + public int readInt() { + return readInt32(); + } + + public byte readInt8() { + return readRawByte(); + } + + public short readInt16() { + byte b0 = readRawByte(); + byte b1 = readRawByte(); + return (short) ((b0 & 0xFF) | ((b1 & 0xFF) << 8)); + } + + public int readInt32() { + byte b0 = readRawByte(); + byte b1 = readRawByte(); + byte b2 = readRawByte(); + byte b3 = readRawByte(); + return (b0 & 0xFF) | ((b1 & 0xFF) << 8) | ((b2 & 0xFF) << 16) | ((b3 & 0xFF) << 24); + } + + public long readInt64() { + byte b0 = readRawByte(); + byte b1 = readRawByte(); + byte b2 = readRawByte(); + byte b3 = readRawByte(); + byte b4 = readRawByte(); + byte b5 = readRawByte(); + byte b6 = readRawByte(); + byte b7 = readRawByte(); + return (b0 & 0xFFL) + | ((b1 & 0xFFL) << 8) + | ((b2 & 0xFFL) << 16) + | ((b3 & 0xFFL) << 24) + | ((b4 & 0xFFL) << 32) + | ((b5 & 0xFFL) << 40) + | ((b6 & 0xFFL) << 48) + | ((b7 & 0xFFL) << 56); + } + + /** Reads a 32-bit unsigned value, returned as a long. */ + public long readUInt() { + return readInt32() & 0xFFFFFFFFL; + } + + /** Reads an 8-bit unsigned value (0–255), returned as int. */ + public int readUInt8() { + return readRawByte() & 0xFF; + } + + /** Reads a 16-bit unsigned value (0–65535), returned as int. */ + public int readUInt16() { + return readInt16() & 0xFFFF; + } + + /** Reads a 32-bit unsigned value (0–4294967295), returned as long. */ + public long readUInt32() { + return readInt32() & 0xFFFFFFFFL; + } + + /** Reads a 64-bit unsigned value (same bit pattern as signed long). */ + public long readUInt64() { + return readInt64(); + } + + public float readFloat32() { + return Float.intBitsToFloat(readInt32()); + } + + public double readFloat64() { + return Double.longBitsToDouble(readInt64()); + } + + /** + * Reads a uint16 length prefix, then reads exactly that many UTF-8 bytes and + * returns the decoded string. + */ + public String readString() { + int len = readUInt16(); + byte[] strBytes = readBytes(len); + return new String(strBytes, StandardCharsets.UTF_8); + } + + /** Reads exactly {@code length} bytes from the buffer. */ + public byte[] readBytes(int length) { + byte[] result = new byte[length]; + int remaining = length; + int pos = 0; + while (remaining > 0) { + int n; + try { + n = in.read(result, pos, remaining); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + if (n < 0) { + throw new BufferUnderflowException(); + } + pos += n; + remaining -= n; + } + return result; + } + + /** + * Returns true if the next bytes match {@code tag} without consuming them. + * Used to detect the optional string-table header. + */ + public boolean startsWith(byte[] tag) { + try { + in.mark(tag.length); + byte[] head = new byte[tag.length]; + int pos = 0; + while (pos < tag.length) { + int n = in.read(head, pos, tag.length - pos); + if (n < 0) { + break; + } + pos += n; + } + in.reset(); + return pos == tag.length && Arrays.equals(head, tag); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + // ------------------------------------------------------------------------- + // Internal helpers + // ------------------------------------------------------------------------- + + private byte readRawByte() { + int b; + try { + b = in.read(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + if (b < 0) { + throw new BufferUnderflowException(); + } + return (byte) b; + } +} diff --git a/tests/opencost/java/com/bingen/StringTableReader.java b/tests/opencost/java/com/bingen/StringTableReader.java new file mode 100644 index 0000000..c5326ff --- /dev/null +++ b/tests/opencost/java/com/bingen/StringTableReader.java @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +/** + * Pre-loaded string table providing index-based lookup, mirroring the go + * slice-backed reader. + */ +public final class StringTableReader { + + private final String[] table; + + private StringTableReader(String[] table) { + this.table = table; + } + + /** + * Reads the string count followed by that many strings from the buffer, + * which must be positioned immediately after the {@code BGST} tag. + */ + public static StringTableReader from(ReadBuffer buff) { + int count = buff.readInt(); + String[] table = new String[count]; + for (int i = 0; i < count; i++) { + table[i] = buff.readString(); + } + return new StringTableReader(table); + } + + /** Returns the string at {@code index}. */ + public String at(int index) { + return table[index]; + } + + /** Returns the number of strings in the table. */ + public int len() { + return table.length; + } +} diff --git a/tests/opencost/java/com/bingen/StringTableWriter.java b/tests/opencost/java/com/bingen/StringTableWriter.java new file mode 100644 index 0000000..1d77d93 --- /dev/null +++ b/tests/opencost/java/com/bingen/StringTableWriter.java @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Assigns each distinct string an insertion-ordered index and writes the table, + * prefixed with the {@code BGST} tag, ahead of the payload. + */ +public final class StringTableWriter { + + private static final byte[] TAG = {'B', 'G', 'S', 'T'}; + + private final Map indices = new LinkedHashMap<>(); + private int next = 0; + + /** Returns the existing index for {@code s}, or assigns and returns a new one. */ + public int addOrGet(String s) { + Integer existing = indices.get(s); + if (existing != null) { + return existing; + } + int current = next++; + indices.put(s, current); + return current; + } + + /** Writes the tag, the string count, and each string in index order. */ + public void writeTo(WriteBuffer buff) { + buff.writeBytes(TAG); + + String[] ordered = new String[next]; + for (Map.Entry entry : indices.entrySet()) { + ordered[entry.getValue()] = entry.getKey(); + } + + buff.writeInt(ordered.length); + for (String s : ordered) { + buff.writeString(s); + } + } +} diff --git a/tests/opencost/java/com/bingen/WriteBuffer.java b/tests/opencost/java/com/bingen/WriteBuffer.java new file mode 100644 index 0000000..ce727a5 --- /dev/null +++ b/tests/opencost/java/com/bingen/WriteBuffer.java @@ -0,0 +1,130 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.bingen; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; + +/** + * Little-endian binary write buffer backed by a {@link ByteArrayOutputStream}. + * + *

Not thread-safe. + */ +public final class WriteBuffer { + private static final int MAX_STRING_BYTES = 0xFFFF; + + private final ByteArrayOutputStream bos; + + private WriteBuffer() { + this.bos = new ByteArrayOutputStream(64); + } + + /** Creates a new empty write buffer. */ + public static WriteBuffer create() { + return new WriteBuffer(); + } + + // ------------------------------------------------------------------------- + // Write API + // ------------------------------------------------------------------------- + + public void writeBool(boolean v) { + bos.write(v ? 1 : 0); + } + + /** Writes a 32-bit signed integer (same as writeInt32). */ + public void writeInt(int v) { + writeInt32(v); + } + + public void writeInt8(byte v) { + bos.write(v); + } + + public void writeInt16(short v) { + bos.write(v & 0xFF); + bos.write((v >>> 8) & 0xFF); + } + + public void writeInt32(int v) { + bos.write(v & 0xFF); + bos.write((v >>> 8) & 0xFF); + bos.write((v >>> 16) & 0xFF); + bos.write((v >>> 24) & 0xFF); + } + + public void writeInt64(long v) { + bos.write((int) (v & 0xFF)); + bos.write((int) ((v >>> 8) & 0xFF)); + bos.write((int) ((v >>> 16) & 0xFF)); + bos.write((int) ((v >>> 24) & 0xFF)); + bos.write((int) ((v >>> 32) & 0xFF)); + bos.write((int) ((v >>> 40) & 0xFF)); + bos.write((int) ((v >>> 48) & 0xFF)); + bos.write((int) ((v >>> 56) & 0xFF)); + } + + /** Writes a 32-bit unsigned value (accepts long to cover full 0–4294967295 range). */ + public void writeUInt(long v) { + writeInt32((int) (v & 0xFFFFFFFFL)); + } + + /** Writes an 8-bit unsigned value (0–255). */ + public void writeUInt8(int v) { + bos.write(v); + } + + /** Writes a 16-bit unsigned value (0–65535). */ + public void writeUInt16(int v) { + writeInt16((short) (v & 0xFFFF)); + } + + /** Writes a 32-bit unsigned value. */ + public void writeUInt32(long v) { + writeInt32((int) (v & 0xFFFFFFFFL)); + } + + /** Writes a 64-bit unsigned value (same bit pattern as signed long). */ + public void writeUInt64(long v) { + writeInt64(v); + } + + public void writeFloat32(float v) { + writeInt32(Float.floatToRawIntBits(v)); + } + + public void writeFloat64(double v) { + writeInt64(Double.doubleToRawLongBits(v)); + } + + /** + * Writes the string as a uint16 length prefix followed by UTF-8 bytes. + * Strings longer than 65535 bytes are silently truncated at the byte boundary. + */ + public void writeString(String s) { + byte[] strBytes = s.getBytes(StandardCharsets.UTF_8); + int len = Math.min(strBytes.length, MAX_STRING_BYTES); + writeUInt16(len); + bos.write(strBytes, 0, len); + } + + /** Writes the raw byte array contents into the buffer. */ + public void writeBytes(byte[] bytes) { + bos.write(bytes, 0, bytes.length); + } + + // ------------------------------------------------------------------------- + // Utility + // ------------------------------------------------------------------------- + + /** Returns a copy of all bytes written so far. */ + public byte[] bytes() { + return bos.toByteArray(); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Allocation.java b/tests/opencost/java/com/opencost/opencost/Allocation.java new file mode 100644 index 0000000..381dcd5 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Allocation.java @@ -0,0 +1,186 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code Allocation} go struct. + */ +public record Allocation(String name, AllocationProperties properties, Window window, OffsetDateTime start, OffsetDateTime end, double cPUCoreHours, double cPUCoreRequestAverage, double cPUCoreUsageAverage, double cPUCost, double cPUCostAdjustment, double gPUHours, double gPUCost, double gPUCostAdjustment, double networkTransferBytes, double networkReceiveBytes, double networkCost, double networkCostAdjustment, double loadBalancerCost, double loadBalancerCostAdjustment, Map pVs, double pVCostAdjustment, double rAMByteHours, double rAMBytesRequestAverage, double rAMBytesUsageAverage, double rAMCost, double rAMCostAdjustment, double sharedCost, double externalCost, RawAllocationOnlyData rawAllocationOnly, int testProperty, String testStr) { + + /** Creates a new builder for {@link Allocation}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private String name; + private AllocationProperties properties; + private Window window; + private OffsetDateTime start; + private OffsetDateTime end; + private double cPUCoreHours; + private double cPUCoreRequestAverage; + private double cPUCoreUsageAverage; + private double cPUCost; + private double cPUCostAdjustment; + private double gPUHours; + private double gPUCost; + private double gPUCostAdjustment; + private double networkTransferBytes; + private double networkReceiveBytes; + private double networkCost; + private double networkCostAdjustment; + private double loadBalancerCost; + private double loadBalancerCostAdjustment; + private Map pVs; + private double pVCostAdjustment; + private double rAMByteHours; + private double rAMBytesRequestAverage; + private double rAMBytesUsageAverage; + private double rAMCost; + private double rAMCostAdjustment; + private double sharedCost; + private double externalCost; + private RawAllocationOnlyData rawAllocationOnly; + private int testProperty; + private String testStr; + public Builder name(String name) { + this.name = name; + return this; + } + public Builder properties(AllocationProperties properties) { + this.properties = properties; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder cPUCoreHours(double cPUCoreHours) { + this.cPUCoreHours = cPUCoreHours; + return this; + } + public Builder cPUCoreRequestAverage(double cPUCoreRequestAverage) { + this.cPUCoreRequestAverage = cPUCoreRequestAverage; + return this; + } + public Builder cPUCoreUsageAverage(double cPUCoreUsageAverage) { + this.cPUCoreUsageAverage = cPUCoreUsageAverage; + return this; + } + public Builder cPUCost(double cPUCost) { + this.cPUCost = cPUCost; + return this; + } + public Builder cPUCostAdjustment(double cPUCostAdjustment) { + this.cPUCostAdjustment = cPUCostAdjustment; + return this; + } + public Builder gPUHours(double gPUHours) { + this.gPUHours = gPUHours; + return this; + } + public Builder gPUCost(double gPUCost) { + this.gPUCost = gPUCost; + return this; + } + public Builder gPUCostAdjustment(double gPUCostAdjustment) { + this.gPUCostAdjustment = gPUCostAdjustment; + return this; + } + public Builder networkTransferBytes(double networkTransferBytes) { + this.networkTransferBytes = networkTransferBytes; + return this; + } + public Builder networkReceiveBytes(double networkReceiveBytes) { + this.networkReceiveBytes = networkReceiveBytes; + return this; + } + public Builder networkCost(double networkCost) { + this.networkCost = networkCost; + return this; + } + public Builder networkCostAdjustment(double networkCostAdjustment) { + this.networkCostAdjustment = networkCostAdjustment; + return this; + } + public Builder loadBalancerCost(double loadBalancerCost) { + this.loadBalancerCost = loadBalancerCost; + return this; + } + public Builder loadBalancerCostAdjustment(double loadBalancerCostAdjustment) { + this.loadBalancerCostAdjustment = loadBalancerCostAdjustment; + return this; + } + public Builder pVs(Map pVs) { + this.pVs = pVs; + return this; + } + public Builder pVCostAdjustment(double pVCostAdjustment) { + this.pVCostAdjustment = pVCostAdjustment; + return this; + } + public Builder rAMByteHours(double rAMByteHours) { + this.rAMByteHours = rAMByteHours; + return this; + } + public Builder rAMBytesRequestAverage(double rAMBytesRequestAverage) { + this.rAMBytesRequestAverage = rAMBytesRequestAverage; + return this; + } + public Builder rAMBytesUsageAverage(double rAMBytesUsageAverage) { + this.rAMBytesUsageAverage = rAMBytesUsageAverage; + return this; + } + public Builder rAMCost(double rAMCost) { + this.rAMCost = rAMCost; + return this; + } + public Builder rAMCostAdjustment(double rAMCostAdjustment) { + this.rAMCostAdjustment = rAMCostAdjustment; + return this; + } + public Builder sharedCost(double sharedCost) { + this.sharedCost = sharedCost; + return this; + } + public Builder externalCost(double externalCost) { + this.externalCost = externalCost; + return this; + } + public Builder rawAllocationOnly(RawAllocationOnlyData rawAllocationOnly) { + this.rawAllocationOnly = rawAllocationOnly; + return this; + } + public Builder testProperty(int testProperty) { + this.testProperty = testProperty; + return this; + } + public Builder testStr(String testStr) { + this.testStr = testStr; + return this; + } + + public Allocation build() { + return new Allocation(name, properties, window, start, end, cPUCoreHours, cPUCoreRequestAverage, cPUCoreUsageAverage, cPUCost, cPUCostAdjustment, gPUHours, gPUCost, gPUCostAdjustment, networkTransferBytes, networkReceiveBytes, networkCost, networkCostAdjustment, loadBalancerCost, loadBalancerCostAdjustment, pVs, pVCostAdjustment, rAMByteHours, rAMBytesRequestAverage, rAMBytesUsageAverage, rAMCost, rAMCostAdjustment, sharedCost, externalCost, rawAllocationOnly, testProperty, testStr); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java new file mode 100644 index 0000000..d03cd7d --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java @@ -0,0 +1,190 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link Allocation}. + */ +public final class AllocationDecoder implements BinDecoder { + + public static final AllocationDecoder INSTANCE = new AllocationDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Allocation} from a standalone byte array. */ + public static Allocation fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Allocation} read incrementally from a stream. */ + public static Allocation fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Allocation decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Allocation: expected " + VERSION + " or less, got " + version); + } + + Allocation.Builder builder = Allocation.builder(); + String v0; + if (ctx.isStringTable()) { + v0 = ctx.table().at(buff.readInt()); // string table index + } else { + v0 = buff.readString(); // read string + } + builder.name(v0); + AllocationProperties v1; + if (buff.readUInt8() == 0) { + v1 = null; + } else { + buff.readInt(); // [compatibility, unused] + v1 = AllocationPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v1); + Window v2; + buff.readInt(); // [compatibility, unused] + v2 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v2); + OffsetDateTime v3; + v3 = GoTime.decode(buff); + builder.start(v3); + OffsetDateTime v4; + v4 = GoTime.decode(buff); + builder.end(v4); + double v5; + v5 = buff.readFloat64(); + builder.cPUCoreHours(v5); + double v6; + v6 = buff.readFloat64(); + builder.cPUCoreRequestAverage(v6); + double v7; + v7 = buff.readFloat64(); + builder.cPUCoreUsageAverage(v7); + double v8; + v8 = buff.readFloat64(); + builder.cPUCost(v8); + double v9; + v9 = buff.readFloat64(); + builder.cPUCostAdjustment(v9); + double v10; + v10 = buff.readFloat64(); + builder.gPUHours(v10); + double v11; + v11 = buff.readFloat64(); + builder.gPUCost(v11); + double v12; + v12 = buff.readFloat64(); + builder.gPUCostAdjustment(v12); + double v13; + v13 = buff.readFloat64(); + builder.networkTransferBytes(v13); + double v14; + v14 = buff.readFloat64(); + builder.networkReceiveBytes(v14); + double v15; + v15 = buff.readFloat64(); + builder.networkCost(v15); + double v16; + v16 = buff.readFloat64(); + builder.networkCostAdjustment(v16); + double v17; + v17 = buff.readFloat64(); + builder.loadBalancerCost(v17); + double v18; + v18 = buff.readFloat64(); + builder.loadBalancerCostAdjustment(v18); + Map v19; + if (buff.readUInt8() == 0) { + v19 = null; + } else { + int v20 = buff.readInt(); // map length + v19 = new LinkedHashMap<>(v20); + for (int v21 = 0; v21 < v20; v21++) { + PVKey v22; + buff.readInt(); // [compatibility, unused] + v22 = PVKeyDecoder.INSTANCE.decode(ctx); + PVAllocation v23; + if (buff.readUInt8() == 0) { + v23 = null; + } else { + buff.readInt(); // [compatibility, unused] + v23 = PVAllocationDecoder.INSTANCE.decode(ctx); + } + v19.put(v22, v23); + } + } + builder.pVs(v19); + double v24; + v24 = buff.readFloat64(); + builder.pVCostAdjustment(v24); + double v25; + v25 = buff.readFloat64(); + builder.rAMByteHours(v25); + double v26; + v26 = buff.readFloat64(); + builder.rAMBytesRequestAverage(v26); + double v27; + v27 = buff.readFloat64(); + builder.rAMBytesUsageAverage(v27); + double v28; + v28 = buff.readFloat64(); + builder.rAMCost(v28); + double v29; + v29 = buff.readFloat64(); + builder.rAMCostAdjustment(v29); + double v30; + v30 = buff.readFloat64(); + builder.sharedCost(v30); + double v31; + v31 = buff.readFloat64(); + builder.externalCost(v31); + RawAllocationOnlyData v32; + if (buff.readUInt8() == 0) { + v32 = null; + } else { + buff.readInt(); // [compatibility, unused] + v32 = RawAllocationOnlyDataDecoder.INSTANCE.decode(ctx); + } + builder.rawAllocationOnly(v32); + if (16 <= version) { + int v33; + v33 = buff.readInt(); + builder.testProperty(v33); + } else { + builder.testProperty(0); + } + if (16 <= version) { + String v34; + if (ctx.isStringTable()) { + v34 = ctx.table().at(buff.readInt()); // string table index + } else { + v34 = buff.readString(); // read string + } + builder.testStr(v34); + } else { + builder.testStr("test"); + } + Allocation result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java b/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java new file mode 100644 index 0000000..78715d4 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java @@ -0,0 +1,108 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link Allocation}. + */ +public final class AllocationEncoder implements BinEncoder { + + public static final AllocationEncoder INSTANCE = new AllocationEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Allocation value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Allocation value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.name())); // string table index + } else { + buff.writeString(value.name()); // string + } + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AllocationPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeFloat64(value.cPUCoreHours()); + buff.writeFloat64(value.cPUCoreRequestAverage()); + buff.writeFloat64(value.cPUCoreUsageAverage()); + buff.writeFloat64(value.cPUCost()); + buff.writeFloat64(value.cPUCostAdjustment()); + buff.writeFloat64(value.gPUHours()); + buff.writeFloat64(value.gPUCost()); + buff.writeFloat64(value.gPUCostAdjustment()); + buff.writeFloat64(value.networkTransferBytes()); + buff.writeFloat64(value.networkReceiveBytes()); + buff.writeFloat64(value.networkCost()); + buff.writeFloat64(value.networkCostAdjustment()); + buff.writeFloat64(value.loadBalancerCost()); + buff.writeFloat64(value.loadBalancerCostAdjustment()); + if (value.pVs() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.pVs().size()); // map length + for (Map.Entry v0 : value.pVs().entrySet()) { + buff.writeInt(0); // [compatibility, unused] + PVKeyEncoder.INSTANCE.encode(v0.getKey(), ctx); + if (v0.getValue() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + PVAllocationEncoder.INSTANCE.encode(v0.getValue(), ctx); + } + } + } + buff.writeFloat64(value.pVCostAdjustment()); + buff.writeFloat64(value.rAMByteHours()); + buff.writeFloat64(value.rAMBytesRequestAverage()); + buff.writeFloat64(value.rAMBytesUsageAverage()); + buff.writeFloat64(value.rAMCost()); + buff.writeFloat64(value.rAMCostAdjustment()); + buff.writeFloat64(value.sharedCost()); + buff.writeFloat64(value.externalCost()); + if (value.rawAllocationOnly() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + RawAllocationOnlyDataEncoder.INSTANCE.encode(value.rawAllocationOnly(), ctx); + } + buff.writeInt(value.testProperty()); + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.testStr())); // string table index + } else { + buff.writeString(value.testStr()); // string + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationProperties.java b/tests/opencost/java/com/opencost/opencost/AllocationProperties.java new file mode 100644 index 0000000..23bf9d7 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationProperties.java @@ -0,0 +1,86 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.List; +import java.util.Map; + +/** + * Generated data type for the {@code AllocationProperties} go struct. + */ +public record AllocationProperties(String cluster, String node, String container, String controller, String controllerKind, String namespace, String pod, List services, String providerID, Map labels, Map annotations) { + + /** Creates a new builder for {@link AllocationProperties}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private String cluster; + private String node; + private String container; + private String controller; + private String controllerKind; + private String namespace; + private String pod; + private List services; + private String providerID; + private Map labels; + private Map annotations; + public Builder cluster(String cluster) { + this.cluster = cluster; + return this; + } + public Builder node(String node) { + this.node = node; + return this; + } + public Builder container(String container) { + this.container = container; + return this; + } + public Builder controller(String controller) { + this.controller = controller; + return this; + } + public Builder controllerKind(String controllerKind) { + this.controllerKind = controllerKind; + return this; + } + public Builder namespace(String namespace) { + this.namespace = namespace; + return this; + } + public Builder pod(String pod) { + this.pod = pod; + return this; + } + public Builder services(List services) { + this.services = services; + return this; + } + public Builder providerID(String providerID) { + this.providerID = providerID; + return this; + } + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder annotations(Map annotations) { + this.annotations = annotations; + return this; + } + + public AllocationProperties build() { + return new AllocationProperties(cluster, node, container, controller, controllerKind, namespace, pod, services, providerID, labels, annotations); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java new file mode 100644 index 0000000..1c6a135 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java @@ -0,0 +1,171 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Generated binary decoder for {@link AllocationProperties}. + */ +public final class AllocationPropertiesDecoder implements BinDecoder { + + public static final AllocationPropertiesDecoder INSTANCE = new AllocationPropertiesDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link AllocationProperties} from a standalone byte array. */ + public static AllocationProperties fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link AllocationProperties} read incrementally from a stream. */ + public static AllocationProperties fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public AllocationProperties decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding AllocationProperties: expected " + VERSION + " or less, got " + version); + } + + AllocationProperties.Builder builder = AllocationProperties.builder(); + String v0; + if (ctx.isStringTable()) { + v0 = ctx.table().at(buff.readInt()); // string table index + } else { + v0 = buff.readString(); // read string + } + builder.cluster(v0); + String v1; + if (ctx.isStringTable()) { + v1 = ctx.table().at(buff.readInt()); // string table index + } else { + v1 = buff.readString(); // read string + } + builder.node(v1); + String v2; + if (ctx.isStringTable()) { + v2 = ctx.table().at(buff.readInt()); // string table index + } else { + v2 = buff.readString(); // read string + } + builder.container(v2); + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + builder.controller(v3); + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + builder.controllerKind(v4); + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + builder.namespace(v5); + String v6; + if (ctx.isStringTable()) { + v6 = ctx.table().at(buff.readInt()); // string table index + } else { + v6 = buff.readString(); // read string + } + builder.pod(v6); + List v7; + if (buff.readUInt8() == 0) { + v7 = null; + } else { + int v8 = buff.readInt(); // slice length + v7 = new ArrayList<>(v8); + for (int v9 = 0; v9 < v8; v9++) { + String v10; + if (ctx.isStringTable()) { + v10 = ctx.table().at(buff.readInt()); // string table index + } else { + v10 = buff.readString(); // read string + } + v7.add(v10); + } + } + builder.services(v7); + String v11; + if (ctx.isStringTable()) { + v11 = ctx.table().at(buff.readInt()); // string table index + } else { + v11 = buff.readString(); // read string + } + builder.providerID(v11); + Map v12; + if (buff.readUInt8() == 0) { + v12 = null; + } else { + int v13 = buff.readInt(); // map length + v12 = new LinkedHashMap<>(v13); + for (int v14 = 0; v14 < v13; v14++) { + String v15; + if (ctx.isStringTable()) { + v15 = ctx.table().at(buff.readInt()); // string table index + } else { + v15 = buff.readString(); // read string + } + String v16; + if (ctx.isStringTable()) { + v16 = ctx.table().at(buff.readInt()); // string table index + } else { + v16 = buff.readString(); // read string + } + v12.put(v15, v16); + } + } + builder.labels(v12); + Map v17; + if (buff.readUInt8() == 0) { + v17 = null; + } else { + int v18 = buff.readInt(); // map length + v17 = new LinkedHashMap<>(v18); + for (int v19 = 0; v19 < v18; v19++) { + String v20; + if (ctx.isStringTable()) { + v20 = ctx.table().at(buff.readInt()); // string table index + } else { + v20 = buff.readString(); // read string + } + String v21; + if (ctx.isStringTable()) { + v21 = ctx.table().at(buff.readInt()); // string table index + } else { + v21 = buff.readString(); // read string + } + v17.put(v20, v21); + } + } + builder.annotations(v17); + AllocationProperties result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationPropertiesEncoder.java b/tests/opencost/java/com/opencost/opencost/AllocationPropertiesEncoder.java new file mode 100644 index 0000000..80abd54 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationPropertiesEncoder.java @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import java.util.Map; + +/** + * Generated binary encoder for {@link AllocationProperties}. + */ +public final class AllocationPropertiesEncoder implements BinEncoder { + + public static final AllocationPropertiesEncoder INSTANCE = new AllocationPropertiesEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(AllocationProperties value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(AllocationProperties value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.cluster())); // string table index + } else { + buff.writeString(value.cluster()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.node())); // string table index + } else { + buff.writeString(value.node()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.container())); // string table index + } else { + buff.writeString(value.container()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.controller())); // string table index + } else { + buff.writeString(value.controller()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.controllerKind())); // string table index + } else { + buff.writeString(value.controllerKind()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.namespace())); // string table index + } else { + buff.writeString(value.namespace()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.pod())); // string table index + } else { + buff.writeString(value.pod()); // string + } + if (value.services() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.services().size()); // slice length + for (String v0 : value.services()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0)); // string table index + } else { + buff.writeString(v0); // string + } + } + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.providerID())); // string table index + } else { + buff.writeString(value.providerID()); // string + } + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v1 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v1.getKey())); // string table index + } else { + buff.writeString(v1.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v1.getValue())); // string table index + } else { + buff.writeString(v1.getValue()); // string + } + } + } + if (value.annotations() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.annotations().size()); // map length + for (Map.Entry v2 : value.annotations().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v2.getKey())); // string table index + } else { + buff.writeString(v2.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v2.getValue())); // string table index + } else { + buff.writeString(v2.getValue()); // string + } + } + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSet.java b/tests/opencost/java/com/opencost/opencost/AllocationSet.java new file mode 100644 index 0000000..3de85a8 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSet.java @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.List; +import java.util.Map; + +/** + * Generated data type for the {@code AllocationSet} go struct. + */ +public record AllocationSet(Map allocations, Map externalKeys, Map idleKeys, String fromSource, Window window, List warnings, List errors) { + + /** Creates a new builder for {@link AllocationSet}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private Map allocations; + private Map externalKeys; + private Map idleKeys; + private String fromSource; + private Window window; + private List warnings; + private List errors; + public Builder allocations(Map allocations) { + this.allocations = allocations; + return this; + } + public Builder externalKeys(Map externalKeys) { + this.externalKeys = externalKeys; + return this; + } + public Builder idleKeys(Map idleKeys) { + this.idleKeys = idleKeys; + return this; + } + public Builder fromSource(String fromSource) { + this.fromSource = fromSource; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder warnings(List warnings) { + this.warnings = warnings; + return this; + } + public Builder errors(List errors) { + this.errors = errors; + return this; + } + + public AllocationSet build() { + return new AllocationSet(allocations, externalKeys, idleKeys, fromSource, window, warnings, errors); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java new file mode 100644 index 0000000..beaaa1a --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java @@ -0,0 +1,159 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Generated binary decoder for {@link AllocationSet}. + */ +public final class AllocationSetDecoder implements BinDecoder { + + public static final AllocationSetDecoder INSTANCE = new AllocationSetDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link AllocationSet} from a standalone byte array. */ + public static AllocationSet fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link AllocationSet} read incrementally from a stream. */ + public static AllocationSet fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public AllocationSet decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding AllocationSet: expected " + VERSION + " or less, got " + version); + } + + AllocationSet.Builder builder = AllocationSet.builder(); + Map v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // map length + v0 = new LinkedHashMap<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + Allocation v4; + if (buff.readUInt8() == 0) { + v4 = null; + } else { + buff.readInt(); // [compatibility, unused] + v4 = AllocationDecoder.INSTANCE.decode(ctx); + } + v0.put(v3, v4); + } + } + builder.allocations(v0); + Map v5; + if (buff.readUInt8() == 0) { + v5 = null; + } else { + int v6 = buff.readInt(); // map length + v5 = new LinkedHashMap<>(v6); + for (int v7 = 0; v7 < v6; v7++) { + String v8; + if (ctx.isStringTable()) { + v8 = ctx.table().at(buff.readInt()); // string table index + } else { + v8 = buff.readString(); // read string + } + boolean v9; + v9 = buff.readBool(); + v5.put(v8, v9); + } + } + builder.externalKeys(v5); + Map v10; + if (buff.readUInt8() == 0) { + v10 = null; + } else { + int v11 = buff.readInt(); // map length + v10 = new LinkedHashMap<>(v11); + for (int v12 = 0; v12 < v11; v12++) { + String v13; + if (ctx.isStringTable()) { + v13 = ctx.table().at(buff.readInt()); // string table index + } else { + v13 = buff.readString(); // read string + } + boolean v14; + v14 = buff.readBool(); + v10.put(v13, v14); + } + } + builder.idleKeys(v10); + String v15; + if (ctx.isStringTable()) { + v15 = ctx.table().at(buff.readInt()); // string table index + } else { + v15 = buff.readString(); // read string + } + builder.fromSource(v15); + Window v16; + buff.readInt(); // [compatibility, unused] + v16 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v16); + List v17; + if (buff.readUInt8() == 0) { + v17 = null; + } else { + int v18 = buff.readInt(); // slice length + v17 = new ArrayList<>(v18); + for (int v19 = 0; v19 < v18; v19++) { + String v20; + if (ctx.isStringTable()) { + v20 = ctx.table().at(buff.readInt()); // string table index + } else { + v20 = buff.readString(); // read string + } + v17.add(v20); + } + } + builder.warnings(v17); + List v21; + if (buff.readUInt8() == 0) { + v21 = null; + } else { + int v22 = buff.readInt(); // slice length + v21 = new ArrayList<>(v22); + for (int v23 = 0; v23 < v22; v23++) { + String v24; + if (ctx.isStringTable()) { + v24 = ctx.table().at(buff.readInt()); // string table index + } else { + v24 = buff.readString(); // read string + } + v21.add(v24); + } + } + builder.errors(v21); + AllocationSet result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java new file mode 100644 index 0000000..e1060b0 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java @@ -0,0 +1,119 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import java.util.Map; + +/** + * Generated binary encoder for {@link AllocationSet}. + */ +public final class AllocationSetEncoder implements BinEncoder { + + public static final AllocationSetEncoder INSTANCE = new AllocationSetEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = true; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(AllocationSet value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(AllocationSet value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.allocations() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.allocations().size()); // map length + for (Map.Entry v0 : value.allocations().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (v0.getValue() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AllocationEncoder.INSTANCE.encode(v0.getValue(), ctx); + } + } + } + if (value.externalKeys() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.externalKeys().size()); // map length + for (Map.Entry v1 : value.externalKeys().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v1.getKey())); // string table index + } else { + buff.writeString(v1.getKey()); // string + } + buff.writeBool(v1.getValue()); + } + } + if (value.idleKeys() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.idleKeys().size()); // map length + for (Map.Entry v2 : value.idleKeys().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v2.getKey())); // string table index + } else { + buff.writeString(v2.getKey()); // string + } + buff.writeBool(v2.getValue()); + } + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.fromSource())); // string table index + } else { + buff.writeString(value.fromSource()); // string + } + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + if (value.warnings() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.warnings().size()); // slice length + for (String v3 : value.warnings()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v3)); // string table index + } else { + buff.writeString(v3); // string + } + } + } + if (value.errors() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.errors().size()); // slice length + for (String v4 : value.errors()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v4)); // string table index + } else { + buff.writeString(v4); // string + } + } + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java b/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java new file mode 100644 index 0000000..c5f94b4 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.List; + +/** + * Generated data type for the {@code AllocationSetRange} go struct. + */ +public record AllocationSetRange(List allocations, String fromStore) { + + /** Creates a new builder for {@link AllocationSetRange}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private List allocations; + private String fromStore; + public Builder allocations(List allocations) { + this.allocations = allocations; + return this; + } + public Builder fromStore(String fromStore) { + this.fromStore = fromStore; + return this; + } + + public AllocationSetRange build() { + return new AllocationSetRange(allocations, fromStore); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java new file mode 100644 index 0000000..b0c2b5d --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Generated binary decoder for {@link AllocationSetRange}. + */ +public final class AllocationSetRangeDecoder implements BinDecoder { + + public static final AllocationSetRangeDecoder INSTANCE = new AllocationSetRangeDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link AllocationSetRange} from a standalone byte array. */ + public static AllocationSetRange fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link AllocationSetRange} read incrementally from a stream. */ + public static AllocationSetRange fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public AllocationSetRange decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding AllocationSetRange: expected " + VERSION + " or less, got " + version); + } + + AllocationSetRange.Builder builder = AllocationSetRange.builder(); + List v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // slice length + v0 = new ArrayList<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + AllocationSet v3; + if (buff.readUInt8() == 0) { + v3 = null; + } else { + buff.readInt(); // [compatibility, unused] + v3 = AllocationSetDecoder.INSTANCE.decode(ctx); + } + v0.add(v3); + } + } + builder.allocations(v0); + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + builder.fromStore(v4); + AllocationSetRange result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetRangeEncoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetRangeEncoder.java new file mode 100644 index 0000000..a95f22b --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetRangeEncoder.java @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link AllocationSetRange}. + */ +public final class AllocationSetRangeEncoder implements BinEncoder { + + public static final AllocationSetRangeEncoder INSTANCE = new AllocationSetRangeEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(AllocationSetRange value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(AllocationSetRange value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.allocations() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.allocations().size()); // slice length + for (AllocationSet v0 : value.allocations()) { + if (v0 == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AllocationSetEncoder.INSTANCE.encode(v0, ctx); + } + } + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.fromStore())); // string table index + } else { + buff.writeString(value.fromStore()); // string + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetStreamer.java b/tests/opencost/java/com/opencost/opencost/AllocationSetStreamer.java new file mode 100644 index 0000000..040e067 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetStreamer.java @@ -0,0 +1,176 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BingenConsumer; +import com.bingen.BingenFieldInfo; +import com.bingen.BingenValue; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * Generated push streamer for {@link AllocationSet}. Each field is delivered to + * the consumer; slices and maps are flattened one depth (one element per call). + * Return false from the consumer to stop early. + */ +public final class AllocationSetStreamer { + + private static final int VERSION = 16; + + private AllocationSetStreamer() { + } + + /** Streams the fields of an encoded {@link AllocationSet} held in memory. */ + public static void stream(byte[] data, BingenConsumer consumer) { + stream(new ByteArrayInputStream(data), consumer); + } + + /** + * Streams the fields of an encoded {@link AllocationSet} read incrementally + * from {@code in} (socket, file, ...). The caller retains ownership of the + * stream and is responsible for closing it. + */ + public static void stream(InputStream in, BingenConsumer consumer) { + DecodingContext ctx = DecodingContext.fromStream(in); + ReadBuffer buff = ctx.buffer(); + + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version streaming AllocationSet: expected " + VERSION + " or less, got " + version); + } + + BingenFieldInfo fi = null; + fi = new BingenFieldInfo("allocations"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v0 = buff.readInt(); + for (int v1 = 0; v1 < v0; v1++) { + String v2; + if (ctx.isStringTable()) { + v2 = ctx.table().at(buff.readInt()); // string table index + } else { + v2 = buff.readString(); // read string + } + Allocation v3; + if (buff.readUInt8() == 0) { + v3 = null; + } else { + buff.readInt(); // [compatibility, unused] + v3 = AllocationDecoder.INSTANCE.decode(ctx); + } + if (!consumer.accept(fi, BingenValue.pair(v2, v3))) { + return; + } + } + } + fi = new BingenFieldInfo("externalKeys"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v4 = buff.readInt(); + for (int v5 = 0; v5 < v4; v5++) { + String v6; + if (ctx.isStringTable()) { + v6 = ctx.table().at(buff.readInt()); // string table index + } else { + v6 = buff.readString(); // read string + } + boolean v7; + v7 = buff.readBool(); + if (!consumer.accept(fi, BingenValue.pair(v6, v7))) { + return; + } + } + } + fi = new BingenFieldInfo("idleKeys"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v8 = buff.readInt(); + for (int v9 = 0; v9 < v8; v9++) { + String v10; + if (ctx.isStringTable()) { + v10 = ctx.table().at(buff.readInt()); // string table index + } else { + v10 = buff.readString(); // read string + } + boolean v11; + v11 = buff.readBool(); + if (!consumer.accept(fi, BingenValue.pair(v10, v11))) { + return; + } + } + } + fi = new BingenFieldInfo("FromSource"); + String v12; + if (ctx.isStringTable()) { + v12 = ctx.table().at(buff.readInt()); // string table index + } else { + v12 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.single(v12))) { + return; + } + fi = new BingenFieldInfo("Window"); + Window v13; + buff.readInt(); // [compatibility, unused] + v13 = WindowDecoder.INSTANCE.decode(ctx); + if (!consumer.accept(fi, BingenValue.single(v13))) { + return; + } + fi = new BingenFieldInfo("Warnings"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v14 = buff.readInt(); + for (int v15 = 0; v15 < v14; v15++) { + String v16; + if (ctx.isStringTable()) { + v16 = ctx.table().at(buff.readInt()); // string table index + } else { + v16 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.pair(v15, v16))) { + return; + } + } + } + fi = new BingenFieldInfo("Errors"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v17 = buff.readInt(); + for (int v18 = 0; v18 < v17; v18++) { + String v19; + if (ctx.isStringTable()) { + v19 = ctx.table().at(buff.readInt()); // string table index + } else { + v19 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.pair(v18, v19))) { + return; + } + } + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Any.java b/tests/opencost/java/com/opencost/opencost/Any.java new file mode 100644 index 0000000..f0a89bd --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Any.java @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code Any} go struct. + */ +public record Any(Map labels, AssetProperties properties, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost) implements Asset { + + /** Creates a new builder for {@link Any}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private Map labels; + private AssetProperties properties; + private OffsetDateTime start; + private OffsetDateTime end; + private Window window; + private double adjustment; + private double cost; + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder adjustment(double adjustment) { + this.adjustment = adjustment; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + + public Any build() { + return new Any(labels, properties, start, end, window, adjustment, cost); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AnyDecoder.java b/tests/opencost/java/com/opencost/opencost/AnyDecoder.java new file mode 100644 index 0000000..fb8bba0 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AnyDecoder.java @@ -0,0 +1,99 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link Any}. + */ +public final class AnyDecoder implements BinDecoder { + + public static final AnyDecoder INSTANCE = new AnyDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Any} from a standalone byte array. */ + public static Any fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Any} read incrementally from a stream. */ + public static Any fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Any decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Any: expected " + VERSION + " or less, got " + version); + } + + Any.Builder builder = Any.builder(); + Map v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // map length + v0 = new LinkedHashMap<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + v0.put(v3, v4); + } + } + builder.labels(v0); + AssetProperties v5; + if (buff.readUInt8() == 0) { + v5 = null; + } else { + buff.readInt(); // [compatibility, unused] + v5 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v5); + OffsetDateTime v6; + v6 = GoTime.decode(buff); + builder.start(v6); + OffsetDateTime v7; + v7 = GoTime.decode(buff); + builder.end(v7); + Window v8; + buff.readInt(); // [compatibility, unused] + v8 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v8); + double v9; + v9 = buff.readFloat64(); + builder.adjustment(v9); + double v10; + v10 = buff.readFloat64(); + builder.cost(v10); + Any result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AnyEncoder.java b/tests/opencost/java/com/opencost/opencost/AnyEncoder.java new file mode 100644 index 0000000..ef5b0e4 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AnyEncoder.java @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link Any}. + */ +public final class AnyEncoder implements BinEncoder { + + public static final AnyEncoder INSTANCE = new AnyEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Any value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Any value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.adjustment()); + buff.writeFloat64(value.cost()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Asset.java b/tests/opencost/java/com/opencost/opencost/Asset.java new file mode 100644 index 0000000..9f0ee8b --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Asset.java @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +/** + * Marker interface for the {@code Asset} go interface. Concrete + * implementations are dispatched by the generated {@code TypeRegistry}. + */ +public interface Asset { +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetProperties.java b/tests/opencost/java/com/opencost/opencost/AssetProperties.java new file mode 100644 index 0000000..6e380d5 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetProperties.java @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + + +/** + * Generated data type for the {@code AssetProperties} go struct. + */ +public record AssetProperties(String category, String provider, String account, String project, String service, String cluster, String name, String providerID) { + + /** Creates a new builder for {@link AssetProperties}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private String category; + private String provider; + private String account; + private String project; + private String service; + private String cluster; + private String name; + private String providerID; + public Builder category(String category) { + this.category = category; + return this; + } + public Builder provider(String provider) { + this.provider = provider; + return this; + } + public Builder account(String account) { + this.account = account; + return this; + } + public Builder project(String project) { + this.project = project; + return this; + } + public Builder service(String service) { + this.service = service; + return this; + } + public Builder cluster(String cluster) { + this.cluster = cluster; + return this; + } + public Builder name(String name) { + this.name = name; + return this; + } + public Builder providerID(String providerID) { + this.providerID = providerID; + return this; + } + + public AssetProperties build() { + return new AssetProperties(category, provider, account, project, service, cluster, name, providerID); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java b/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java new file mode 100644 index 0000000..2dca273 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; + +/** + * Generated binary decoder for {@link AssetProperties}. + */ +public final class AssetPropertiesDecoder implements BinDecoder { + + public static final AssetPropertiesDecoder INSTANCE = new AssetPropertiesDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link AssetProperties} from a standalone byte array. */ + public static AssetProperties fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link AssetProperties} read incrementally from a stream. */ + public static AssetProperties fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public AssetProperties decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding AssetProperties: expected " + VERSION + " or less, got " + version); + } + + AssetProperties.Builder builder = AssetProperties.builder(); + String v0; + if (ctx.isStringTable()) { + v0 = ctx.table().at(buff.readInt()); // string table index + } else { + v0 = buff.readString(); // read string + } + builder.category(v0); + String v1; + if (ctx.isStringTable()) { + v1 = ctx.table().at(buff.readInt()); // string table index + } else { + v1 = buff.readString(); // read string + } + builder.provider(v1); + String v2; + if (ctx.isStringTable()) { + v2 = ctx.table().at(buff.readInt()); // string table index + } else { + v2 = buff.readString(); // read string + } + builder.account(v2); + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + builder.project(v3); + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + builder.service(v4); + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + builder.cluster(v5); + String v6; + if (ctx.isStringTable()) { + v6 = ctx.table().at(buff.readInt()); // string table index + } else { + v6 = buff.readString(); // read string + } + builder.name(v6); + String v7; + if (ctx.isStringTable()) { + v7 = ctx.table().at(buff.readInt()); // string table index + } else { + v7 = buff.readString(); // read string + } + builder.providerID(v7); + AssetProperties result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java b/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java new file mode 100644 index 0000000..aa74228 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link AssetProperties}. + */ +public final class AssetPropertiesEncoder implements BinEncoder { + + public static final AssetPropertiesEncoder INSTANCE = new AssetPropertiesEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(AssetProperties value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(AssetProperties value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.category())); // string table index + } else { + buff.writeString(value.category()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.provider())); // string table index + } else { + buff.writeString(value.provider()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.account())); // string table index + } else { + buff.writeString(value.account()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.project())); // string table index + } else { + buff.writeString(value.project()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.service())); // string table index + } else { + buff.writeString(value.service()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.cluster())); // string table index + } else { + buff.writeString(value.cluster()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.name())); // string table index + } else { + buff.writeString(value.name()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.providerID())); // string table index + } else { + buff.writeString(value.providerID()); // string + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSet.java b/tests/opencost/java/com/opencost/opencost/AssetSet.java new file mode 100644 index 0000000..3033f57 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSet.java @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.List; +import java.util.Map; + +/** + * Generated data type for the {@code AssetSet} go struct. + */ +public record AssetSet(List aggregateBy, Map assets, String fromSource, Window window, List warnings, List errors) { + + /** Creates a new builder for {@link AssetSet}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private List aggregateBy; + private Map assets; + private String fromSource; + private Window window; + private List warnings; + private List errors; + public Builder aggregateBy(List aggregateBy) { + this.aggregateBy = aggregateBy; + return this; + } + public Builder assets(Map assets) { + this.assets = assets; + return this; + } + public Builder fromSource(String fromSource) { + this.fromSource = fromSource; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder warnings(List warnings) { + this.warnings = warnings; + return this; + } + public Builder errors(List errors) { + this.errors = errors; + return this; + } + + public AssetSet build() { + return new AssetSet(aggregateBy, assets, fromSource, window, warnings, errors); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java new file mode 100644 index 0000000..5953a3c --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Generated binary decoder for {@link AssetSet}. + */ +public final class AssetSetDecoder implements BinDecoder { + + public static final AssetSetDecoder INSTANCE = new AssetSetDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link AssetSet} from a standalone byte array. */ + public static AssetSet fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link AssetSet} read incrementally from a stream. */ + public static AssetSet fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public AssetSet decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding AssetSet: expected " + VERSION + " or less, got " + version); + } + + AssetSet.Builder builder = AssetSet.builder(); + List v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // slice length + v0 = new ArrayList<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + v0.add(v3); + } + } + builder.aggregateBy(v0); + Map v4; + if (buff.readUInt8() == 0) { + v4 = null; + } else { + int v5 = buff.readInt(); // map length + v4 = new LinkedHashMap<>(v5); + for (int v6 = 0; v6 < v5; v6++) { + String v7; + if (ctx.isStringTable()) { + v7 = ctx.table().at(buff.readInt()); // string table index + } else { + v7 = buff.readString(); // read string + } + Asset v8; + if (buff.readUInt8() == 0) { + v8 = null; + } else { + String v9 = buff.readString(); + v8 = (Asset) TypeRegistry.decode(v9, ctx); + } + v4.put(v7, v8); + } + } + builder.assets(v4); + String v10; + if (ctx.isStringTable()) { + v10 = ctx.table().at(buff.readInt()); // string table index + } else { + v10 = buff.readString(); // read string + } + builder.fromSource(v10); + Window v11; + buff.readInt(); // [compatibility, unused] + v11 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v11); + List v12; + if (buff.readUInt8() == 0) { + v12 = null; + } else { + int v13 = buff.readInt(); // slice length + v12 = new ArrayList<>(v13); + for (int v14 = 0; v14 < v13; v14++) { + String v15; + if (ctx.isStringTable()) { + v15 = ctx.table().at(buff.readInt()); // string table index + } else { + v15 = buff.readString(); // read string + } + v12.add(v15); + } + } + builder.warnings(v12); + List v16; + if (buff.readUInt8() == 0) { + v16 = null; + } else { + int v17 = buff.readInt(); // slice length + v16 = new ArrayList<>(v17); + for (int v18 = 0; v18 < v17; v18++) { + String v19; + if (ctx.isStringTable()) { + v19 = ctx.table().at(buff.readInt()); // string table index + } else { + v19 = buff.readString(); // read string + } + v16.add(v19); + } + } + builder.errors(v16); + AssetSet result = builder.build(); + result = AssetSetHooks.postProcess(result); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java new file mode 100644 index 0000000..ca2650f --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import java.util.Map; + +/** + * Generated binary encoder for {@link AssetSet}. + */ +public final class AssetSetEncoder implements BinEncoder { + + public static final AssetSetEncoder INSTANCE = new AssetSetEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = true; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(AssetSet value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(AssetSet value, EncodingContext ctx) { + value = AssetSetHooks.preProcess(value); + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.aggregateBy() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.aggregateBy().size()); // slice length + for (String v0 : value.aggregateBy()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0)); // string table index + } else { + buff.writeString(v0); // string + } + } + } + if (value.assets() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.assets().size()); // map length + for (Map.Entry v1 : value.assets().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v1.getKey())); // string table index + } else { + buff.writeString(v1.getKey()); // string + } + if (v1.getValue() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + TypeRegistry.encode(v1.getValue(), ctx); + } + } + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.fromSource())); // string table index + } else { + buff.writeString(value.fromSource()); // string + } + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + if (value.warnings() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.warnings().size()); // slice length + for (String v2 : value.warnings()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v2)); // string table index + } else { + buff.writeString(v2); // string + } + } + } + if (value.errors() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.errors().size()); // slice length + for (String v3 : value.errors()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v3)); // string table index + } else { + buff.writeString(v3); // string + } + } + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetRange.java b/tests/opencost/java/com/opencost/opencost/AssetSetRange.java new file mode 100644 index 0000000..69e39b8 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSetRange.java @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.List; + +/** + * Generated data type for the {@code AssetSetRange} go struct. + */ +public record AssetSetRange(List assets, String fromStore) { + + /** Creates a new builder for {@link AssetSetRange}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private List assets; + private String fromStore; + public Builder assets(List assets) { + this.assets = assets; + return this; + } + public Builder fromStore(String fromStore) { + this.fromStore = fromStore; + return this; + } + + public AssetSetRange build() { + return new AssetSetRange(assets, fromStore); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java new file mode 100644 index 0000000..b9b7fc4 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Generated binary decoder for {@link AssetSetRange}. + */ +public final class AssetSetRangeDecoder implements BinDecoder { + + public static final AssetSetRangeDecoder INSTANCE = new AssetSetRangeDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link AssetSetRange} from a standalone byte array. */ + public static AssetSetRange fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link AssetSetRange} read incrementally from a stream. */ + public static AssetSetRange fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public AssetSetRange decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding AssetSetRange: expected " + VERSION + " or less, got " + version); + } + + AssetSetRange.Builder builder = AssetSetRange.builder(); + List v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // slice length + v0 = new ArrayList<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + AssetSet v3; + if (buff.readUInt8() == 0) { + v3 = null; + } else { + buff.readInt(); // [compatibility, unused] + v3 = AssetSetDecoder.INSTANCE.decode(ctx); + } + v0.add(v3); + } + } + builder.assets(v0); + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + builder.fromStore(v4); + AssetSetRange result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java new file mode 100644 index 0000000..8ccd9a3 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link AssetSetRange}. + */ +public final class AssetSetRangeEncoder implements BinEncoder { + + public static final AssetSetRangeEncoder INSTANCE = new AssetSetRangeEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(AssetSetRange value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(AssetSetRange value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.assets() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.assets().size()); // slice length + for (AssetSet v0 : value.assets()) { + if (v0 == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetSetEncoder.INSTANCE.encode(v0, ctx); + } + } + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.fromStore())); // string table index + } else { + buff.writeString(value.fromStore()); // string + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java b/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java new file mode 100644 index 0000000..8d4d08d --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java @@ -0,0 +1,153 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BingenConsumer; +import com.bingen.BingenFieldInfo; +import com.bingen.BingenValue; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * Generated push streamer for {@link AssetSet}. Each field is delivered to + * the consumer; slices and maps are flattened one depth (one element per call). + * Return false from the consumer to stop early. + */ +public final class AssetSetStreamer { + + private static final int VERSION = 16; + + private AssetSetStreamer() { + } + + /** Streams the fields of an encoded {@link AssetSet} held in memory. */ + public static void stream(byte[] data, BingenConsumer consumer) { + stream(new ByteArrayInputStream(data), consumer); + } + + /** + * Streams the fields of an encoded {@link AssetSet} read incrementally + * from {@code in} (socket, file, ...). The caller retains ownership of the + * stream and is responsible for closing it. + */ + public static void stream(InputStream in, BingenConsumer consumer) { + DecodingContext ctx = DecodingContext.fromStream(in); + ReadBuffer buff = ctx.buffer(); + + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version streaming AssetSet: expected " + VERSION + " or less, got " + version); + } + + BingenFieldInfo fi = null; + fi = new BingenFieldInfo("aggregateBy"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v0 = buff.readInt(); + for (int v1 = 0; v1 < v0; v1++) { + String v2; + if (ctx.isStringTable()) { + v2 = ctx.table().at(buff.readInt()); // string table index + } else { + v2 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.pair(v1, v2))) { + return; + } + } + } + fi = new BingenFieldInfo("assets"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v3 = buff.readInt(); + for (int v4 = 0; v4 < v3; v4++) { + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + Asset v6; + if (buff.readUInt8() == 0) { + v6 = null; + } else { + String v7 = buff.readString(); + v6 = (Asset) TypeRegistry.decode(v7, ctx); + } + if (!consumer.accept(fi, BingenValue.pair(v5, v6))) { + return; + } + } + } + fi = new BingenFieldInfo("FromSource"); + String v8; + if (ctx.isStringTable()) { + v8 = ctx.table().at(buff.readInt()); // string table index + } else { + v8 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.single(v8))) { + return; + } + fi = new BingenFieldInfo("Window"); + Window v9; + buff.readInt(); // [compatibility, unused] + v9 = WindowDecoder.INSTANCE.decode(ctx); + if (!consumer.accept(fi, BingenValue.single(v9))) { + return; + } + fi = new BingenFieldInfo("Warnings"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v10 = buff.readInt(); + for (int v11 = 0; v11 < v10; v11++) { + String v12; + if (ctx.isStringTable()) { + v12 = ctx.table().at(buff.readInt()); // string table index + } else { + v12 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.pair(v11, v12))) { + return; + } + } + } + fi = new BingenFieldInfo("Errors"); + if (buff.readUInt8() == 0) { + if (!consumer.accept(fi, null)) { + return; + } + } else { + int v13 = buff.readInt(); + for (int v14 = 0; v14 < v13; v14++) { + String v15; + if (ctx.isStringTable()) { + v15 = ctx.table().at(buff.readInt()); // string table index + } else { + v15 = buff.readString(); // read string + } + if (!consumer.accept(fi, BingenValue.pair(v14, v15))) { + return; + } + } + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Breakdown.java b/tests/opencost/java/com/opencost/opencost/Breakdown.java new file mode 100644 index 0000000..4f56fd9 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Breakdown.java @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + + +/** + * Generated data type for the {@code Breakdown} go struct. + */ +public record Breakdown(double idle, double other, double system, double user) { + + /** Creates a new builder for {@link Breakdown}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private double idle; + private double other; + private double system; + private double user; + public Builder idle(double idle) { + this.idle = idle; + return this; + } + public Builder other(double other) { + this.other = other; + return this; + } + public Builder system(double system) { + this.system = system; + return this; + } + public Builder user(double user) { + this.user = user; + return this; + } + + public Breakdown build() { + return new Breakdown(idle, other, system, user); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java b/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java new file mode 100644 index 0000000..a21e38b --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; + +/** + * Generated binary decoder for {@link Breakdown}. + */ +public final class BreakdownDecoder implements BinDecoder { + + public static final BreakdownDecoder INSTANCE = new BreakdownDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Breakdown} from a standalone byte array. */ + public static Breakdown fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Breakdown} read incrementally from a stream. */ + public static Breakdown fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Breakdown decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Breakdown: expected " + VERSION + " or less, got " + version); + } + + Breakdown.Builder builder = Breakdown.builder(); + double v0; + v0 = buff.readFloat64(); + builder.idle(v0); + double v1; + v1 = buff.readFloat64(); + builder.other(v1); + double v2; + v2 = buff.readFloat64(); + builder.system(v2); + double v3; + v3 = buff.readFloat64(); + builder.user(v3); + Breakdown result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java b/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java new file mode 100644 index 0000000..eb0b9b9 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link Breakdown}. + */ +public final class BreakdownEncoder implements BinEncoder { + + public static final BreakdownEncoder INSTANCE = new BreakdownEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Breakdown value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Breakdown value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + buff.writeFloat64(value.idle()); + buff.writeFloat64(value.other()); + buff.writeFloat64(value.system()); + buff.writeFloat64(value.user()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Cloud.java b/tests/opencost/java/com/opencost/opencost/Cloud.java new file mode 100644 index 0000000..aaef223 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Cloud.java @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code Cloud} go struct. + */ +public record Cloud(Map labels, AssetProperties properties, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost, double credit) implements Asset { + + /** Creates a new builder for {@link Cloud}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private Map labels; + private AssetProperties properties; + private OffsetDateTime start; + private OffsetDateTime end; + private Window window; + private double adjustment; + private double cost; + private double credit; + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder adjustment(double adjustment) { + this.adjustment = adjustment; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + public Builder credit(double credit) { + this.credit = credit; + return this; + } + + public Cloud build() { + return new Cloud(labels, properties, start, end, window, adjustment, cost, credit); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/CloudDecoder.java b/tests/opencost/java/com/opencost/opencost/CloudDecoder.java new file mode 100644 index 0000000..34560dc --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/CloudDecoder.java @@ -0,0 +1,102 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link Cloud}. + */ +public final class CloudDecoder implements BinDecoder { + + public static final CloudDecoder INSTANCE = new CloudDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Cloud} from a standalone byte array. */ + public static Cloud fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Cloud} read incrementally from a stream. */ + public static Cloud fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Cloud decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Cloud: expected " + VERSION + " or less, got " + version); + } + + Cloud.Builder builder = Cloud.builder(); + Map v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // map length + v0 = new LinkedHashMap<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + v0.put(v3, v4); + } + } + builder.labels(v0); + AssetProperties v5; + if (buff.readUInt8() == 0) { + v5 = null; + } else { + buff.readInt(); // [compatibility, unused] + v5 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v5); + OffsetDateTime v6; + v6 = GoTime.decode(buff); + builder.start(v6); + OffsetDateTime v7; + v7 = GoTime.decode(buff); + builder.end(v7); + Window v8; + buff.readInt(); // [compatibility, unused] + v8 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v8); + double v9; + v9 = buff.readFloat64(); + builder.adjustment(v9); + double v10; + v10 = buff.readFloat64(); + builder.cost(v10); + double v11; + v11 = buff.readFloat64(); + builder.credit(v11); + Cloud result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/CloudEncoder.java b/tests/opencost/java/com/opencost/opencost/CloudEncoder.java new file mode 100644 index 0000000..63abbc5 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/CloudEncoder.java @@ -0,0 +1,72 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link Cloud}. + */ +public final class CloudEncoder implements BinEncoder { + + public static final CloudEncoder INSTANCE = new CloudEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Cloud value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Cloud value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.adjustment()); + buff.writeFloat64(value.cost()); + buff.writeFloat64(value.credit()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/ClusterManagement.java b/tests/opencost/java/com/opencost/opencost/ClusterManagement.java new file mode 100644 index 0000000..44d030c --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/ClusterManagement.java @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.Map; + +/** + * Generated data type for the {@code ClusterManagement} go struct. + */ +public record ClusterManagement(Map labels, AssetProperties properties, Window window, double cost) implements Asset { + + /** Creates a new builder for {@link ClusterManagement}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private Map labels; + private AssetProperties properties; + private Window window; + private double cost; + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + + public ClusterManagement build() { + return new ClusterManagement(labels, properties, window, cost); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java b/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java new file mode 100644 index 0000000..d66177d --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link ClusterManagement}. + */ +public final class ClusterManagementDecoder implements BinDecoder { + + public static final ClusterManagementDecoder INSTANCE = new ClusterManagementDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link ClusterManagement} from a standalone byte array. */ + public static ClusterManagement fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link ClusterManagement} read incrementally from a stream. */ + public static ClusterManagement fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public ClusterManagement decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding ClusterManagement: expected " + VERSION + " or less, got " + version); + } + + ClusterManagement.Builder builder = ClusterManagement.builder(); + Map v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // map length + v0 = new LinkedHashMap<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + v0.put(v3, v4); + } + } + builder.labels(v0); + AssetProperties v5; + if (buff.readUInt8() == 0) { + v5 = null; + } else { + buff.readInt(); // [compatibility, unused] + v5 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v5); + Window v6; + buff.readInt(); // [compatibility, unused] + v6 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v6); + double v7; + v7 = buff.readFloat64(); + builder.cost(v7); + ClusterManagement result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/ClusterManagementEncoder.java b/tests/opencost/java/com/opencost/opencost/ClusterManagementEncoder.java new file mode 100644 index 0000000..d113fc9 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/ClusterManagementEncoder.java @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import java.util.Map; + +/** + * Generated binary encoder for {@link ClusterManagement}. + */ +public final class ClusterManagementEncoder implements BinEncoder { + + public static final ClusterManagementEncoder INSTANCE = new ClusterManagementEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(ClusterManagement value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(ClusterManagement value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.cost()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Disk.java b/tests/opencost/java/com/opencost/opencost/Disk.java new file mode 100644 index 0000000..a8d0509 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Disk.java @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code Disk} go struct. + */ +public record Disk(Map labels, AssetProperties properties, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost, double byteHours, double local, Breakdown breakdown) implements Asset { + + /** Creates a new builder for {@link Disk}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private Map labels; + private AssetProperties properties; + private OffsetDateTime start; + private OffsetDateTime end; + private Window window; + private double adjustment; + private double cost; + private double byteHours; + private double local; + private Breakdown breakdown; + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder adjustment(double adjustment) { + this.adjustment = adjustment; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + public Builder byteHours(double byteHours) { + this.byteHours = byteHours; + return this; + } + public Builder local(double local) { + this.local = local; + return this; + } + public Builder breakdown(Breakdown breakdown) { + this.breakdown = breakdown; + return this; + } + + public Disk build() { + return new Disk(labels, properties, start, end, window, adjustment, cost, byteHours, local, breakdown); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/DiskDecoder.java b/tests/opencost/java/com/opencost/opencost/DiskDecoder.java new file mode 100644 index 0000000..d7bcae8 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/DiskDecoder.java @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link Disk}. + */ +public final class DiskDecoder implements BinDecoder { + + public static final DiskDecoder INSTANCE = new DiskDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Disk} from a standalone byte array. */ + public static Disk fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Disk} read incrementally from a stream. */ + public static Disk fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Disk decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Disk: expected " + VERSION + " or less, got " + version); + } + + Disk.Builder builder = Disk.builder(); + Map v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + int v1 = buff.readInt(); // map length + v0 = new LinkedHashMap<>(v1); + for (int v2 = 0; v2 < v1; v2++) { + String v3; + if (ctx.isStringTable()) { + v3 = ctx.table().at(buff.readInt()); // string table index + } else { + v3 = buff.readString(); // read string + } + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + v0.put(v3, v4); + } + } + builder.labels(v0); + AssetProperties v5; + if (buff.readUInt8() == 0) { + v5 = null; + } else { + buff.readInt(); // [compatibility, unused] + v5 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v5); + OffsetDateTime v6; + v6 = GoTime.decode(buff); + builder.start(v6); + OffsetDateTime v7; + v7 = GoTime.decode(buff); + builder.end(v7); + Window v8; + buff.readInt(); // [compatibility, unused] + v8 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v8); + double v9; + v9 = buff.readFloat64(); + builder.adjustment(v9); + double v10; + v10 = buff.readFloat64(); + builder.cost(v10); + double v11; + v11 = buff.readFloat64(); + builder.byteHours(v11); + double v12; + v12 = buff.readFloat64(); + builder.local(v12); + Breakdown v13; + if (buff.readUInt8() == 0) { + v13 = null; + } else { + buff.readInt(); // [compatibility, unused] + v13 = BreakdownDecoder.INSTANCE.decode(ctx); + } + builder.breakdown(v13); + Disk result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/DiskEncoder.java b/tests/opencost/java/com/opencost/opencost/DiskEncoder.java new file mode 100644 index 0000000..b3004f8 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/DiskEncoder.java @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link Disk}. + */ +public final class DiskEncoder implements BinEncoder { + + public static final DiskEncoder INSTANCE = new DiskEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Disk value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Disk value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.adjustment()); + buff.writeFloat64(value.cost()); + buff.writeFloat64(value.byteHours()); + buff.writeFloat64(value.local()); + if (value.breakdown() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + BreakdownEncoder.INSTANCE.encode(value.breakdown(), ctx); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/LoadBalancer.java b/tests/opencost/java/com/opencost/opencost/LoadBalancer.java new file mode 100644 index 0000000..ac5d5c3 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/LoadBalancer.java @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code LoadBalancer} go struct. + */ +public record LoadBalancer(AssetProperties properties, Map labels, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost) implements Asset { + + /** Creates a new builder for {@link LoadBalancer}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private AssetProperties properties; + private Map labels; + private OffsetDateTime start; + private OffsetDateTime end; + private Window window; + private double adjustment; + private double cost; + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder adjustment(double adjustment) { + this.adjustment = adjustment; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + + public LoadBalancer build() { + return new LoadBalancer(properties, labels, start, end, window, adjustment, cost); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java b/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java new file mode 100644 index 0000000..bf46c9b --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java @@ -0,0 +1,99 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link LoadBalancer}. + */ +public final class LoadBalancerDecoder implements BinDecoder { + + public static final LoadBalancerDecoder INSTANCE = new LoadBalancerDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link LoadBalancer} from a standalone byte array. */ + public static LoadBalancer fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link LoadBalancer} read incrementally from a stream. */ + public static LoadBalancer fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public LoadBalancer decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding LoadBalancer: expected " + VERSION + " or less, got " + version); + } + + LoadBalancer.Builder builder = LoadBalancer.builder(); + AssetProperties v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + buff.readInt(); // [compatibility, unused] + v0 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v0); + Map v1; + if (buff.readUInt8() == 0) { + v1 = null; + } else { + int v2 = buff.readInt(); // map length + v1 = new LinkedHashMap<>(v2); + for (int v3 = 0; v3 < v2; v3++) { + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + v1.put(v4, v5); + } + } + builder.labels(v1); + OffsetDateTime v6; + v6 = GoTime.decode(buff); + builder.start(v6); + OffsetDateTime v7; + v7 = GoTime.decode(buff); + builder.end(v7); + Window v8; + buff.readInt(); // [compatibility, unused] + v8 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v8); + double v9; + v9 = buff.readFloat64(); + builder.adjustment(v9); + double v10; + v10 = buff.readFloat64(); + builder.cost(v10); + LoadBalancer result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java b/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java new file mode 100644 index 0000000..e335df9 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link LoadBalancer}. + */ +public final class LoadBalancerEncoder implements BinEncoder { + + public static final LoadBalancerEncoder INSTANCE = new LoadBalancerEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(LoadBalancer value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(LoadBalancer value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.adjustment()); + buff.writeFloat64(value.cost()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Network.java b/tests/opencost/java/com/opencost/opencost/Network.java new file mode 100644 index 0000000..eb3067c --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Network.java @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code Network} go struct. + */ +public record Network(AssetProperties properties, Map labels, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost) implements Asset { + + /** Creates a new builder for {@link Network}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private AssetProperties properties; + private Map labels; + private OffsetDateTime start; + private OffsetDateTime end; + private Window window; + private double adjustment; + private double cost; + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder adjustment(double adjustment) { + this.adjustment = adjustment; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + + public Network build() { + return new Network(properties, labels, start, end, window, adjustment, cost); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java b/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java new file mode 100644 index 0000000..ccd41f8 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java @@ -0,0 +1,99 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link Network}. + */ +public final class NetworkDecoder implements BinDecoder { + + public static final NetworkDecoder INSTANCE = new NetworkDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Network} from a standalone byte array. */ + public static Network fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Network} read incrementally from a stream. */ + public static Network fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Network decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Network: expected " + VERSION + " or less, got " + version); + } + + Network.Builder builder = Network.builder(); + AssetProperties v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + buff.readInt(); // [compatibility, unused] + v0 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v0); + Map v1; + if (buff.readUInt8() == 0) { + v1 = null; + } else { + int v2 = buff.readInt(); // map length + v1 = new LinkedHashMap<>(v2); + for (int v3 = 0; v3 < v2; v3++) { + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + v1.put(v4, v5); + } + } + builder.labels(v1); + OffsetDateTime v6; + v6 = GoTime.decode(buff); + builder.start(v6); + OffsetDateTime v7; + v7 = GoTime.decode(buff); + builder.end(v7); + Window v8; + buff.readInt(); // [compatibility, unused] + v8 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v8); + double v9; + v9 = buff.readFloat64(); + builder.adjustment(v9); + double v10; + v10 = buff.readFloat64(); + builder.cost(v10); + Network result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java b/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java new file mode 100644 index 0000000..fbb5af2 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link Network}. + */ +public final class NetworkEncoder implements BinEncoder { + + public static final NetworkEncoder INSTANCE = new NetworkEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Network value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Network value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.adjustment()); + buff.writeFloat64(value.cost()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Node.java b/tests/opencost/java/com/opencost/opencost/Node.java new file mode 100644 index 0000000..84631c3 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Node.java @@ -0,0 +1,121 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated data type for the {@code Node} go struct. + */ +public record Node(AssetProperties properties, Map labels, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, String nodeType, double cPUCoreHours, double rAMByteHours, double gPUHours, Breakdown cPUBreakdown, Breakdown rAMBreakdown, double cPUCost, double gPUCost, double gPUCount, double rAMCost, double discount, double preemptible) implements Asset { + + /** Creates a new builder for {@link Node}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private AssetProperties properties; + private Map labels; + private OffsetDateTime start; + private OffsetDateTime end; + private Window window; + private double adjustment; + private String nodeType; + private double cPUCoreHours; + private double rAMByteHours; + private double gPUHours; + private Breakdown cPUBreakdown; + private Breakdown rAMBreakdown; + private double cPUCost; + private double gPUCost; + private double gPUCount; + private double rAMCost; + private double discount; + private double preemptible; + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder adjustment(double adjustment) { + this.adjustment = adjustment; + return this; + } + public Builder nodeType(String nodeType) { + this.nodeType = nodeType; + return this; + } + public Builder cPUCoreHours(double cPUCoreHours) { + this.cPUCoreHours = cPUCoreHours; + return this; + } + public Builder rAMByteHours(double rAMByteHours) { + this.rAMByteHours = rAMByteHours; + return this; + } + public Builder gPUHours(double gPUHours) { + this.gPUHours = gPUHours; + return this; + } + public Builder cPUBreakdown(Breakdown cPUBreakdown) { + this.cPUBreakdown = cPUBreakdown; + return this; + } + public Builder rAMBreakdown(Breakdown rAMBreakdown) { + this.rAMBreakdown = rAMBreakdown; + return this; + } + public Builder cPUCost(double cPUCost) { + this.cPUCost = cPUCost; + return this; + } + public Builder gPUCost(double gPUCost) { + this.gPUCost = gPUCost; + return this; + } + public Builder gPUCount(double gPUCount) { + this.gPUCount = gPUCount; + return this; + } + public Builder rAMCost(double rAMCost) { + this.rAMCost = rAMCost; + return this; + } + public Builder discount(double discount) { + this.discount = discount; + return this; + } + public Builder preemptible(double preemptible) { + this.preemptible = preemptible; + return this; + } + + public Node build() { + return new Node(properties, labels, start, end, window, adjustment, nodeType, cPUCoreHours, rAMByteHours, gPUHours, cPUBreakdown, rAMBreakdown, cPUCost, gPUCost, gPUCount, rAMCost, discount, preemptible); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/NodeDecoder.java b/tests/opencost/java/com/opencost/opencost/NodeDecoder.java new file mode 100644 index 0000000..cd66c63 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/NodeDecoder.java @@ -0,0 +1,146 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link Node}. + */ +public final class NodeDecoder implements BinDecoder { + + public static final NodeDecoder INSTANCE = new NodeDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Node} from a standalone byte array. */ + public static Node fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Node} read incrementally from a stream. */ + public static Node fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Node decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Node: expected " + VERSION + " or less, got " + version); + } + + Node.Builder builder = Node.builder(); + AssetProperties v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + buff.readInt(); // [compatibility, unused] + v0 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v0); + Map v1; + if (buff.readUInt8() == 0) { + v1 = null; + } else { + int v2 = buff.readInt(); // map length + v1 = new LinkedHashMap<>(v2); + for (int v3 = 0; v3 < v2; v3++) { + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + v1.put(v4, v5); + } + } + builder.labels(v1); + OffsetDateTime v6; + v6 = GoTime.decode(buff); + builder.start(v6); + OffsetDateTime v7; + v7 = GoTime.decode(buff); + builder.end(v7); + Window v8; + buff.readInt(); // [compatibility, unused] + v8 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v8); + double v9; + v9 = buff.readFloat64(); + builder.adjustment(v9); + String v10; + if (ctx.isStringTable()) { + v10 = ctx.table().at(buff.readInt()); // string table index + } else { + v10 = buff.readString(); // read string + } + builder.nodeType(v10); + double v11; + v11 = buff.readFloat64(); + builder.cPUCoreHours(v11); + double v12; + v12 = buff.readFloat64(); + builder.rAMByteHours(v12); + double v13; + v13 = buff.readFloat64(); + builder.gPUHours(v13); + Breakdown v14; + if (buff.readUInt8() == 0) { + v14 = null; + } else { + buff.readInt(); // [compatibility, unused] + v14 = BreakdownDecoder.INSTANCE.decode(ctx); + } + builder.cPUBreakdown(v14); + Breakdown v15; + if (buff.readUInt8() == 0) { + v15 = null; + } else { + buff.readInt(); // [compatibility, unused] + v15 = BreakdownDecoder.INSTANCE.decode(ctx); + } + builder.rAMBreakdown(v15); + double v16; + v16 = buff.readFloat64(); + builder.cPUCost(v16); + double v17; + v17 = buff.readFloat64(); + builder.gPUCost(v17); + double v18; + v18 = buff.readFloat64(); + builder.gPUCount(v18); + double v19; + v19 = buff.readFloat64(); + builder.rAMCost(v19); + double v20; + v20 = buff.readFloat64(); + builder.discount(v20); + double v21; + v21 = buff.readFloat64(); + builder.preemptible(v21); + Node result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/NodeEncoder.java b/tests/opencost/java/com/opencost/opencost/NodeEncoder.java new file mode 100644 index 0000000..0d72150 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/NodeEncoder.java @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Generated binary encoder for {@link Node}. + */ +public final class NodeEncoder implements BinEncoder { + + public static final NodeEncoder INSTANCE = new NodeEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Node value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Node value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + GoTime.encode(value.start(), buff); + GoTime.encode(value.end(), buff); + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.adjustment()); + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.nodeType())); // string table index + } else { + buff.writeString(value.nodeType()); // string + } + buff.writeFloat64(value.cPUCoreHours()); + buff.writeFloat64(value.rAMByteHours()); + buff.writeFloat64(value.gPUHours()); + if (value.cPUBreakdown() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + BreakdownEncoder.INSTANCE.encode(value.cPUBreakdown(), ctx); + } + if (value.rAMBreakdown() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + BreakdownEncoder.INSTANCE.encode(value.rAMBreakdown(), ctx); + } + buff.writeFloat64(value.cPUCost()); + buff.writeFloat64(value.gPUCost()); + buff.writeFloat64(value.gPUCount()); + buff.writeFloat64(value.rAMCost()); + buff.writeFloat64(value.discount()); + buff.writeFloat64(value.preemptible()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/PVAllocation.java b/tests/opencost/java/com/opencost/opencost/PVAllocation.java new file mode 100644 index 0000000..b0e0839 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/PVAllocation.java @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + + +/** + * Generated data type for the {@code PVAllocation} go struct. + */ +public record PVAllocation(double byteHours, double cost) { + + /** Creates a new builder for {@link PVAllocation}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private double byteHours; + private double cost; + public Builder byteHours(double byteHours) { + this.byteHours = byteHours; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + + public PVAllocation build() { + return new PVAllocation(byteHours, cost); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java b/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java new file mode 100644 index 0000000..81e6068 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; + +/** + * Generated binary decoder for {@link PVAllocation}. + */ +public final class PVAllocationDecoder implements BinDecoder { + + public static final PVAllocationDecoder INSTANCE = new PVAllocationDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link PVAllocation} from a standalone byte array. */ + public static PVAllocation fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link PVAllocation} read incrementally from a stream. */ + public static PVAllocation fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public PVAllocation decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding PVAllocation: expected " + VERSION + " or less, got " + version); + } + + PVAllocation.Builder builder = PVAllocation.builder(); + double v0; + v0 = buff.readFloat64(); + builder.byteHours(v0); + double v1; + v1 = buff.readFloat64(); + builder.cost(v1); + PVAllocation result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java b/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java new file mode 100644 index 0000000..d4e38ba --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link PVAllocation}. + */ +public final class PVAllocationEncoder implements BinEncoder { + + public static final PVAllocationEncoder INSTANCE = new PVAllocationEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(PVAllocation value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(PVAllocation value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + buff.writeFloat64(value.byteHours()); + buff.writeFloat64(value.cost()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/PVKey.java b/tests/opencost/java/com/opencost/opencost/PVKey.java new file mode 100644 index 0000000..4ef6439 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/PVKey.java @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + + +/** + * Generated data type for the {@code PVKey} go struct. + */ +public record PVKey(String cluster, String name) { + + /** Creates a new builder for {@link PVKey}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private String cluster; + private String name; + public Builder cluster(String cluster) { + this.cluster = cluster; + return this; + } + public Builder name(String name) { + this.name = name; + return this; + } + + public PVKey build() { + return new PVKey(cluster, name); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java b/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java new file mode 100644 index 0000000..a2264da --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; + +/** + * Generated binary decoder for {@link PVKey}. + */ +public final class PVKeyDecoder implements BinDecoder { + + public static final PVKeyDecoder INSTANCE = new PVKeyDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link PVKey} from a standalone byte array. */ + public static PVKey fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link PVKey} read incrementally from a stream. */ + public static PVKey fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public PVKey decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding PVKey: expected " + VERSION + " or less, got " + version); + } + + PVKey.Builder builder = PVKey.builder(); + String v0; + if (ctx.isStringTable()) { + v0 = ctx.table().at(buff.readInt()); // string table index + } else { + v0 = buff.readString(); // read string + } + builder.cluster(v0); + String v1; + if (ctx.isStringTable()) { + v1 = ctx.table().at(buff.readInt()); // string table index + } else { + v1 = buff.readString(); // read string + } + builder.name(v1); + PVKey result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java b/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java new file mode 100644 index 0000000..7c6c3c8 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link PVKey}. + */ +public final class PVKeyEncoder implements BinEncoder { + + public static final PVKeyEncoder INSTANCE = new PVKeyEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(PVKey value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(PVKey value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.cluster())); // string table index + } else { + buff.writeString(value.cluster()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(value.name())); // string table index + } else { + buff.writeString(value.name()); // string + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java new file mode 100644 index 0000000..b631e44 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + + +/** + * Generated data type for the {@code RawAllocationOnlyData} go struct. + */ +public record RawAllocationOnlyData(double cPUCoreUsageMax, double rAMBytesUsageMax) { + + /** Creates a new builder for {@link RawAllocationOnlyData}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private double cPUCoreUsageMax; + private double rAMBytesUsageMax; + public Builder cPUCoreUsageMax(double cPUCoreUsageMax) { + this.cPUCoreUsageMax = cPUCoreUsageMax; + return this; + } + public Builder rAMBytesUsageMax(double rAMBytesUsageMax) { + this.rAMBytesUsageMax = rAMBytesUsageMax; + return this; + } + + public RawAllocationOnlyData build() { + return new RawAllocationOnlyData(cPUCoreUsageMax, rAMBytesUsageMax); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java new file mode 100644 index 0000000..d0584a5 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; + +/** + * Generated binary decoder for {@link RawAllocationOnlyData}. + */ +public final class RawAllocationOnlyDataDecoder implements BinDecoder { + + public static final RawAllocationOnlyDataDecoder INSTANCE = new RawAllocationOnlyDataDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link RawAllocationOnlyData} from a standalone byte array. */ + public static RawAllocationOnlyData fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link RawAllocationOnlyData} read incrementally from a stream. */ + public static RawAllocationOnlyData fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public RawAllocationOnlyData decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding RawAllocationOnlyData: expected " + VERSION + " or less, got " + version); + } + + RawAllocationOnlyData.Builder builder = RawAllocationOnlyData.builder(); + double v0; + v0 = buff.readFloat64(); + builder.cPUCoreUsageMax(v0); + double v1; + v1 = buff.readFloat64(); + builder.rAMBytesUsageMax(v1); + RawAllocationOnlyData result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataEncoder.java b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataEncoder.java new file mode 100644 index 0000000..93942c6 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataEncoder.java @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; + +/** + * Generated binary encoder for {@link RawAllocationOnlyData}. + */ +public final class RawAllocationOnlyDataEncoder implements BinEncoder { + + public static final RawAllocationOnlyDataEncoder INSTANCE = new RawAllocationOnlyDataEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(RawAllocationOnlyData value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(RawAllocationOnlyData value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + buff.writeFloat64(value.cPUCoreUsageMax()); + buff.writeFloat64(value.rAMBytesUsageMax()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/SharedAsset.java b/tests/opencost/java/com/opencost/opencost/SharedAsset.java new file mode 100644 index 0000000..3edd89d --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/SharedAsset.java @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.util.Map; + +/** + * Generated data type for the {@code SharedAsset} go struct. + */ +public record SharedAsset(AssetProperties properties, Map labels, Window window, double cost) implements Asset { + + /** Creates a new builder for {@link SharedAsset}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private AssetProperties properties; + private Map labels; + private Window window; + private double cost; + public Builder properties(AssetProperties properties) { + this.properties = properties; + return this; + } + public Builder labels(Map labels) { + this.labels = labels; + return this; + } + public Builder window(Window window) { + this.window = window; + return this; + } + public Builder cost(double cost) { + this.cost = cost; + return this; + } + + public SharedAsset build() { + return new SharedAsset(properties, labels, window, cost); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java b/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java new file mode 100644 index 0000000..301b646 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Generated binary decoder for {@link SharedAsset}. + */ +public final class SharedAssetDecoder implements BinDecoder { + + public static final SharedAssetDecoder INSTANCE = new SharedAssetDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link SharedAsset} from a standalone byte array. */ + public static SharedAsset fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link SharedAsset} read incrementally from a stream. */ + public static SharedAsset fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public SharedAsset decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding SharedAsset: expected " + VERSION + " or less, got " + version); + } + + SharedAsset.Builder builder = SharedAsset.builder(); + AssetProperties v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + buff.readInt(); // [compatibility, unused] + v0 = AssetPropertiesDecoder.INSTANCE.decode(ctx); + } + builder.properties(v0); + Map v1; + if (buff.readUInt8() == 0) { + v1 = null; + } else { + int v2 = buff.readInt(); // map length + v1 = new LinkedHashMap<>(v2); + for (int v3 = 0; v3 < v2; v3++) { + String v4; + if (ctx.isStringTable()) { + v4 = ctx.table().at(buff.readInt()); // string table index + } else { + v4 = buff.readString(); // read string + } + String v5; + if (ctx.isStringTable()) { + v5 = ctx.table().at(buff.readInt()); // string table index + } else { + v5 = buff.readString(); // read string + } + v1.put(v4, v5); + } + } + builder.labels(v1); + Window v6; + buff.readInt(); // [compatibility, unused] + v6 = WindowDecoder.INSTANCE.decode(ctx); + builder.window(v6); + double v7; + v7 = buff.readFloat64(); + builder.cost(v7); + SharedAsset result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java b/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java new file mode 100644 index 0000000..20f8db3 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import java.util.Map; + +/** + * Generated binary encoder for {@link SharedAsset}. + */ +public final class SharedAssetEncoder implements BinEncoder { + + public static final SharedAssetEncoder INSTANCE = new SharedAssetEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(SharedAsset value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(SharedAsset value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.properties() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(0); // [compatibility, unused] + AssetPropertiesEncoder.INSTANCE.encode(value.properties(), ctx); + } + if (value.labels() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + buff.writeInt(value.labels().size()); // map length + for (Map.Entry v0 : value.labels().entrySet()) { + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getKey())); // string table index + } else { + buff.writeString(v0.getKey()); // string + } + if (ctx.isStringTable()) { + buff.writeInt(ctx.table().addOrGet(v0.getValue())); // string table index + } else { + buff.writeString(v0.getValue()); // string + } + } + } + buff.writeInt(0); // [compatibility, unused] + WindowEncoder.INSTANCE.encode(value.window(), ctx); + buff.writeFloat64(value.cost()); + } +} diff --git a/tests/opencost/java/com/opencost/opencost/TypeRegistry.java b/tests/opencost/java/com/opencost/opencost/TypeRegistry.java new file mode 100644 index 0000000..c095514 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/TypeRegistry.java @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.BinEncoder; +import com.bingen.DecodingContext; +import com.bingen.EncodingContext; +import java.util.HashMap; +import java.util.Map; + +/** + * Maps go wire type strings to the generated codecs for interface dispatch, + * replacing go's reflection-based type map. + */ +public final class TypeRegistry { + + private static final Map> DECODERS = new HashMap<>(); + private static final Map, String> WIRE_NAMES = new HashMap<>(); + private static final Map, BinEncoder> ENCODERS = new HashMap<>(); + + static { + register("*github.com/opencost/bingen/tests/opencost.Allocation", Allocation.class, AllocationEncoder.INSTANCE, AllocationDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.AllocationProperties", AllocationProperties.class, AllocationPropertiesEncoder.INSTANCE, AllocationPropertiesDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.AllocationSet", AllocationSet.class, AllocationSetEncoder.INSTANCE, AllocationSetDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.AllocationSetRange", AllocationSetRange.class, AllocationSetRangeEncoder.INSTANCE, AllocationSetRangeDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Any", Any.class, AnyEncoder.INSTANCE, AnyDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.AssetProperties", AssetProperties.class, AssetPropertiesEncoder.INSTANCE, AssetPropertiesDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.AssetSet", AssetSet.class, AssetSetEncoder.INSTANCE, AssetSetDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.AssetSetRange", AssetSetRange.class, AssetSetRangeEncoder.INSTANCE, AssetSetRangeDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Breakdown", Breakdown.class, BreakdownEncoder.INSTANCE, BreakdownDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Cloud", Cloud.class, CloudEncoder.INSTANCE, CloudDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.ClusterManagement", ClusterManagement.class, ClusterManagementEncoder.INSTANCE, ClusterManagementDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Disk", Disk.class, DiskEncoder.INSTANCE, DiskDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.LoadBalancer", LoadBalancer.class, LoadBalancerEncoder.INSTANCE, LoadBalancerDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Network", Network.class, NetworkEncoder.INSTANCE, NetworkDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Node", Node.class, NodeEncoder.INSTANCE, NodeDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.PVAllocation", PVAllocation.class, PVAllocationEncoder.INSTANCE, PVAllocationDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.PVKey", PVKey.class, PVKeyEncoder.INSTANCE, PVKeyDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.RawAllocationOnlyData", RawAllocationOnlyData.class, RawAllocationOnlyDataEncoder.INSTANCE, RawAllocationOnlyDataDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.SharedAsset", SharedAsset.class, SharedAssetEncoder.INSTANCE, SharedAssetDecoder.INSTANCE); + register("*github.com/opencost/bingen/tests/opencost.Window", Window.class, WindowEncoder.INSTANCE, WindowDecoder.INSTANCE); + } + + private TypeRegistry() { + } + + private static void register(String wire, Class cls, BinEncoder enc, BinDecoder dec) { + DECODERS.put(wire, dec); + DECODERS.put(stripStar(wire), dec); + WIRE_NAMES.put(cls, wire); + ENCODERS.put(cls, enc); + } + + /** Writes the wire type string + compatibility marker, then the value body. */ + @SuppressWarnings("unchecked") + public static void encode(Object value, EncodingContext ctx) { + String wire = WIRE_NAMES.get(value.getClass()); + if (wire == null) { + throw new IllegalArgumentException("bingen: unregistered interface type " + value.getClass().getName()); + } + BinEncoder enc = (BinEncoder) ENCODERS.get(value.getClass()); + ctx.buffer().writeString(wire); + ctx.buffer().writeInt(0); // [compatibility, unused] + enc.encode(value, ctx); + } + + /** Reads the compatibility marker, then decodes the concrete value. */ + public static Object decode(String wire, DecodingContext ctx) { + BinDecoder dec = DECODERS.get(wire); + if (dec == null) { + dec = DECODERS.get(stripStar(wire)); + } + if (dec == null) { + throw new IllegalArgumentException("bingen: unknown wire type " + wire); + } + ctx.buffer().readInt(); // [compatibility, unused] + return dec.decode(ctx); + } + + private static String stripStar(String s) { + return s.startsWith("*") ? s.substring(1) : s; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/Window.java b/tests/opencost/java/com/opencost/opencost/Window.java new file mode 100644 index 0000000..d8914ee --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/Window.java @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import java.time.OffsetDateTime; + +/** + * Generated data type for the {@code Window} go struct. + */ +public record Window(OffsetDateTime start, OffsetDateTime end) { + + /** Creates a new builder for {@link Window}. */ + public static Builder builder() { + return new Builder(); + } + + /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + public static final class Builder { + private OffsetDateTime start; + private OffsetDateTime end; + public Builder start(OffsetDateTime start) { + this.start = start; + return this; + } + public Builder end(OffsetDateTime end) { + this.end = end; + return this; + } + + public Window build() { + return new Window(start, end); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/WindowDecoder.java b/tests/opencost/java/com/opencost/opencost/WindowDecoder.java new file mode 100644 index 0000000..e0196ca --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/WindowDecoder.java @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinDecoder; +import com.bingen.DecodingContext; +import com.bingen.ReadBuffer; +import java.io.InputStream; +import com.bingen.GoTime; +import java.time.OffsetDateTime; + +/** + * Generated binary decoder for {@link Window}. + */ +public final class WindowDecoder implements BinDecoder { + + public static final WindowDecoder INSTANCE = new WindowDecoder(); + + private static final int VERSION = 16; + + /** Decodes a {@link Window} from a standalone byte array. */ + public static Window fromBytes(byte[] data) { + return INSTANCE.decode(DecodingContext.fromBytes(data)); + } + + /** Decodes a {@link Window} read incrementally from a stream. */ + public static Window fromStream(InputStream in) { + return INSTANCE.decode(DecodingContext.fromStream(in)); + } + + @Override + public Window decode(DecodingContext ctx) { + ReadBuffer buff = ctx.buffer(); + int version = buff.readUInt8(); + if (version > VERSION) { + throw new IllegalStateException( + "Invalid version decoding Window: expected " + VERSION + " or less, got " + version); + } + + Window.Builder builder = Window.builder(); + OffsetDateTime v0; + if (buff.readUInt8() == 0) { + v0 = null; + } else { + v0 = GoTime.decode(buff); + } + builder.start(v0); + OffsetDateTime v1; + if (buff.readUInt8() == 0) { + v1 = null; + } else { + v1 = GoTime.decode(buff); + } + builder.end(v1); + Window result = builder.build(); + return result; + } +} diff --git a/tests/opencost/java/com/opencost/opencost/WindowEncoder.java b/tests/opencost/java/com/opencost/opencost/WindowEncoder.java new file mode 100644 index 0000000..ecbf130 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/WindowEncoder.java @@ -0,0 +1,51 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package com.opencost.opencost; + +import com.bingen.BinEncoder; +import com.bingen.EncodingContext; +import com.bingen.WriteBuffer; +import com.bingen.GoTime; +import java.time.OffsetDateTime; + +/** + * Generated binary encoder for {@link Window}. + */ +public final class WindowEncoder implements BinEncoder { + + public static final WindowEncoder INSTANCE = new WindowEncoder(); + + private static final int VERSION = 16; + private static final boolean STRING_TABLE = false; + + /** Encodes {@code value} to a standalone byte array. */ + public static byte[] toBytes(Window value) { + EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); + INSTANCE.encode(value, ctx); + return ctx.toBytes(); + } + + @Override + public void encode(Window value, EncodingContext ctx) { + WriteBuffer buff = ctx.buffer(); + buff.writeUInt8(VERSION); // version + if (value.start() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + GoTime.encode(value.start(), buff); + } + if (value.end() == null) { + buff.writeUInt8(0); // write nil byte + } else { + buff.writeUInt8(1); // write non-nil byte + GoTime.encode(value.end(), buff); + } + } +} diff --git a/tests/opencost/java/com/opencost/opencost/package-info.java b/tests/opencost/java/com/opencost/opencost/package-info.java new file mode 100644 index 0000000..10691d5 --- /dev/null +++ b/tests/opencost/java/com/opencost/opencost/package-info.java @@ -0,0 +1,12 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Binary codecs generated by bingen for the {@code opencost} go package. + */ +package com.opencost.opencost; diff --git a/tests/opencost/opencost_codecs.go b/tests/opencost/opencost_codecs.go index 866389f..c855dab 100644 --- a/tests/opencost/opencost_codecs.go +++ b/tests/opencost/opencost_codecs.go @@ -413,155 +413,115 @@ func (target *Allocation) MarshalBinaryWithContext(ctx *EncodingContext) (err er buff.WriteUInt8(AllocationCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Name) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Name) // write string } - if target.Properties == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AllocationProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.Properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v1 := target.Properties.MarshalBinaryWithContext(ctx) + if v1 != nil { + return v1 } // --- [end][write][struct](AllocationProperties) --- - } - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errB := target.Window.MarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v2 := target.Window.MarshalBinaryWithContext(ctx) + if v2 != nil { + return v2 } // --- [end][write][struct](Window) --- - // --- [begin][write][reference](time.Time) --- - b, errC := target.Start.MarshalBinary() - if errC != nil { - return errC + v3, v4 := target.Start.MarshalBinary() + if v4 != nil { + return v4 } - buff.WriteInt(len(b)) - buff.WriteBytes(b) + buff.WriteInt(len(v3)) + buff.WriteBytes(v3) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - c, errD := target.End.MarshalBinary() - if errD != nil { - return errD + v5, v6 := target.End.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - - buff.WriteFloat64(target.CPUCoreHours) // write float64 - - buff.WriteFloat64(target.CPUCoreRequestAverage) // write float64 - - buff.WriteFloat64(target.CPUCoreUsageAverage) // write float64 - - buff.WriteFloat64(target.CPUCost) // write float64 - - buff.WriteFloat64(target.CPUCostAdjustment) // write float64 - - buff.WriteFloat64(target.GPUHours) // write float64 - - buff.WriteFloat64(target.GPUCost) // write float64 - - buff.WriteFloat64(target.GPUCostAdjustment) // write float64 - - buff.WriteFloat64(target.NetworkTransferBytes) // write float64 - - buff.WriteFloat64(target.NetworkReceiveBytes) // write float64 - - buff.WriteFloat64(target.NetworkCost) // write float64 - - buff.WriteFloat64(target.NetworkCostAdjustment) // write float64 - - buff.WriteFloat64(target.LoadBalancerCost) // write float64 - - buff.WriteFloat64(target.LoadBalancerCostAdjustment) // write float64 - + buff.WriteFloat64(target.CPUCoreHours) + buff.WriteFloat64(target.CPUCoreRequestAverage) + buff.WriteFloat64(target.CPUCoreUsageAverage) + buff.WriteFloat64(target.CPUCost) + buff.WriteFloat64(target.CPUCostAdjustment) + buff.WriteFloat64(target.GPUHours) + buff.WriteFloat64(target.GPUCost) + buff.WriteFloat64(target.GPUCostAdjustment) + buff.WriteFloat64(target.NetworkTransferBytes) + buff.WriteFloat64(target.NetworkReceiveBytes) + buff.WriteFloat64(target.NetworkCost) + buff.WriteFloat64(target.NetworkCostAdjustment) + buff.WriteFloat64(target.LoadBalancerCost) + buff.WriteFloat64(target.LoadBalancerCostAdjustment) // --- [begin][write][alias](PVAllocations) --- if map[PVKey]*PVAllocation(target.PVs) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[PVKey]*PVAllocation) --- buff.WriteInt(len(map[PVKey]*PVAllocation(target.PVs))) // map length - for v, z := range map[PVKey]*PVAllocation(target.PVs) { - + for v7, v8 := range map[PVKey]*PVAllocation(target.PVs) { // --- [begin][write][struct](PVKey) --- buff.WriteInt(0) // [compatibility, unused] - errE := v.MarshalBinaryWithContext(ctx) - if errE != nil { - return errE + v9 := v7.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](PVKey) --- - - if z == nil { + if v8 == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](PVAllocation) --- buff.WriteInt(0) // [compatibility, unused] - errF := z.MarshalBinaryWithContext(ctx) - if errF != nil { - return errF + v10 := v8.MarshalBinaryWithContext(ctx) + if v10 != nil { + return v10 } // --- [end][write][struct](PVAllocation) --- - } } // --- [end][write][map](map[PVKey]*PVAllocation) --- - } // --- [end][write][alias](PVAllocations) --- - - buff.WriteFloat64(target.PVCostAdjustment) // write float64 - - buff.WriteFloat64(target.RAMByteHours) // write float64 - - buff.WriteFloat64(target.RAMBytesRequestAverage) // write float64 - - buff.WriteFloat64(target.RAMBytesUsageAverage) // write float64 - - buff.WriteFloat64(target.RAMCost) // write float64 - - buff.WriteFloat64(target.RAMCostAdjustment) // write float64 - - buff.WriteFloat64(target.SharedCost) // write float64 - - buff.WriteFloat64(target.ExternalCost) // write float64 - + buff.WriteFloat64(target.PVCostAdjustment) + buff.WriteFloat64(target.RAMByteHours) + buff.WriteFloat64(target.RAMBytesRequestAverage) + buff.WriteFloat64(target.RAMBytesUsageAverage) + buff.WriteFloat64(target.RAMCost) + buff.WriteFloat64(target.RAMCostAdjustment) + buff.WriteFloat64(target.SharedCost) + buff.WriteFloat64(target.ExternalCost) if target.RawAllocationOnly == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](RawAllocationOnlyData) --- buff.WriteInt(0) // [compatibility, unused] - errG := target.RawAllocationOnly.MarshalBinaryWithContext(ctx) - if errG != nil { - return errG + v11 := target.RawAllocationOnly.MarshalBinaryWithContext(ctx) + if v11 != nil { + return v11 } // --- [end][write][struct](RawAllocationOnlyData) --- - } - - buff.WriteInt(target.TestProperty) // write int - + buff.WriteInt(target.TestProperty) if ctx.IsStringTable() { - d := ctx.Table.AddOrGet(target.TestStr) - buff.WriteInt(d) // write table index + v12 := ctx.Table.AddOrGet(target.TestStr) + buff.WriteInt(v12) // write table index } else { buff.WriteString(target.TestStr) // write string } @@ -620,216 +580,204 @@ func (target *Allocation) UnmarshalBinaryWithContext(ctx *DecodingContext) (err return fmt.Errorf("Invalid Version Unmarshalling Allocation. Expected %d or less, got %d", AllocationCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Name = a - + target.Name = v0 + var v2 *AllocationProperties if buff.ReadUInt8() == uint8(0) { - target.Properties = nil + v2 = nil } else { - // --- [begin][read][struct](AllocationProperties) --- - d := new(AllocationProperties) + v3 := new(AllocationProperties) buff.ReadInt() // [compatibility, unused] - errA := d.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v4 := v3.UnmarshalBinaryWithContext(ctx) + if v4 != nil { + return v4 } - target.Properties = d + v2 = v3 // --- [end][read][struct](AllocationProperties) --- - } - + target.Properties = v2 + var v5 Window // --- [begin][read][struct](Window) --- - e := new(Window) + v6 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := e.UnmarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v7 := v6.UnmarshalBinaryWithContext(ctx) + if v7 != nil { + return v7 } - target.Window = *e + v5 = *v6 // --- [end][read][struct](Window) --- - + target.Window = v5 + var v8 time.Time // --- [begin][read][reference](time.Time) --- - f := new(time.Time) - g := buff.ReadInt() // byte array length - h := buff.ReadBytes(g) - errC := f.UnmarshalBinary(h) - if errC != nil { - return errC - } - target.Start = *f + v9 := new(time.Time) + v10 := buff.ReadInt() // byte array length + v11 := buff.ReadBytes(v10) + v12 := v9.UnmarshalBinary(v11) + if v12 != nil { + return v12 + } + v8 = *v9 // --- [end][read][reference](time.Time) --- - + target.Start = v8 + var v13 time.Time // --- [begin][read][reference](time.Time) --- - l := new(time.Time) - m := buff.ReadInt() // byte array length - n := buff.ReadBytes(m) - errD := l.UnmarshalBinary(n) - if errD != nil { - return errD - } - target.End = *l + v14 := new(time.Time) + v15 := buff.ReadInt() // byte array length + v16 := buff.ReadBytes(v15) + v17 := v14.UnmarshalBinary(v16) + if v17 != nil { + return v17 + } + v13 = *v14 // --- [end][read][reference](time.Time) --- - - o := buff.ReadFloat64() // read float64 - target.CPUCoreHours = o - - p := buff.ReadFloat64() // read float64 - target.CPUCoreRequestAverage = p - - q := buff.ReadFloat64() // read float64 - target.CPUCoreUsageAverage = q - - r := buff.ReadFloat64() // read float64 - target.CPUCost = r - - s := buff.ReadFloat64() // read float64 - target.CPUCostAdjustment = s - - t := buff.ReadFloat64() // read float64 - target.GPUHours = t - - u := buff.ReadFloat64() // read float64 - target.GPUCost = u - - w := buff.ReadFloat64() // read float64 - target.GPUCostAdjustment = w - - x := buff.ReadFloat64() // read float64 - target.NetworkTransferBytes = x - - y := buff.ReadFloat64() // read float64 - target.NetworkReceiveBytes = y - - aa := buff.ReadFloat64() // read float64 - target.NetworkCost = aa - - bb := buff.ReadFloat64() // read float64 - target.NetworkCostAdjustment = bb - - cc := buff.ReadFloat64() // read float64 - target.LoadBalancerCost = cc - - dd := buff.ReadFloat64() // read float64 - target.LoadBalancerCostAdjustment = dd - + target.End = v13 + var v18 float64 + v18 = buff.ReadFloat64() + target.CPUCoreHours = v18 + var v19 float64 + v19 = buff.ReadFloat64() + target.CPUCoreRequestAverage = v19 + var v20 float64 + v20 = buff.ReadFloat64() + target.CPUCoreUsageAverage = v20 + var v21 float64 + v21 = buff.ReadFloat64() + target.CPUCost = v21 + var v22 float64 + v22 = buff.ReadFloat64() + target.CPUCostAdjustment = v22 + var v23 float64 + v23 = buff.ReadFloat64() + target.GPUHours = v23 + var v24 float64 + v24 = buff.ReadFloat64() + target.GPUCost = v24 + var v25 float64 + v25 = buff.ReadFloat64() + target.GPUCostAdjustment = v25 + var v26 float64 + v26 = buff.ReadFloat64() + target.NetworkTransferBytes = v26 + var v27 float64 + v27 = buff.ReadFloat64() + target.NetworkReceiveBytes = v27 + var v28 float64 + v28 = buff.ReadFloat64() + target.NetworkCost = v28 + var v29 float64 + v29 = buff.ReadFloat64() + target.NetworkCostAdjustment = v29 + var v30 float64 + v30 = buff.ReadFloat64() + target.LoadBalancerCost = v30 + var v31 float64 + v31 = buff.ReadFloat64() + target.LoadBalancerCostAdjustment = v31 + var v32 PVAllocations // --- [begin][read][alias](PVAllocations) --- - var ee map[PVKey]*PVAllocation + var v33 map[PVKey]*PVAllocation if buff.ReadUInt8() == uint8(0) { - ee = nil + v33 = nil } else { // --- [begin][read][map](map[PVKey]*PVAllocation) --- - gg := buff.ReadInt() // map len - ff := make(map[PVKey]*PVAllocation, gg) - for range gg { - + v34 := buff.ReadInt() // map len + v33 = make(map[PVKey]*PVAllocation, v34) + for range v34 { + var v35 PVKey // --- [begin][read][struct](PVKey) --- - hh := new(PVKey) + v36 := new(PVKey) buff.ReadInt() // [compatibility, unused] - errE := hh.UnmarshalBinaryWithContext(ctx) - if errE != nil { - return errE + v37 := v36.UnmarshalBinaryWithContext(ctx) + if v37 != nil { + return v37 } - v := *hh + v35 = *v36 // --- [end][read][struct](PVKey) --- - - var z *PVAllocation + var v38 *PVAllocation if buff.ReadUInt8() == uint8(0) { - z = nil + v38 = nil } else { - // --- [begin][read][struct](PVAllocation) --- - ll := new(PVAllocation) + v39 := new(PVAllocation) buff.ReadInt() // [compatibility, unused] - errF := ll.UnmarshalBinaryWithContext(ctx) - if errF != nil { - return errF + v40 := v39.UnmarshalBinaryWithContext(ctx) + if v40 != nil { + return v40 } - z = ll + v38 = v39 // --- [end][read][struct](PVAllocation) --- - } - ff[v] = z + v33[v35] = v38 } - ee = ff // --- [end][read][map](map[PVKey]*PVAllocation) --- - } - - target.PVs = PVAllocations(ee) + v32 = PVAllocations(v33) // --- [end][read][alias](PVAllocations) --- - - mm := buff.ReadFloat64() // read float64 - target.PVCostAdjustment = mm - - nn := buff.ReadFloat64() // read float64 - target.RAMByteHours = nn - - oo := buff.ReadFloat64() // read float64 - target.RAMBytesRequestAverage = oo - - pp := buff.ReadFloat64() // read float64 - target.RAMBytesUsageAverage = pp - - qq := buff.ReadFloat64() // read float64 - target.RAMCost = qq - - rr := buff.ReadFloat64() // read float64 - target.RAMCostAdjustment = rr - - ss := buff.ReadFloat64() // read float64 - target.SharedCost = ss - - tt := buff.ReadFloat64() // read float64 - target.ExternalCost = tt - + target.PVs = v32 + var v41 float64 + v41 = buff.ReadFloat64() + target.PVCostAdjustment = v41 + var v42 float64 + v42 = buff.ReadFloat64() + target.RAMByteHours = v42 + var v43 float64 + v43 = buff.ReadFloat64() + target.RAMBytesRequestAverage = v43 + var v44 float64 + v44 = buff.ReadFloat64() + target.RAMBytesUsageAverage = v44 + var v45 float64 + v45 = buff.ReadFloat64() + target.RAMCost = v45 + var v46 float64 + v46 = buff.ReadFloat64() + target.RAMCostAdjustment = v46 + var v47 float64 + v47 = buff.ReadFloat64() + target.SharedCost = v47 + var v48 float64 + v48 = buff.ReadFloat64() + target.ExternalCost = v48 + var v49 *RawAllocationOnlyData if buff.ReadUInt8() == uint8(0) { - target.RawAllocationOnly = nil + v49 = nil } else { - // --- [begin][read][struct](RawAllocationOnlyData) --- - uu := new(RawAllocationOnlyData) + v50 := new(RawAllocationOnlyData) buff.ReadInt() // [compatibility, unused] - errG := uu.UnmarshalBinaryWithContext(ctx) - if errG != nil { - return errG + v51 := v50.UnmarshalBinaryWithContext(ctx) + if v51 != nil { + return v51 } - target.RawAllocationOnly = uu + v49 = v50 // --- [end][read][struct](RawAllocationOnlyData) --- - } - - // field version check + target.RawAllocationOnly = v49 if uint8(16) <= version { - - ww := buff.ReadInt() // read int - target.TestProperty = ww - + var v52 int + v52 = buff.ReadInt() + target.TestProperty = v52 } else { - target.TestProperty = int(0) // default + target.TestProperty = int(0) } - // field version check if uint8(16) <= version { - - var yy string + var v53 string if ctx.IsStringTable() { - aaa := buff.ReadInt() // read string index - yy = ctx.Table.At(aaa) + v54 := buff.ReadInt() // read string index + v53 = ctx.Table.At(v54) } else { - yy = buff.ReadString() // read string + v53 = buff.ReadString() // read string } - xx := yy - target.TestStr = xx - + target.TestStr = v53 } else { - target.TestStr = "test" // default + target.TestStr = "test" } return nil @@ -883,136 +831,115 @@ func (target *AllocationProperties) MarshalBinaryWithContext(ctx *EncodingContex buff.WriteUInt8(AllocationCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Cluster) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Cluster) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Cluster) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(target.Node) - buff.WriteInt(b) // write table index + v1 := ctx.Table.AddOrGet(target.Node) + buff.WriteInt(v1) // write table index } else { buff.WriteString(target.Node) // write string } - if ctx.IsStringTable() { - c := ctx.Table.AddOrGet(target.Container) - buff.WriteInt(c) // write table index + v2 := ctx.Table.AddOrGet(target.Container) + buff.WriteInt(v2) // write table index } else { buff.WriteString(target.Container) // write string } - if ctx.IsStringTable() { - d := ctx.Table.AddOrGet(target.Controller) - buff.WriteInt(d) // write table index + v3 := ctx.Table.AddOrGet(target.Controller) + buff.WriteInt(v3) // write table index } else { buff.WriteString(target.Controller) // write string } - if ctx.IsStringTable() { - e := ctx.Table.AddOrGet(target.ControllerKind) - buff.WriteInt(e) // write table index + v4 := ctx.Table.AddOrGet(target.ControllerKind) + buff.WriteInt(v4) // write table index } else { buff.WriteString(target.ControllerKind) // write string } - if ctx.IsStringTable() { - f := ctx.Table.AddOrGet(target.Namespace) - buff.WriteInt(f) // write table index + v5 := ctx.Table.AddOrGet(target.Namespace) + buff.WriteInt(v5) // write table index } else { buff.WriteString(target.Namespace) // write string } - if ctx.IsStringTable() { - g := ctx.Table.AddOrGet(target.Pod) - buff.WriteInt(g) // write table index + v6 := ctx.Table.AddOrGet(target.Pod) + buff.WriteInt(v6) // write table index } else { buff.WriteString(target.Pod) // write string } - if target.Services == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Services)) // slice length - for i := range target.Services { + for v7 := range target.Services { if ctx.IsStringTable() { - h := ctx.Table.AddOrGet(target.Services[i]) - buff.WriteInt(h) // write table index + v8 := ctx.Table.AddOrGet(target.Services[v7]) + buff.WriteInt(v8) // write table index } else { - buff.WriteString(target.Services[i]) // write string + buff.WriteString(target.Services[v7]) // write string } - } // --- [end][write][slice]([]string) --- - } - if ctx.IsStringTable() { - l := ctx.Table.AddOrGet(target.ProviderID) - buff.WriteInt(l) // write table index + v9 := ctx.Table.AddOrGet(target.ProviderID) + buff.WriteInt(v9) // write table index } else { buff.WriteString(target.ProviderID) // write string } - // --- [begin][write][alias](AllocationLabels) --- if map[string]string(target.Labels) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.Labels))) // map length - for v, z := range map[string]string(target.Labels) { + for v10, v11 := range map[string]string(target.Labels) { if ctx.IsStringTable() { - m := ctx.Table.AddOrGet(v) - buff.WriteInt(m) // write table index + v12 := ctx.Table.AddOrGet(v10) + buff.WriteInt(v12) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v10) // write string } - if ctx.IsStringTable() { - n := ctx.Table.AddOrGet(z) - buff.WriteInt(n) // write table index + v13 := ctx.Table.AddOrGet(v11) + buff.WriteInt(v13) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v11) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AllocationLabels) --- - // --- [begin][write][alias](AllocationAnnotations) --- if map[string]string(target.Annotations) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.Annotations))) // map length - for vv, zz := range map[string]string(target.Annotations) { + for v14, v15 := range map[string]string(target.Annotations) { if ctx.IsStringTable() { - o := ctx.Table.AddOrGet(vv) - buff.WriteInt(o) // write table index + v16 := ctx.Table.AddOrGet(v14) + buff.WriteInt(v16) // write table index } else { - buff.WriteString(vv) // write string + buff.WriteString(v14) // write string } - if ctx.IsStringTable() { - p := ctx.Table.AddOrGet(zz) - buff.WriteInt(p) // write table index + v17 := ctx.Table.AddOrGet(v15) + buff.WriteInt(v17) // write table index } else { - buff.WriteString(zz) // write string + buff.WriteString(v15) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AllocationAnnotations) --- @@ -1070,192 +997,152 @@ func (target *AllocationProperties) UnmarshalBinaryWithContext(ctx *DecodingCont return fmt.Errorf("Invalid Version Unmarshalling AllocationProperties. Expected %d or less, got %d", AllocationCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Cluster = a - - var e string + target.Cluster = v0 + var v2 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v3 := buff.ReadInt() // read string index + v2 = ctx.Table.At(v3) } else { - e = buff.ReadString() // read string + v2 = buff.ReadString() // read string } - d := e - target.Node = d - - var h string + target.Node = v2 + var v4 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v5 := buff.ReadInt() // read string index + v4 = ctx.Table.At(v5) } else { - h = buff.ReadString() // read string + v4 = buff.ReadString() // read string } - g := h - target.Container = g - - var n string + target.Container = v4 + var v6 string if ctx.IsStringTable() { - o := buff.ReadInt() // read string index - n = ctx.Table.At(o) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - n = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - m := n - target.Controller = m - - var q string + target.Controller = v6 + var v8 string if ctx.IsStringTable() { - r := buff.ReadInt() // read string index - q = ctx.Table.At(r) + v9 := buff.ReadInt() // read string index + v8 = ctx.Table.At(v9) } else { - q = buff.ReadString() // read string + v8 = buff.ReadString() // read string } - p := q - target.ControllerKind = p - - var t string + target.ControllerKind = v8 + var v10 string if ctx.IsStringTable() { - u := buff.ReadInt() // read string index - t = ctx.Table.At(u) + v11 := buff.ReadInt() // read string index + v10 = ctx.Table.At(v11) } else { - t = buff.ReadString() // read string + v10 = buff.ReadString() // read string } - s := t - target.Namespace = s - - var x string + target.Namespace = v10 + var v12 string if ctx.IsStringTable() { - y := buff.ReadInt() // read string index - x = ctx.Table.At(y) + v13 := buff.ReadInt() // read string index + v12 = ctx.Table.At(v13) } else { - x = buff.ReadString() // read string + v12 = buff.ReadString() // read string } - w := x - target.Pod = w - + target.Pod = v12 + var v14 []string if buff.ReadUInt8() == uint8(0) { - target.Services = nil + v14 = nil } else { // --- [begin][read][slice]([]string) --- - bb := buff.ReadInt() // slice len - aa := make([]string, bb) - for i := range bb { - var cc string - var ee string + v15 := buff.ReadInt() // slice len + v14 = make([]string, v15) + for v16 := range v15 { + var v17 string if ctx.IsStringTable() { - ff := buff.ReadInt() // read string index - ee = ctx.Table.At(ff) + v18 := buff.ReadInt() // read string index + v17 = ctx.Table.At(v18) } else { - ee = buff.ReadString() // read string + v17 = buff.ReadString() // read string } - dd := ee - cc = dd - - aa[i] = cc + v14[v16] = v17 } - target.Services = aa // --- [end][read][slice]([]string) --- - } - - var hh string + target.Services = v14 + var v19 string if ctx.IsStringTable() { - ll := buff.ReadInt() // read string index - hh = ctx.Table.At(ll) + v20 := buff.ReadInt() // read string index + v19 = ctx.Table.At(v20) } else { - hh = buff.ReadString() // read string + v19 = buff.ReadString() // read string } - gg := hh - target.ProviderID = gg - + target.ProviderID = v19 + var v21 AllocationLabels // --- [begin][read][alias](AllocationLabels) --- - var mm map[string]string + var v22 map[string]string if buff.ReadUInt8() == uint8(0) { - mm = nil + v22 = nil } else { // --- [begin][read][map](map[string]string) --- - oo := buff.ReadInt() // map len - nn := make(map[string]string, oo) - for range oo { - var v string - var qq string + v23 := buff.ReadInt() // map len + v22 = make(map[string]string, v23) + for range v23 { + var v24 string if ctx.IsStringTable() { - rr := buff.ReadInt() // read string index - qq = ctx.Table.At(rr) + v25 := buff.ReadInt() // read string index + v24 = ctx.Table.At(v25) } else { - qq = buff.ReadString() // read string + v24 = buff.ReadString() // read string } - pp := qq - v = pp - - var z string - var tt string + var v26 string if ctx.IsStringTable() { - uu := buff.ReadInt() // read string index - tt = ctx.Table.At(uu) + v27 := buff.ReadInt() // read string index + v26 = ctx.Table.At(v27) } else { - tt = buff.ReadString() // read string + v26 = buff.ReadString() // read string } - ss := tt - z = ss - - nn[v] = z + v22[v24] = v26 } - mm = nn // --- [end][read][map](map[string]string) --- - } - - target.Labels = AllocationLabels(mm) + v21 = AllocationLabels(v22) // --- [end][read][alias](AllocationLabels) --- - + target.Labels = v21 + var v28 AllocationAnnotations // --- [begin][read][alias](AllocationAnnotations) --- - var ww map[string]string + var v29 map[string]string if buff.ReadUInt8() == uint8(0) { - ww = nil + v29 = nil } else { // --- [begin][read][map](map[string]string) --- - yy := buff.ReadInt() // map len - xx := make(map[string]string, yy) - for range yy { - var vv string - var bbb string + v30 := buff.ReadInt() // map len + v29 = make(map[string]string, v30) + for range v30 { + var v31 string if ctx.IsStringTable() { - ccc := buff.ReadInt() // read string index - bbb = ctx.Table.At(ccc) + v32 := buff.ReadInt() // read string index + v31 = ctx.Table.At(v32) } else { - bbb = buff.ReadString() // read string + v31 = buff.ReadString() // read string } - aaa := bbb - vv = aaa - - var zz string - var eee string + var v33 string if ctx.IsStringTable() { - fff := buff.ReadInt() // read string index - eee = ctx.Table.At(fff) + v34 := buff.ReadInt() // read string index + v33 = ctx.Table.At(v34) } else { - eee = buff.ReadString() // read string + v33 = buff.ReadString() // read string } - ddd := eee - zz = ddd - - xx[vv] = zz + v29[v31] = v33 } - ww = xx // --- [end][read][map](map[string]string) --- - } - - target.Annotations = AllocationAnnotations(ww) + v28 = AllocationAnnotations(v29) // --- [end][read][alias](AllocationAnnotations) --- + target.Annotations = v28 return nil } @@ -1323,129 +1210,108 @@ func (target *AllocationSet) MarshalBinaryWithContext(ctx *EncodingContext) (err buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]*Allocation) --- buff.WriteInt(len(target.allocations)) // map length - for v, z := range target.allocations { + for v0, v1 := range target.allocations { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(v0) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v0) // write string } - if z == nil { + if v1 == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](Allocation) --- buff.WriteInt(0) // [compatibility, unused] - errA := z.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v3 := v1.MarshalBinaryWithContext(ctx) + if v3 != nil { + return v3 } // --- [end][write][struct](Allocation) --- - } } // --- [end][write][map](map[string]*Allocation) --- - } if target.externalKeys == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]bool) --- buff.WriteInt(len(target.externalKeys)) // map length - for vv, zz := range target.externalKeys { + for v4, v5 := range target.externalKeys { if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(vv) - buff.WriteInt(b) // write table index + v6 := ctx.Table.AddOrGet(v4) + buff.WriteInt(v6) // write table index } else { - buff.WriteString(vv) // write string + buff.WriteString(v4) // write string } - - buff.WriteBool(zz) // write bool - + buff.WriteBool(v5) } // --- [end][write][map](map[string]bool) --- - } if target.idleKeys == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]bool) --- buff.WriteInt(len(target.idleKeys)) // map length - for vvv, zzz := range target.idleKeys { + for v7, v8 := range target.idleKeys { if ctx.IsStringTable() { - c := ctx.Table.AddOrGet(vvv) - buff.WriteInt(c) // write table index + v9 := ctx.Table.AddOrGet(v7) + buff.WriteInt(v9) // write table index } else { - buff.WriteString(vvv) // write string + buff.WriteString(v7) // write string } - - buff.WriteBool(zzz) // write bool - + buff.WriteBool(v8) } // --- [end][write][map](map[string]bool) --- - } - if ctx.IsStringTable() { - d := ctx.Table.AddOrGet(target.FromSource) - buff.WriteInt(d) // write table index + v10 := ctx.Table.AddOrGet(target.FromSource) + buff.WriteInt(v10) // write table index } else { buff.WriteString(target.FromSource) // write string } - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errB := target.Window.MarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v11 := target.Window.MarshalBinaryWithContext(ctx) + if v11 != nil { + return v11 } // --- [end][write][struct](Window) --- - if target.Warnings == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Warnings)) // slice length - for i := range target.Warnings { + for v12 := range target.Warnings { if ctx.IsStringTable() { - e := ctx.Table.AddOrGet(target.Warnings[i]) - buff.WriteInt(e) // write table index + v13 := ctx.Table.AddOrGet(target.Warnings[v12]) + buff.WriteInt(v13) // write table index } else { - buff.WriteString(target.Warnings[i]) // write string + buff.WriteString(target.Warnings[v12]) // write string } - } // --- [end][write][slice]([]string) --- - } if target.Errors == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Errors)) // slice length - for j := range target.Errors { + for v14 := range target.Errors { if ctx.IsStringTable() { - f := ctx.Table.AddOrGet(target.Errors[j]) - buff.WriteInt(f) // write table index + v15 := ctx.Table.AddOrGet(target.Errors[v14]) + buff.WriteInt(v15) // write table index } else { - buff.WriteString(target.Errors[j]) // write string + buff.WriteString(target.Errors[v14]) // write string } - } // --- [end][write][slice]([]string) --- - } return nil @@ -1502,173 +1368,143 @@ func (target *AllocationSet) UnmarshalBinaryWithContext(ctx *DecodingContext) (e return fmt.Errorf("Invalid Version Unmarshalling AllocationSet. Expected %d or less, got %d", AllocationCodecVersion, version) } + var v0 map[string]*Allocation if buff.ReadUInt8() == uint8(0) { - target.allocations = nil + v0 = nil } else { // --- [begin][read][map](map[string]*Allocation) --- - b := buff.ReadInt() // map len - a := make(map[string]*Allocation, b) - for range b { - var v string - var d string + v1 := buff.ReadInt() // map len + v0 = make(map[string]*Allocation, v1) + for range v1 { + var v2 string if ctx.IsStringTable() { - e := buff.ReadInt() // read string index - d = ctx.Table.At(e) + v3 := buff.ReadInt() // read string index + v2 = ctx.Table.At(v3) } else { - d = buff.ReadString() // read string + v2 = buff.ReadString() // read string } - c := d - v = c - - var z *Allocation + var v4 *Allocation if buff.ReadUInt8() == uint8(0) { - z = nil + v4 = nil } else { // --- [begin][read][struct](Allocation) --- - f := new(Allocation) + v5 := new(Allocation) buff.ReadInt() // [compatibility, unused] - errA := f.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v6 := v5.UnmarshalBinaryWithContext(ctx) + if v6 != nil { + return v6 } - z = f + v4 = v5 // --- [end][read][struct](Allocation) --- - } - a[v] = z + v0[v2] = v4 } - target.allocations = a // --- [end][read][map](map[string]*Allocation) --- - } - + target.allocations = v0 + var v7 map[string]bool if buff.ReadUInt8() == uint8(0) { - target.externalKeys = nil + v7 = nil } else { // --- [begin][read][map](map[string]bool) --- - h := buff.ReadInt() // map len - g := make(map[string]bool, h) - for range h { - var vv string - var m string + v8 := buff.ReadInt() // map len + v7 = make(map[string]bool, v8) + for range v8 { + var v9 string if ctx.IsStringTable() { - n := buff.ReadInt() // read string index - m = ctx.Table.At(n) + v10 := buff.ReadInt() // read string index + v9 = ctx.Table.At(v10) } else { - m = buff.ReadString() // read string + v9 = buff.ReadString() // read string } - l := m - vv = l - - var zz bool - o := buff.ReadBool() // read bool - zz = o - - g[vv] = zz + var v11 bool + v11 = buff.ReadBool() + v7[v9] = v11 } - target.externalKeys = g // --- [end][read][map](map[string]bool) --- - } - + target.externalKeys = v7 + var v12 map[string]bool if buff.ReadUInt8() == uint8(0) { - target.idleKeys = nil + v12 = nil } else { // --- [begin][read][map](map[string]bool) --- - q := buff.ReadInt() // map len - p := make(map[string]bool, q) - for range q { - var vvv string - var s string + v13 := buff.ReadInt() // map len + v12 = make(map[string]bool, v13) + for range v13 { + var v14 string if ctx.IsStringTable() { - t := buff.ReadInt() // read string index - s = ctx.Table.At(t) + v15 := buff.ReadInt() // read string index + v14 = ctx.Table.At(v15) } else { - s = buff.ReadString() // read string + v14 = buff.ReadString() // read string } - r := s - vvv = r - - var zzz bool - u := buff.ReadBool() // read bool - zzz = u - - p[vvv] = zzz + var v16 bool + v16 = buff.ReadBool() + v12[v14] = v16 } - target.idleKeys = p // --- [end][read][map](map[string]bool) --- - } - - var x string + target.idleKeys = v12 + var v17 string if ctx.IsStringTable() { - y := buff.ReadInt() // read string index - x = ctx.Table.At(y) + v18 := buff.ReadInt() // read string index + v17 = ctx.Table.At(v18) } else { - x = buff.ReadString() // read string + v17 = buff.ReadString() // read string } - w := x - target.FromSource = w - + target.FromSource = v17 + var v19 Window // --- [begin][read][struct](Window) --- - aa := new(Window) + v20 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := aa.UnmarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v21 := v20.UnmarshalBinaryWithContext(ctx) + if v21 != nil { + return v21 } - target.Window = *aa + v19 = *v20 // --- [end][read][struct](Window) --- - + target.Window = v19 + var v22 []string if buff.ReadUInt8() == uint8(0) { - target.Warnings = nil + v22 = nil } else { // --- [begin][read][slice]([]string) --- - cc := buff.ReadInt() // slice len - bb := make([]string, cc) - for i := range cc { - var dd string - var ff string + v23 := buff.ReadInt() // slice len + v22 = make([]string, v23) + for v24 := range v23 { + var v25 string if ctx.IsStringTable() { - gg := buff.ReadInt() // read string index - ff = ctx.Table.At(gg) + v26 := buff.ReadInt() // read string index + v25 = ctx.Table.At(v26) } else { - ff = buff.ReadString() // read string + v25 = buff.ReadString() // read string } - ee := ff - dd = ee - - bb[i] = dd + v22[v24] = v25 } - target.Warnings = bb // --- [end][read][slice]([]string) --- - } - + target.Warnings = v22 + var v27 []string if buff.ReadUInt8() == uint8(0) { - target.Errors = nil + v27 = nil } else { // --- [begin][read][slice]([]string) --- - ll := buff.ReadInt() // slice len - hh := make([]string, ll) - for j := range ll { - var mm string - var oo string + v28 := buff.ReadInt() // slice len + v27 = make([]string, v28) + for v29 := range v28 { + var v30 string if ctx.IsStringTable() { - pp := buff.ReadInt() // read string index - oo = ctx.Table.At(pp) + v31 := buff.ReadInt() // read string index + v30 = ctx.Table.At(v31) } else { - oo = buff.ReadString() // read string + v30 = buff.ReadString() // read string } - nn := oo - mm = nn - - hh[j] = mm + v27[v29] = v30 } - target.Errors = hh // --- [end][read][slice]([]string) --- - } + target.Errors = v27 return nil } @@ -1735,45 +1571,36 @@ func (stream *AllocationSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, * } } else { // --- [begin][read][streaming-map](map[string]*Allocation) --- - a := buff.ReadInt() // map len - for range a { - var v string - var c string + v0 := buff.ReadInt() // map len + for range v0 { + var v1 string if ctx.IsStringTable() { - d := buff.ReadInt() // read string index - c = ctx.Table.At(d) + v2 := buff.ReadInt() // read string index + v1 = ctx.Table.At(v2) } else { - c = buff.ReadString() // read string + v1 = buff.ReadString() // read string } - b := c - v = b - - var z *Allocation + var v3 *Allocation if buff.ReadUInt8() == uint8(0) { - z = nil + v3 = nil } else { // --- [begin][read][struct](Allocation) --- - e := new(Allocation) + v4 := new(Allocation) buff.ReadInt() // [compatibility, unused] - errA := e.UnmarshalBinaryWithContext(ctx) - if errA != nil { - stream.err = errA + v5 := v4.UnmarshalBinaryWithContext(ctx) + if v5 != nil { + stream.err = v5 return - } - z = e + v3 = v4 // --- [end][read][struct](Allocation) --- - } - - if !yield(fi, bstream.PairV(v, z)) { + if !yield(fi, bstream.PairV(v1, v3)) { return } } // --- [end][read][streaming-map](map[string]*Allocation) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[map[string]bool](), Name: "externalKeys", @@ -1784,31 +1611,23 @@ func (stream *AllocationSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, * } } else { // --- [begin][read][streaming-map](map[string]bool) --- - f := buff.ReadInt() // map len - for range f { - var vv string - var h string + v6 := buff.ReadInt() // map len + for range v6 { + var v7 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v8 := buff.ReadInt() // read string index + v7 = ctx.Table.At(v8) } else { - h = buff.ReadString() // read string + v7 = buff.ReadString() // read string } - g := h - vv = g - - var zz bool - m := buff.ReadBool() // read bool - zz = m - - if !yield(fi, bstream.PairV(vv, zz)) { + var v9 bool + v9 = buff.ReadBool() + if !yield(fi, bstream.PairV(v7, v9)) { return } } // --- [end][read][streaming-map](map[string]bool) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[map[string]bool](), Name: "idleKeys", @@ -1819,70 +1638,55 @@ func (stream *AllocationSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, * } } else { // --- [begin][read][streaming-map](map[string]bool) --- - n := buff.ReadInt() // map len - for range n { - var vvv string - var p string + v10 := buff.ReadInt() // map len + for range v10 { + var v11 string if ctx.IsStringTable() { - q := buff.ReadInt() // read string index - p = ctx.Table.At(q) + v12 := buff.ReadInt() // read string index + v11 = ctx.Table.At(v12) } else { - p = buff.ReadString() // read string + v11 = buff.ReadString() // read string } - o := p - vvv = o - - var zzz bool - r := buff.ReadBool() // read bool - zzz = r - - if !yield(fi, bstream.PairV(vvv, zzz)) { + var v13 bool + v13 = buff.ReadBool() + if !yield(fi, bstream.PairV(v11, v13)) { return } } // --- [end][read][streaming-map](map[string]bool) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[string](), Name: "FromSource", } - - var s string - var u string + var v14 string if ctx.IsStringTable() { - w := buff.ReadInt() // read string index - u = ctx.Table.At(w) + v15 := buff.ReadInt() // read string index + v14 = ctx.Table.At(v15) } else { - u = buff.ReadString() // read string + v14 = buff.ReadString() // read string } - t := u - s = t - if !yield(fi, bstream.SingleV(s)) { + if !yield(fi, bstream.SingleV(v14)) { return } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[Window](), Name: "Window", } - + var v16 Window // --- [begin][read][struct](Window) --- - y := new(Window) + v17 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := y.UnmarshalBinaryWithContext(ctx) - if errB != nil { - stream.err = errB + v18 := v17.UnmarshalBinaryWithContext(ctx) + if v18 != nil { + stream.err = v18 return - } - x := *y + v16 = *v17 // --- [end][read][struct](Window) --- - if !yield(fi, bstream.SingleV(x)) { + if !yield(fi, bstream.SingleV(v16)) { return } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[[]string](), Name: "Warnings", @@ -1893,28 +1697,21 @@ func (stream *AllocationSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, * } } else { // --- [begin][read][streaming-slice]([]string) --- - aa := buff.ReadInt() // slice len - for i := range aa { - - var bb string - var dd string + v19 := buff.ReadInt() // slice len + for v20 := range v19 { + var v21 string if ctx.IsStringTable() { - ee := buff.ReadInt() // read string index - dd = ctx.Table.At(ee) + v22 := buff.ReadInt() // read string index + v21 = ctx.Table.At(v22) } else { - dd = buff.ReadString() // read string + v21 = buff.ReadString() // read string } - cc := dd - bb = cc - - if !yield(fi, bstream.PairV(i, bb)) { + if !yield(fi, bstream.PairV(v20, v21)) { return } } // --- [end][read][streaming-slice]([]string) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[[]string](), Name: "Errors", @@ -1925,28 +1722,21 @@ func (stream *AllocationSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, * } } else { // --- [begin][read][streaming-slice]([]string) --- - ff := buff.ReadInt() // slice len - for j := range ff { - - var gg string - var ll string + v23 := buff.ReadInt() // slice len + for v24 := range v23 { + var v25 string if ctx.IsStringTable() { - mm := buff.ReadInt() // read string index - ll = ctx.Table.At(mm) + v26 := buff.ReadInt() // read string index + v25 = ctx.Table.At(v26) } else { - ll = buff.ReadString() // read string + v25 = buff.ReadString() // read string } - hh := ll - gg = hh - - if !yield(fi, bstream.PairV(j, gg)) { + if !yield(fi, bstream.PairV(v24, v25)) { return } } // --- [end][read][streaming-slice]([]string) --- - } - } } @@ -2001,32 +1791,27 @@ func (target *AllocationSetRange) MarshalBinaryWithContext(ctx *EncodingContext) buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]*AllocationSet) --- buff.WriteInt(len(target.allocations)) // slice length - for i := range target.allocations { - if target.allocations[i] == nil { + for v0 := range target.allocations { + if target.allocations[v0] == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AllocationSet) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.allocations[i].MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v1 := target.allocations[v0].MarshalBinaryWithContext(ctx) + if v1 != nil { + return v1 } // --- [end][write][struct](AllocationSet) --- - } } // --- [end][write][slice]([]*AllocationSet) --- - } - if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.FromStore) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(target.FromStore) + buff.WriteInt(v2) // write table index } else { buff.WriteString(target.FromStore) // write string } @@ -2085,45 +1870,41 @@ func (target *AllocationSetRange) UnmarshalBinaryWithContext(ctx *DecodingContex return fmt.Errorf("Invalid Version Unmarshalling AllocationSetRange. Expected %d or less, got %d", AllocationCodecVersion, version) } + var v0 []*AllocationSet if buff.ReadUInt8() == uint8(0) { - target.allocations = nil + v0 = nil } else { // --- [begin][read][slice]([]*AllocationSet) --- - b := buff.ReadInt() // slice len - a := make([]*AllocationSet, b) - for i := range b { - var c *AllocationSet + v1 := buff.ReadInt() // slice len + v0 = make([]*AllocationSet, v1) + for v2 := range v1 { + var v3 *AllocationSet if buff.ReadUInt8() == uint8(0) { - c = nil + v3 = nil } else { // --- [begin][read][struct](AllocationSet) --- - d := new(AllocationSet) + v4 := new(AllocationSet) buff.ReadInt() // [compatibility, unused] - errA := d.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v5 := v4.UnmarshalBinaryWithContext(ctx) + if v5 != nil { + return v5 } - c = d + v3 = v4 // --- [end][read][struct](AllocationSet) --- - } - - a[i] = c + v0[v2] = v3 } - target.allocations = a // --- [end][read][slice]([]*AllocationSet) --- - } - - var f string + target.allocations = v0 + var v6 string if ctx.IsStringTable() { - g := buff.ReadInt() // read string index - f = ctx.Table.At(g) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - f = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - e := f - target.FromStore = e + target.FromStore = v6 return nil } @@ -2180,73 +1961,62 @@ func (target *Any) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v0, v1 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(v0) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v0) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v1) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- if target.properties == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v4 := target.properties.MarshalBinaryWithContext(ctx) + if v4 != nil { + return v4 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][reference](time.Time) --- - c, errB := target.start.MarshalBinary() - if errB != nil { - return errB + v5, v6 := target.start.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - d, errC := target.end.MarshalBinary() - if errC != nil { - return errC + v7, v8 := target.end.MarshalBinary() + if v8 != nil { + return v8 } - buff.WriteInt(len(d)) - buff.WriteBytes(d) + buff.WriteInt(len(v7)) + buff.WriteBytes(v7) // --- [end][write][reference](time.Time) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errD := target.window.MarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v9 := target.window.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.adjustment) // write float64 - - buff.WriteFloat64(target.Cost) // write float64 + buff.WriteFloat64(target.adjustment) + buff.WriteFloat64(target.Cost) return nil } @@ -2302,100 +2072,93 @@ func (target *Any) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) return fmt.Errorf("Invalid Version Unmarshalling Any. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var a map[string]string + var v1 map[string]string if buff.ReadUInt8() == uint8(0) { - a = nil + v1 = nil } else { // --- [begin][read][map](map[string]string) --- - c := buff.ReadInt() // map len - b := make(map[string]string, c) - for range c { - var v string - var e string + v2 := buff.ReadInt() // map len + v1 = make(map[string]string, v2) + for range v2 { + var v3 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v4 := buff.ReadInt() // read string index + v3 = ctx.Table.At(v4) } else { - e = buff.ReadString() // read string + v3 = buff.ReadString() // read string } - d := e - v = d - - var z string - var h string + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - z = g - - b[v] = z + v1[v3] = v5 } - a = b // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(a) + v0 = AssetLabels(v1) // --- [end][read][alias](AssetLabels) --- - + target.labels = v0 + var v7 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v7 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - m := new(AssetProperties) + v8 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := m.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v9 := v8.UnmarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } - target.properties = m + v7 = v8 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v7 + var v10 time.Time // --- [begin][read][reference](time.Time) --- - n := new(time.Time) - o := buff.ReadInt() // byte array length - p := buff.ReadBytes(o) - errB := n.UnmarshalBinary(p) - if errB != nil { - return errB - } - target.start = *n + v11 := new(time.Time) + v12 := buff.ReadInt() // byte array length + v13 := buff.ReadBytes(v12) + v14 := v11.UnmarshalBinary(v13) + if v14 != nil { + return v14 + } + v10 = *v11 // --- [end][read][reference](time.Time) --- - + target.start = v10 + var v15 time.Time // --- [begin][read][reference](time.Time) --- - q := new(time.Time) - r := buff.ReadInt() // byte array length - s := buff.ReadBytes(r) - errC := q.UnmarshalBinary(s) - if errC != nil { - return errC - } - target.end = *q + v16 := new(time.Time) + v17 := buff.ReadInt() // byte array length + v18 := buff.ReadBytes(v17) + v19 := v16.UnmarshalBinary(v18) + if v19 != nil { + return v19 + } + v15 = *v16 // --- [end][read][reference](time.Time) --- - + target.end = v15 + var v20 Window // --- [begin][read][struct](Window) --- - t := new(Window) + v21 := new(Window) buff.ReadInt() // [compatibility, unused] - errD := t.UnmarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v22 := v21.UnmarshalBinaryWithContext(ctx) + if v22 != nil { + return v22 } - target.window = *t + v20 = *v21 // --- [end][read][struct](Window) --- - - u := buff.ReadFloat64() // read float64 - target.adjustment = u - - w := buff.ReadFloat64() // read float64 - target.Cost = w + target.window = v20 + var v23 float64 + v23 = buff.ReadFloat64() + target.adjustment = v23 + var v24 float64 + v24 = buff.ReadFloat64() + target.Cost = v24 return nil } @@ -2448,57 +2211,50 @@ func (target *AssetProperties) MarshalBinaryWithContext(ctx *EncodingContext) (e buff.WriteUInt8(AssetsCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Category) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Category) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Category) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(target.Provider) - buff.WriteInt(b) // write table index + v1 := ctx.Table.AddOrGet(target.Provider) + buff.WriteInt(v1) // write table index } else { buff.WriteString(target.Provider) // write string } - if ctx.IsStringTable() { - c := ctx.Table.AddOrGet(target.Account) - buff.WriteInt(c) // write table index + v2 := ctx.Table.AddOrGet(target.Account) + buff.WriteInt(v2) // write table index } else { buff.WriteString(target.Account) // write string } - if ctx.IsStringTable() { - d := ctx.Table.AddOrGet(target.Project) - buff.WriteInt(d) // write table index + v3 := ctx.Table.AddOrGet(target.Project) + buff.WriteInt(v3) // write table index } else { buff.WriteString(target.Project) // write string } - if ctx.IsStringTable() { - e := ctx.Table.AddOrGet(target.Service) - buff.WriteInt(e) // write table index + v4 := ctx.Table.AddOrGet(target.Service) + buff.WriteInt(v4) // write table index } else { buff.WriteString(target.Service) // write string } - if ctx.IsStringTable() { - f := ctx.Table.AddOrGet(target.Cluster) - buff.WriteInt(f) // write table index + v5 := ctx.Table.AddOrGet(target.Cluster) + buff.WriteInt(v5) // write table index } else { buff.WriteString(target.Cluster) // write string } - if ctx.IsStringTable() { - g := ctx.Table.AddOrGet(target.Name) - buff.WriteInt(g) // write table index + v6 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v6) // write table index } else { buff.WriteString(target.Name) // write string } - if ctx.IsStringTable() { - h := ctx.Table.AddOrGet(target.ProviderID) - buff.WriteInt(h) // write table index + v7 := ctx.Table.AddOrGet(target.ProviderID) + buff.WriteInt(v7) // write table index } else { buff.WriteString(target.ProviderID) // write string } @@ -2557,85 +2313,70 @@ func (target *AssetProperties) UnmarshalBinaryWithContext(ctx *DecodingContext) return fmt.Errorf("Invalid Version Unmarshalling AssetProperties. Expected %d or less, got %d", AssetsCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Category = a - - var e string + target.Category = v0 + var v2 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v3 := buff.ReadInt() // read string index + v2 = ctx.Table.At(v3) } else { - e = buff.ReadString() // read string + v2 = buff.ReadString() // read string } - d := e - target.Provider = d - - var h string + target.Provider = v2 + var v4 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v5 := buff.ReadInt() // read string index + v4 = ctx.Table.At(v5) } else { - h = buff.ReadString() // read string + v4 = buff.ReadString() // read string } - g := h - target.Account = g - - var n string + target.Account = v4 + var v6 string if ctx.IsStringTable() { - o := buff.ReadInt() // read string index - n = ctx.Table.At(o) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - n = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - m := n - target.Project = m - - var q string + target.Project = v6 + var v8 string if ctx.IsStringTable() { - r := buff.ReadInt() // read string index - q = ctx.Table.At(r) + v9 := buff.ReadInt() // read string index + v8 = ctx.Table.At(v9) } else { - q = buff.ReadString() // read string + v8 = buff.ReadString() // read string } - p := q - target.Service = p - - var t string + target.Service = v8 + var v10 string if ctx.IsStringTable() { - u := buff.ReadInt() // read string index - t = ctx.Table.At(u) + v11 := buff.ReadInt() // read string index + v10 = ctx.Table.At(v11) } else { - t = buff.ReadString() // read string + v10 = buff.ReadString() // read string } - s := t - target.Cluster = s - - var x string + target.Cluster = v10 + var v12 string if ctx.IsStringTable() { - y := buff.ReadInt() // read string index - x = ctx.Table.At(y) + v13 := buff.ReadInt() // read string index + v12 = ctx.Table.At(v13) } else { - x = buff.ReadString() // read string + v12 = buff.ReadString() // read string } - w := x - target.Name = w - - var bb string + target.Name = v12 + var v14 string if ctx.IsStringTable() { - cc := buff.ReadInt() // read string index - bb = ctx.Table.At(cc) + v15 := buff.ReadInt() // read string index + v14 = ctx.Table.At(v15) } else { - bb = buff.ReadString() // read string + v14 = buff.ReadString() // read string } - aa := bb - target.ProviderID = aa + target.ProviderID = v14 return nil } @@ -2698,120 +2439,103 @@ func (target *AssetSet) MarshalBinaryWithContext(ctx *EncodingContext) (err erro buff := ctx.Buffer buff.WriteUInt8(AssetsCodecVersion) // version - // execute pre-processing func preProcessAssetSet(target) + if target.aggregateBy == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.aggregateBy)) // slice length - for i := range target.aggregateBy { + for v0 := range target.aggregateBy { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.aggregateBy[i]) - buff.WriteInt(a) // write table index + v1 := ctx.Table.AddOrGet(target.aggregateBy[v0]) + buff.WriteInt(v1) // write table index } else { - buff.WriteString(target.aggregateBy[i]) // write string + buff.WriteString(target.aggregateBy[v0]) // write string } - } // --- [end][write][slice]([]string) --- - } if target.assets == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]Asset) --- buff.WriteInt(len(target.assets)) // map length - for v, z := range target.assets { + for v2, v3 := range target.assets { if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(v) - buff.WriteInt(b) // write table index + v4 := ctx.Table.AddOrGet(v2) + buff.WriteInt(v4) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v2) // write string } - if z == nil { + if v3 == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][interface](Asset) --- - c := reflect.ValueOf(z).Interface() - d, okA := c.(BinEncoder) - if !okA { - return fmt.Errorf("type: %s does not implement %s.BinEncoder", typeToString(z), GeneratorPackageName) + v5 := reflect.ValueOf(v3).Interface() + v6, v7 := v5.(BinEncoder) + if !v7 { + return fmt.Errorf("type: %s does not implement %s.BinEncoder", typeToString(v3), GeneratorPackageName) } - buff.WriteString(typeToString(z)) + buff.WriteString(typeToString(v3)) buff.WriteInt(0) // [compatibility, unused] - - errA := d.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v8 := v6.MarshalBinaryWithContext(ctx) + if v8 != nil { + return v8 } // --- [end][write][interface](Asset) --- - } } // --- [end][write][map](map[string]Asset) --- - } - if ctx.IsStringTable() { - e := ctx.Table.AddOrGet(target.FromSource) - buff.WriteInt(e) // write table index + v9 := ctx.Table.AddOrGet(target.FromSource) + buff.WriteInt(v9) // write table index } else { buff.WriteString(target.FromSource) // write string } - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errB := target.Window.MarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v10 := target.Window.MarshalBinaryWithContext(ctx) + if v10 != nil { + return v10 } // --- [end][write][struct](Window) --- - if target.Warnings == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Warnings)) // slice length - for j := range target.Warnings { + for v11 := range target.Warnings { if ctx.IsStringTable() { - f := ctx.Table.AddOrGet(target.Warnings[j]) - buff.WriteInt(f) // write table index + v12 := ctx.Table.AddOrGet(target.Warnings[v11]) + buff.WriteInt(v12) // write table index } else { - buff.WriteString(target.Warnings[j]) // write string + buff.WriteString(target.Warnings[v11]) // write string } - } // --- [end][write][slice]([]string) --- - } if target.Errors == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]string) --- buff.WriteInt(len(target.Errors)) // slice length - for ii := range target.Errors { + for v13 := range target.Errors { if ctx.IsStringTable() { - g := ctx.Table.AddOrGet(target.Errors[ii]) - buff.WriteInt(g) // write table index + v14 := ctx.Table.AddOrGet(target.Errors[v13]) + buff.WriteInt(v14) // write table index } else { - buff.WriteString(target.Errors[ii]) // write string + buff.WriteString(target.Errors[v13]) // write string } - } // --- [end][write][slice]([]string) --- - } return nil @@ -2868,150 +2592,127 @@ func (target *AssetSet) UnmarshalBinaryWithContext(ctx *DecodingContext) (err er return fmt.Errorf("Invalid Version Unmarshalling AssetSet. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 []string if buff.ReadUInt8() == uint8(0) { - target.aggregateBy = nil + v0 = nil } else { // --- [begin][read][slice]([]string) --- - b := buff.ReadInt() // slice len - a := make([]string, b) - for i := range b { - var c string - var e string + v1 := buff.ReadInt() // slice len + v0 = make([]string, v1) + for v2 := range v1 { + var v3 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v4 := buff.ReadInt() // read string index + v3 = ctx.Table.At(v4) } else { - e = buff.ReadString() // read string + v3 = buff.ReadString() // read string } - d := e - c = d - - a[i] = c + v0[v2] = v3 } - target.aggregateBy = a // --- [end][read][slice]([]string) --- - } - + target.aggregateBy = v0 + var v5 map[string]Asset if buff.ReadUInt8() == uint8(0) { - target.assets = nil + v5 = nil } else { // --- [begin][read][map](map[string]Asset) --- - h := buff.ReadInt() // map len - g := make(map[string]Asset, h) - for range h { - var v string - var m string + v6 := buff.ReadInt() // map len + v5 = make(map[string]Asset, v6) + for range v6 { + var v7 string if ctx.IsStringTable() { - n := buff.ReadInt() // read string index - m = ctx.Table.At(n) + v8 := buff.ReadInt() // read string index + v7 = ctx.Table.At(v8) } else { - m = buff.ReadString() // read string + v7 = buff.ReadString() // read string } - l := m - v = l - - var z Asset + var v9 Asset if buff.ReadUInt8() == uint8(0) { - z = nil + v9 = nil } else { // --- [begin][read][interface](Asset) --- - o := buff.ReadString() - _, p, _ := resolveType(o) - if _, ok := typeMap[p]; !ok { - return fmt.Errorf("Unknown Type: %s", p) + v10 := buff.ReadString() + _, v11, _ := resolveType(v10) + if _, ok := typeMap[v11]; !ok { + return fmt.Errorf("unknown type: %s", v11) } - - q, okA := reflect.New(typeMap[p]).Interface().(BinDecoder) - if !okA { - return fmt.Errorf("Type: %s does not implement %s.BinDecoder.", p, GeneratorPackageName) + v12, v13 := reflect.New(typeMap[v11]).Interface().(BinDecoder) + if !v13 { + return fmt.Errorf("type: %s does not implement %s.BinDecoder.", v11, GeneratorPackageName) } - buff.ReadInt() // [compatibility, unused] - errA := q.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v14 := v12.UnmarshalBinaryWithContext(ctx) + if v14 != nil { + return v14 } - z = q.(Asset) + v9 = v12.(Asset) // --- [end][read][interface](Asset) --- - } - g[v] = z + v5[v7] = v9 } - target.assets = g // --- [end][read][map](map[string]Asset) --- - } - - var s string + target.assets = v5 + var v15 string if ctx.IsStringTable() { - t := buff.ReadInt() // read string index - s = ctx.Table.At(t) + v16 := buff.ReadInt() // read string index + v15 = ctx.Table.At(v16) } else { - s = buff.ReadString() // read string + v15 = buff.ReadString() // read string } - r := s - target.FromSource = r - + target.FromSource = v15 + var v17 Window // --- [begin][read][struct](Window) --- - u := new(Window) + v18 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := u.UnmarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v19 := v18.UnmarshalBinaryWithContext(ctx) + if v19 != nil { + return v19 } - target.Window = *u + v17 = *v18 // --- [end][read][struct](Window) --- - + target.Window = v17 + var v20 []string if buff.ReadUInt8() == uint8(0) { - target.Warnings = nil + v20 = nil } else { // --- [begin][read][slice]([]string) --- - x := buff.ReadInt() // slice len - w := make([]string, x) - for j := range x { - var y string - var bb string + v21 := buff.ReadInt() // slice len + v20 = make([]string, v21) + for v22 := range v21 { + var v23 string if ctx.IsStringTable() { - cc := buff.ReadInt() // read string index - bb = ctx.Table.At(cc) + v24 := buff.ReadInt() // read string index + v23 = ctx.Table.At(v24) } else { - bb = buff.ReadString() // read string + v23 = buff.ReadString() // read string } - aa := bb - y = aa - - w[j] = y + v20[v22] = v23 } - target.Warnings = w // --- [end][read][slice]([]string) --- - } - + target.Warnings = v20 + var v25 []string if buff.ReadUInt8() == uint8(0) { - target.Errors = nil + v25 = nil } else { // --- [begin][read][slice]([]string) --- - ee := buff.ReadInt() // slice len - dd := make([]string, ee) - for ii := range ee { - var ff string - var hh string + v26 := buff.ReadInt() // slice len + v25 = make([]string, v26) + for v27 := range v26 { + var v28 string if ctx.IsStringTable() { - ll := buff.ReadInt() // read string index - hh = ctx.Table.At(ll) + v29 := buff.ReadInt() // read string index + v28 = ctx.Table.At(v29) } else { - hh = buff.ReadString() // read string + v28 = buff.ReadString() // read string } - gg := hh - ff = gg - - dd[ii] = ff + v25[v27] = v28 } - target.Errors = dd // --- [end][read][slice]([]string) --- - } + target.Errors = v25 // execute post-processing func postProcessAssetSet(target) @@ -3081,28 +2782,21 @@ func (stream *AssetSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstre } } else { // --- [begin][read][streaming-slice]([]string) --- - a := buff.ReadInt() // slice len - for i := range a { - - var b string - var d string + v0 := buff.ReadInt() // slice len + for v1 := range v0 { + var v2 string if ctx.IsStringTable() { - e := buff.ReadInt() // read string index - d = ctx.Table.At(e) + v3 := buff.ReadInt() // read string index + v2 = ctx.Table.At(v3) } else { - d = buff.ReadString() // read string + v2 = buff.ReadString() // read string } - c := d - b = c - - if !yield(fi, bstream.PairV(i, b)) { + if !yield(fi, bstream.PairV(v1, v2)) { return } } // --- [end][read][streaming-slice]([]string) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[map[string]Asset](), Name: "assets", @@ -3113,98 +2807,78 @@ func (stream *AssetSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstre } } else { // --- [begin][read][streaming-map](map[string]Asset) --- - f := buff.ReadInt() // map len - for range f { - var v string - var h string + v4 := buff.ReadInt() // map len + for range v4 { + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - v = g - - var z Asset + var v7 Asset if buff.ReadUInt8() == uint8(0) { - z = nil + v7 = nil } else { // --- [begin][read][interface](Asset) --- - m := buff.ReadString() - _, n, _ := resolveType(m) - if _, ok := typeMap[n]; !ok { - stream.err = fmt.Errorf("Unknown Type: %s", n) + v8 := buff.ReadString() + _, v9, _ := resolveType(v8) + if _, ok := typeMap[v9]; !ok { + stream.err = fmt.Errorf("unknown type: %s", v9) return - } - - o, okA := reflect.New(typeMap[n]).Interface().(BinDecoder) - if !okA { - stream.err = fmt.Errorf("Type: %s does not implement %s.BinDecoder.", n, GeneratorPackageName) + v10, v11 := reflect.New(typeMap[v9]).Interface().(BinDecoder) + if !v11 { + stream.err = fmt.Errorf("type: %s does not implement %s.BinDecoder.", v9, GeneratorPackageName) return - } - buff.ReadInt() // [compatibility, unused] - errA := o.UnmarshalBinaryWithContext(ctx) - if errA != nil { - stream.err = errA + v12 := v10.UnmarshalBinaryWithContext(ctx) + if v12 != nil { + stream.err = v12 return - } - z = o.(Asset) + v7 = v10.(Asset) // --- [end][read][interface](Asset) --- - } - - if !yield(fi, bstream.PairV(v, z)) { + if !yield(fi, bstream.PairV(v5, v7)) { return } } // --- [end][read][streaming-map](map[string]Asset) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[string](), Name: "FromSource", } - - var p string - var r string + var v13 string if ctx.IsStringTable() { - s := buff.ReadInt() // read string index - r = ctx.Table.At(s) + v14 := buff.ReadInt() // read string index + v13 = ctx.Table.At(v14) } else { - r = buff.ReadString() // read string + v13 = buff.ReadString() // read string } - q := r - p = q - if !yield(fi, bstream.SingleV(p)) { + if !yield(fi, bstream.SingleV(v13)) { return } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[Window](), Name: "Window", } - + var v15 Window // --- [begin][read][struct](Window) --- - u := new(Window) + v16 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := u.UnmarshalBinaryWithContext(ctx) - if errB != nil { - stream.err = errB + v17 := v16.UnmarshalBinaryWithContext(ctx) + if v17 != nil { + stream.err = v17 return - } - t := *u + v15 = *v16 // --- [end][read][struct](Window) --- - if !yield(fi, bstream.SingleV(t)) { + if !yield(fi, bstream.SingleV(v15)) { return } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[[]string](), Name: "Warnings", @@ -3215,28 +2889,21 @@ func (stream *AssetSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstre } } else { // --- [begin][read][streaming-slice]([]string) --- - w := buff.ReadInt() // slice len - for j := range w { - - var x string - var aa string + v18 := buff.ReadInt() // slice len + for v19 := range v18 { + var v20 string if ctx.IsStringTable() { - bb := buff.ReadInt() // read string index - aa = ctx.Table.At(bb) + v21 := buff.ReadInt() // read string index + v20 = ctx.Table.At(v21) } else { - aa = buff.ReadString() // read string + v20 = buff.ReadString() // read string } - y := aa - x = y - - if !yield(fi, bstream.PairV(j, x)) { + if !yield(fi, bstream.PairV(v19, v20)) { return } } // --- [end][read][streaming-slice]([]string) --- - } - fi = bstream.BingenFieldInfo{ Type: reflect.TypeFor[[]string](), Name: "Errors", @@ -3247,28 +2914,21 @@ func (stream *AssetSetStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstre } } else { // --- [begin][read][streaming-slice]([]string) --- - cc := buff.ReadInt() // slice len - for ii := range cc { - - var dd string - var ff string + v22 := buff.ReadInt() // slice len + for v23 := range v22 { + var v24 string if ctx.IsStringTable() { - gg := buff.ReadInt() // read string index - ff = ctx.Table.At(gg) + v25 := buff.ReadInt() // read string index + v24 = ctx.Table.At(v25) } else { - ff = buff.ReadString() // read string + v24 = buff.ReadString() // read string } - ee := ff - dd = ee - - if !yield(fi, bstream.PairV(ii, dd)) { + if !yield(fi, bstream.PairV(v23, v24)) { return } } // --- [end][read][streaming-slice]([]string) --- - } - } } @@ -3323,32 +2983,27 @@ func (target *AssetSetRange) MarshalBinaryWithContext(ctx *EncodingContext) (err buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][slice]([]*AssetSet) --- buff.WriteInt(len(target.assets)) // slice length - for i := range target.assets { - if target.assets[i] == nil { + for v0 := range target.assets { + if target.assets[v0] == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetSet) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.assets[i].MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v1 := target.assets[v0].MarshalBinaryWithContext(ctx) + if v1 != nil { + return v1 } // --- [end][write][struct](AssetSet) --- - } } // --- [end][write][slice]([]*AssetSet) --- - } - if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.FromStore) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(target.FromStore) + buff.WriteInt(v2) // write table index } else { buff.WriteString(target.FromStore) // write string } @@ -3407,45 +3062,41 @@ func (target *AssetSetRange) UnmarshalBinaryWithContext(ctx *DecodingContext) (e return fmt.Errorf("Invalid Version Unmarshalling AssetSetRange. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 []*AssetSet if buff.ReadUInt8() == uint8(0) { - target.assets = nil + v0 = nil } else { // --- [begin][read][slice]([]*AssetSet) --- - b := buff.ReadInt() // slice len - a := make([]*AssetSet, b) - for i := range b { - var c *AssetSet + v1 := buff.ReadInt() // slice len + v0 = make([]*AssetSet, v1) + for v2 := range v1 { + var v3 *AssetSet if buff.ReadUInt8() == uint8(0) { - c = nil + v3 = nil } else { // --- [begin][read][struct](AssetSet) --- - d := new(AssetSet) + v4 := new(AssetSet) buff.ReadInt() // [compatibility, unused] - errA := d.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v5 := v4.UnmarshalBinaryWithContext(ctx) + if v5 != nil { + return v5 } - c = d + v3 = v4 // --- [end][read][struct](AssetSet) --- - } - - a[i] = c + v0[v2] = v3 } - target.assets = a // --- [end][read][slice]([]*AssetSet) --- - } - - var f string + target.assets = v0 + var v6 string if ctx.IsStringTable() { - g := buff.ReadInt() // read string index - f = ctx.Table.At(g) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - f = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - e := f - target.FromStore = e + target.FromStore = v6 return nil } @@ -3497,13 +3148,10 @@ func (target *Breakdown) MarshalBinaryWithContext(ctx *EncodingContext) (err err buff := ctx.Buffer buff.WriteUInt8(AssetsCodecVersion) // version - buff.WriteFloat64(target.Idle) // write float64 - - buff.WriteFloat64(target.Other) // write float64 - - buff.WriteFloat64(target.System) // write float64 - - buff.WriteFloat64(target.User) // write float64 + buff.WriteFloat64(target.Idle) + buff.WriteFloat64(target.Other) + buff.WriteFloat64(target.System) + buff.WriteFloat64(target.User) return nil } @@ -3559,17 +3207,18 @@ func (target *Breakdown) UnmarshalBinaryWithContext(ctx *DecodingContext) (err e return fmt.Errorf("Invalid Version Unmarshalling Breakdown. Expected %d or less, got %d", AssetsCodecVersion, version) } - a := buff.ReadFloat64() // read float64 - target.Idle = a - - b := buff.ReadFloat64() // read float64 - target.Other = b - - c := buff.ReadFloat64() // read float64 - target.System = c - - d := buff.ReadFloat64() // read float64 - target.User = d + var v0 float64 + v0 = buff.ReadFloat64() + target.Idle = v0 + var v1 float64 + v1 = buff.ReadFloat64() + target.Other = v1 + var v2 float64 + v2 = buff.ReadFloat64() + target.System = v2 + var v3 float64 + v3 = buff.ReadFloat64() + target.User = v3 return nil } @@ -3626,75 +3275,63 @@ func (target *Cloud) MarshalBinaryWithContext(ctx *EncodingContext) (err error) buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v0, v1 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(v0) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v0) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v1) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- if target.properties == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v4 := target.properties.MarshalBinaryWithContext(ctx) + if v4 != nil { + return v4 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][reference](time.Time) --- - c, errB := target.start.MarshalBinary() - if errB != nil { - return errB + v5, v6 := target.start.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - d, errC := target.end.MarshalBinary() - if errC != nil { - return errC + v7, v8 := target.end.MarshalBinary() + if v8 != nil { + return v8 } - buff.WriteInt(len(d)) - buff.WriteBytes(d) + buff.WriteInt(len(v7)) + buff.WriteBytes(v7) // --- [end][write][reference](time.Time) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errD := target.window.MarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v9 := target.window.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.adjustment) // write float64 - - buff.WriteFloat64(target.Cost) // write float64 - - buff.WriteFloat64(target.Credit) // write float64 + buff.WriteFloat64(target.adjustment) + buff.WriteFloat64(target.Cost) + buff.WriteFloat64(target.Credit) return nil } @@ -3750,103 +3387,96 @@ func (target *Cloud) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error return fmt.Errorf("Invalid Version Unmarshalling Cloud. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var a map[string]string + var v1 map[string]string if buff.ReadUInt8() == uint8(0) { - a = nil + v1 = nil } else { // --- [begin][read][map](map[string]string) --- - c := buff.ReadInt() // map len - b := make(map[string]string, c) - for range c { - var v string - var e string + v2 := buff.ReadInt() // map len + v1 = make(map[string]string, v2) + for range v2 { + var v3 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v4 := buff.ReadInt() // read string index + v3 = ctx.Table.At(v4) } else { - e = buff.ReadString() // read string + v3 = buff.ReadString() // read string } - d := e - v = d - - var z string - var h string + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - z = g - - b[v] = z + v1[v3] = v5 } - a = b // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(a) + v0 = AssetLabels(v1) // --- [end][read][alias](AssetLabels) --- - + target.labels = v0 + var v7 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v7 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - m := new(AssetProperties) + v8 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := m.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v9 := v8.UnmarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } - target.properties = m + v7 = v8 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v7 + var v10 time.Time // --- [begin][read][reference](time.Time) --- - n := new(time.Time) - o := buff.ReadInt() // byte array length - p := buff.ReadBytes(o) - errB := n.UnmarshalBinary(p) - if errB != nil { - return errB - } - target.start = *n + v11 := new(time.Time) + v12 := buff.ReadInt() // byte array length + v13 := buff.ReadBytes(v12) + v14 := v11.UnmarshalBinary(v13) + if v14 != nil { + return v14 + } + v10 = *v11 // --- [end][read][reference](time.Time) --- - + target.start = v10 + var v15 time.Time // --- [begin][read][reference](time.Time) --- - q := new(time.Time) - r := buff.ReadInt() // byte array length - s := buff.ReadBytes(r) - errC := q.UnmarshalBinary(s) - if errC != nil { - return errC - } - target.end = *q + v16 := new(time.Time) + v17 := buff.ReadInt() // byte array length + v18 := buff.ReadBytes(v17) + v19 := v16.UnmarshalBinary(v18) + if v19 != nil { + return v19 + } + v15 = *v16 // --- [end][read][reference](time.Time) --- - + target.end = v15 + var v20 Window // --- [begin][read][struct](Window) --- - t := new(Window) + v21 := new(Window) buff.ReadInt() // [compatibility, unused] - errD := t.UnmarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v22 := v21.UnmarshalBinaryWithContext(ctx) + if v22 != nil { + return v22 } - target.window = *t + v20 = *v21 // --- [end][read][struct](Window) --- - - u := buff.ReadFloat64() // read float64 - target.adjustment = u - - w := buff.ReadFloat64() // read float64 - target.Cost = w - - x := buff.ReadFloat64() // read float64 - target.Credit = x + target.window = v20 + var v23 float64 + v23 = buff.ReadFloat64() + target.adjustment = v23 + var v24 float64 + v24 = buff.ReadFloat64() + target.Cost = v24 + var v25 float64 + v25 = buff.ReadFloat64() + target.Credit = v25 return nil } @@ -3903,53 +3533,45 @@ func (target *ClusterManagement) MarshalBinaryWithContext(ctx *EncodingContext) buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v0, v1 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(v0) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v0) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v1) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- if target.properties == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v4 := target.properties.MarshalBinaryWithContext(ctx) + if v4 != nil { + return v4 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errB := target.window.MarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v5 := target.window.MarshalBinaryWithContext(ctx) + if v5 != nil { + return v5 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.Cost) // write float64 + buff.WriteFloat64(target.Cost) return nil } @@ -4005,75 +3627,66 @@ func (target *ClusterManagement) UnmarshalBinaryWithContext(ctx *DecodingContext return fmt.Errorf("Invalid Version Unmarshalling ClusterManagement. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var a map[string]string + var v1 map[string]string if buff.ReadUInt8() == uint8(0) { - a = nil + v1 = nil } else { // --- [begin][read][map](map[string]string) --- - c := buff.ReadInt() // map len - b := make(map[string]string, c) - for range c { - var v string - var e string + v2 := buff.ReadInt() // map len + v1 = make(map[string]string, v2) + for range v2 { + var v3 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v4 := buff.ReadInt() // read string index + v3 = ctx.Table.At(v4) } else { - e = buff.ReadString() // read string + v3 = buff.ReadString() // read string } - d := e - v = d - - var z string - var h string + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - z = g - - b[v] = z + v1[v3] = v5 } - a = b // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(a) + v0 = AssetLabels(v1) // --- [end][read][alias](AssetLabels) --- - + target.labels = v0 + var v7 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v7 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - m := new(AssetProperties) + v8 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := m.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v9 := v8.UnmarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } - target.properties = m + v7 = v8 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v7 + var v10 Window // --- [begin][read][struct](Window) --- - n := new(Window) + v11 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := n.UnmarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v12 := v11.UnmarshalBinaryWithContext(ctx) + if v12 != nil { + return v12 } - target.window = *n + v10 = *v11 // --- [end][read][struct](Window) --- - - o := buff.ReadFloat64() // read float64 - target.Cost = o + target.window = v10 + var v13 float64 + v13 = buff.ReadFloat64() + target.Cost = v13 return nil } @@ -4130,91 +3743,75 @@ func (target *Disk) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v0, v1 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v2 := ctx.Table.AddOrGet(v0) + buff.WriteInt(v2) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v0) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v1) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- if target.properties == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v4 := target.properties.MarshalBinaryWithContext(ctx) + if v4 != nil { + return v4 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][reference](time.Time) --- - c, errB := target.start.MarshalBinary() - if errB != nil { - return errB + v5, v6 := target.start.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - d, errC := target.end.MarshalBinary() - if errC != nil { - return errC + v7, v8 := target.end.MarshalBinary() + if v8 != nil { + return v8 } - buff.WriteInt(len(d)) - buff.WriteBytes(d) + buff.WriteInt(len(v7)) + buff.WriteBytes(v7) // --- [end][write][reference](time.Time) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errD := target.window.MarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v9 := target.window.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.adjustment) // write float64 - - buff.WriteFloat64(target.Cost) // write float64 - - buff.WriteFloat64(target.ByteHours) // write float64 - - buff.WriteFloat64(target.Local) // write float64 - + buff.WriteFloat64(target.adjustment) + buff.WriteFloat64(target.Cost) + buff.WriteFloat64(target.ByteHours) + buff.WriteFloat64(target.Local) if target.Breakdown == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](Breakdown) --- buff.WriteInt(0) // [compatibility, unused] - errE := target.Breakdown.MarshalBinaryWithContext(ctx) - if errE != nil { - return errE + v10 := target.Breakdown.MarshalBinaryWithContext(ctx) + if v10 != nil { + return v10 } // --- [end][write][struct](Breakdown) --- - } return nil @@ -4271,122 +3868,114 @@ func (target *Disk) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) return fmt.Errorf("Invalid Version Unmarshalling Disk. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var a map[string]string + var v1 map[string]string if buff.ReadUInt8() == uint8(0) { - a = nil + v1 = nil } else { // --- [begin][read][map](map[string]string) --- - c := buff.ReadInt() // map len - b := make(map[string]string, c) - for range c { - var v string - var e string + v2 := buff.ReadInt() // map len + v1 = make(map[string]string, v2) + for range v2 { + var v3 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v4 := buff.ReadInt() // read string index + v3 = ctx.Table.At(v4) } else { - e = buff.ReadString() // read string + v3 = buff.ReadString() // read string } - d := e - v = d - - var z string - var h string + var v5 string if ctx.IsStringTable() { - l := buff.ReadInt() // read string index - h = ctx.Table.At(l) + v6 := buff.ReadInt() // read string index + v5 = ctx.Table.At(v6) } else { - h = buff.ReadString() // read string + v5 = buff.ReadString() // read string } - g := h - z = g - - b[v] = z + v1[v3] = v5 } - a = b // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(a) + v0 = AssetLabels(v1) // --- [end][read][alias](AssetLabels) --- - + target.labels = v0 + var v7 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v7 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - m := new(AssetProperties) + v8 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := m.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v9 := v8.UnmarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } - target.properties = m + v7 = v8 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v7 + var v10 time.Time // --- [begin][read][reference](time.Time) --- - n := new(time.Time) - o := buff.ReadInt() // byte array length - p := buff.ReadBytes(o) - errB := n.UnmarshalBinary(p) - if errB != nil { - return errB - } - target.start = *n + v11 := new(time.Time) + v12 := buff.ReadInt() // byte array length + v13 := buff.ReadBytes(v12) + v14 := v11.UnmarshalBinary(v13) + if v14 != nil { + return v14 + } + v10 = *v11 // --- [end][read][reference](time.Time) --- - + target.start = v10 + var v15 time.Time // --- [begin][read][reference](time.Time) --- - q := new(time.Time) - r := buff.ReadInt() // byte array length - s := buff.ReadBytes(r) - errC := q.UnmarshalBinary(s) - if errC != nil { - return errC - } - target.end = *q + v16 := new(time.Time) + v17 := buff.ReadInt() // byte array length + v18 := buff.ReadBytes(v17) + v19 := v16.UnmarshalBinary(v18) + if v19 != nil { + return v19 + } + v15 = *v16 // --- [end][read][reference](time.Time) --- - + target.end = v15 + var v20 Window // --- [begin][read][struct](Window) --- - t := new(Window) + v21 := new(Window) buff.ReadInt() // [compatibility, unused] - errD := t.UnmarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v22 := v21.UnmarshalBinaryWithContext(ctx) + if v22 != nil { + return v22 } - target.window = *t + v20 = *v21 // --- [end][read][struct](Window) --- - - u := buff.ReadFloat64() // read float64 - target.adjustment = u - - w := buff.ReadFloat64() // read float64 - target.Cost = w - - x := buff.ReadFloat64() // read float64 - target.ByteHours = x - - y := buff.ReadFloat64() // read float64 - target.Local = y - + target.window = v20 + var v23 float64 + v23 = buff.ReadFloat64() + target.adjustment = v23 + var v24 float64 + v24 = buff.ReadFloat64() + target.Cost = v24 + var v25 float64 + v25 = buff.ReadFloat64() + target.ByteHours = v25 + var v26 float64 + v26 = buff.ReadFloat64() + target.Local = v26 + var v27 *Breakdown if buff.ReadUInt8() == uint8(0) { - target.Breakdown = nil + v27 = nil } else { - // --- [begin][read][struct](Breakdown) --- - aa := new(Breakdown) + v28 := new(Breakdown) buff.ReadInt() // [compatibility, unused] - errE := aa.UnmarshalBinaryWithContext(ctx) - if errE != nil { - return errE + v29 := v28.UnmarshalBinaryWithContext(ctx) + if v29 != nil { + return v29 } - target.Breakdown = aa + v27 = v28 // --- [end][read][struct](Breakdown) --- - } + target.Breakdown = v27 return nil } @@ -4442,75 +4031,63 @@ func (target *LoadBalancer) MarshalBinaryWithContext(ctx *EncodingContext) (err buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v0 := target.properties.MarshalBinaryWithContext(ctx) + if v0 != nil { + return v0 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][alias](AssetLabels) --- if map[string]string(target.labels) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v1, v2 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v1) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v4 := ctx.Table.AddOrGet(v2) + buff.WriteInt(v4) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v2) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- - // --- [begin][write][reference](time.Time) --- - c, errB := target.start.MarshalBinary() - if errB != nil { - return errB + v5, v6 := target.start.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - d, errC := target.end.MarshalBinary() - if errC != nil { - return errC + v7, v8 := target.end.MarshalBinary() + if v8 != nil { + return v8 } - buff.WriteInt(len(d)) - buff.WriteBytes(d) + buff.WriteInt(len(v7)) + buff.WriteBytes(v7) // --- [end][write][reference](time.Time) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errD := target.window.MarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v9 := target.window.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.adjustment) // write float64 - - buff.WriteFloat64(target.Cost) // write float64 + buff.WriteFloat64(target.adjustment) + buff.WriteFloat64(target.Cost) return nil } @@ -4566,100 +4143,93 @@ func (target *LoadBalancer) UnmarshalBinaryWithContext(ctx *DecodingContext) (er return fmt.Errorf("Invalid Version Unmarshalling LoadBalancer. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v0 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - a := new(AssetProperties) + v1 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := a.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v2 := v1.UnmarshalBinaryWithContext(ctx) + if v2 != nil { + return v2 } - target.properties = a + v0 = v1 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v0 + var v3 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var b map[string]string + var v4 map[string]string if buff.ReadUInt8() == uint8(0) { - b = nil + v4 = nil } else { // --- [begin][read][map](map[string]string) --- - d := buff.ReadInt() // map len - c := make(map[string]string, d) - for range d { - var v string - var f string + v5 := buff.ReadInt() // map len + v4 = make(map[string]string, v5) + for range v5 { + var v6 string if ctx.IsStringTable() { - g := buff.ReadInt() // read string index - f = ctx.Table.At(g) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - f = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - e := f - v = e - - var z string - var l string + var v8 string if ctx.IsStringTable() { - m := buff.ReadInt() // read string index - l = ctx.Table.At(m) + v9 := buff.ReadInt() // read string index + v8 = ctx.Table.At(v9) } else { - l = buff.ReadString() // read string + v8 = buff.ReadString() // read string } - h := l - z = h - - c[v] = z + v4[v6] = v8 } - b = c // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(b) + v3 = AssetLabels(v4) // --- [end][read][alias](AssetLabels) --- - + target.labels = v3 + var v10 time.Time // --- [begin][read][reference](time.Time) --- - n := new(time.Time) - o := buff.ReadInt() // byte array length - p := buff.ReadBytes(o) - errB := n.UnmarshalBinary(p) - if errB != nil { - return errB - } - target.start = *n + v11 := new(time.Time) + v12 := buff.ReadInt() // byte array length + v13 := buff.ReadBytes(v12) + v14 := v11.UnmarshalBinary(v13) + if v14 != nil { + return v14 + } + v10 = *v11 // --- [end][read][reference](time.Time) --- - + target.start = v10 + var v15 time.Time // --- [begin][read][reference](time.Time) --- - q := new(time.Time) - r := buff.ReadInt() // byte array length - s := buff.ReadBytes(r) - errC := q.UnmarshalBinary(s) - if errC != nil { - return errC - } - target.end = *q + v16 := new(time.Time) + v17 := buff.ReadInt() // byte array length + v18 := buff.ReadBytes(v17) + v19 := v16.UnmarshalBinary(v18) + if v19 != nil { + return v19 + } + v15 = *v16 // --- [end][read][reference](time.Time) --- - + target.end = v15 + var v20 Window // --- [begin][read][struct](Window) --- - t := new(Window) + v21 := new(Window) buff.ReadInt() // [compatibility, unused] - errD := t.UnmarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v22 := v21.UnmarshalBinaryWithContext(ctx) + if v22 != nil { + return v22 } - target.window = *t + v20 = *v21 // --- [end][read][struct](Window) --- - - u := buff.ReadFloat64() // read float64 - target.adjustment = u - - w := buff.ReadFloat64() // read float64 - target.Cost = w + target.window = v20 + var v23 float64 + v23 = buff.ReadFloat64() + target.adjustment = v23 + var v24 float64 + v24 = buff.ReadFloat64() + target.Cost = v24 return nil } @@ -4715,75 +4285,63 @@ func (target *Network) MarshalBinaryWithContext(ctx *EncodingContext) (err error buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v0 := target.properties.MarshalBinaryWithContext(ctx) + if v0 != nil { + return v0 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][alias](AssetLabels) --- if map[string]string(target.labels) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v1, v2 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v1) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v4 := ctx.Table.AddOrGet(v2) + buff.WriteInt(v4) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v2) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- - // --- [begin][write][reference](time.Time) --- - c, errB := target.start.MarshalBinary() - if errB != nil { - return errB + v5, v6 := target.start.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - d, errC := target.end.MarshalBinary() - if errC != nil { - return errC + v7, v8 := target.end.MarshalBinary() + if v8 != nil { + return v8 } - buff.WriteInt(len(d)) - buff.WriteBytes(d) + buff.WriteInt(len(v7)) + buff.WriteBytes(v7) // --- [end][write][reference](time.Time) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errD := target.window.MarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v9 := target.window.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.adjustment) // write float64 - - buff.WriteFloat64(target.Cost) // write float64 + buff.WriteFloat64(target.adjustment) + buff.WriteFloat64(target.Cost) return nil } @@ -4839,100 +4397,93 @@ func (target *Network) UnmarshalBinaryWithContext(ctx *DecodingContext) (err err return fmt.Errorf("Invalid Version Unmarshalling Network. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v0 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - a := new(AssetProperties) + v1 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := a.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v2 := v1.UnmarshalBinaryWithContext(ctx) + if v2 != nil { + return v2 } - target.properties = a + v0 = v1 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v0 + var v3 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var b map[string]string + var v4 map[string]string if buff.ReadUInt8() == uint8(0) { - b = nil + v4 = nil } else { // --- [begin][read][map](map[string]string) --- - d := buff.ReadInt() // map len - c := make(map[string]string, d) - for range d { - var v string - var f string + v5 := buff.ReadInt() // map len + v4 = make(map[string]string, v5) + for range v5 { + var v6 string if ctx.IsStringTable() { - g := buff.ReadInt() // read string index - f = ctx.Table.At(g) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - f = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - e := f - v = e - - var z string - var l string + var v8 string if ctx.IsStringTable() { - m := buff.ReadInt() // read string index - l = ctx.Table.At(m) + v9 := buff.ReadInt() // read string index + v8 = ctx.Table.At(v9) } else { - l = buff.ReadString() // read string + v8 = buff.ReadString() // read string } - h := l - z = h - - c[v] = z + v4[v6] = v8 } - b = c // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(b) + v3 = AssetLabels(v4) // --- [end][read][alias](AssetLabels) --- - + target.labels = v3 + var v10 time.Time // --- [begin][read][reference](time.Time) --- - n := new(time.Time) - o := buff.ReadInt() // byte array length - p := buff.ReadBytes(o) - errB := n.UnmarshalBinary(p) - if errB != nil { - return errB - } - target.start = *n + v11 := new(time.Time) + v12 := buff.ReadInt() // byte array length + v13 := buff.ReadBytes(v12) + v14 := v11.UnmarshalBinary(v13) + if v14 != nil { + return v14 + } + v10 = *v11 // --- [end][read][reference](time.Time) --- - + target.start = v10 + var v15 time.Time // --- [begin][read][reference](time.Time) --- - q := new(time.Time) - r := buff.ReadInt() // byte array length - s := buff.ReadBytes(r) - errC := q.UnmarshalBinary(s) - if errC != nil { - return errC - } - target.end = *q + v16 := new(time.Time) + v17 := buff.ReadInt() // byte array length + v18 := buff.ReadBytes(v17) + v19 := v16.UnmarshalBinary(v18) + if v19 != nil { + return v19 + } + v15 = *v16 // --- [end][read][reference](time.Time) --- - + target.end = v15 + var v20 Window // --- [begin][read][struct](Window) --- - t := new(Window) + v21 := new(Window) buff.ReadInt() // [compatibility, unused] - errD := t.UnmarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v22 := v21.UnmarshalBinaryWithContext(ctx) + if v22 != nil { + return v22 } - target.window = *t + v20 = *v21 // --- [end][read][struct](Window) --- - - u := buff.ReadFloat64() // read float64 - target.adjustment = u - - w := buff.ReadFloat64() // read float64 - target.Cost = w + target.window = v20 + var v23 float64 + v23 = buff.ReadFloat64() + target.adjustment = v23 + var v24 float64 + v24 = buff.ReadFloat64() + target.Cost = v24 return nil } @@ -4988,127 +4539,101 @@ func (target *Node) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v0 := target.properties.MarshalBinaryWithContext(ctx) + if v0 != nil { + return v0 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][alias](AssetLabels) --- if map[string]string(target.labels) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v1, v2 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v1) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v4 := ctx.Table.AddOrGet(v2) + buff.WriteInt(v4) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v2) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- - // --- [begin][write][reference](time.Time) --- - c, errB := target.start.MarshalBinary() - if errB != nil { - return errB + v5, v6 := target.start.MarshalBinary() + if v6 != nil { + return v6 } - buff.WriteInt(len(c)) - buff.WriteBytes(c) + buff.WriteInt(len(v5)) + buff.WriteBytes(v5) // --- [end][write][reference](time.Time) --- - // --- [begin][write][reference](time.Time) --- - d, errC := target.end.MarshalBinary() - if errC != nil { - return errC + v7, v8 := target.end.MarshalBinary() + if v8 != nil { + return v8 } - buff.WriteInt(len(d)) - buff.WriteBytes(d) + buff.WriteInt(len(v7)) + buff.WriteBytes(v7) // --- [end][write][reference](time.Time) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errD := target.window.MarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v9 := target.window.MarshalBinaryWithContext(ctx) + if v9 != nil { + return v9 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.adjustment) // write float64 - + buff.WriteFloat64(target.adjustment) if ctx.IsStringTable() { - e := ctx.Table.AddOrGet(target.NodeType) - buff.WriteInt(e) // write table index + v10 := ctx.Table.AddOrGet(target.NodeType) + buff.WriteInt(v10) // write table index } else { buff.WriteString(target.NodeType) // write string } - - buff.WriteFloat64(target.CPUCoreHours) // write float64 - - buff.WriteFloat64(target.RAMByteHours) // write float64 - - buff.WriteFloat64(target.GPUHours) // write float64 - + buff.WriteFloat64(target.CPUCoreHours) + buff.WriteFloat64(target.RAMByteHours) + buff.WriteFloat64(target.GPUHours) if target.CPUBreakdown == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](Breakdown) --- buff.WriteInt(0) // [compatibility, unused] - errE := target.CPUBreakdown.MarshalBinaryWithContext(ctx) - if errE != nil { - return errE + v11 := target.CPUBreakdown.MarshalBinaryWithContext(ctx) + if v11 != nil { + return v11 } // --- [end][write][struct](Breakdown) --- - } if target.RAMBreakdown == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](Breakdown) --- buff.WriteInt(0) // [compatibility, unused] - errF := target.RAMBreakdown.MarshalBinaryWithContext(ctx) - if errF != nil { - return errF + v12 := target.RAMBreakdown.MarshalBinaryWithContext(ctx) + if v12 != nil { + return v12 } // --- [end][write][struct](Breakdown) --- - } - - buff.WriteFloat64(target.CPUCost) // write float64 - - buff.WriteFloat64(target.GPUCost) // write float64 - - buff.WriteFloat64(target.GPUCount) // write float64 - - buff.WriteFloat64(target.RAMCost) // write float64 - - buff.WriteFloat64(target.Discount) // write float64 - - buff.WriteFloat64(target.Preemptible) // write float64 + buff.WriteFloat64(target.CPUCost) + buff.WriteFloat64(target.GPUCost) + buff.WriteFloat64(target.GPUCount) + buff.WriteFloat64(target.RAMCost) + buff.WriteFloat64(target.Discount) + buff.WriteFloat64(target.Preemptible) return nil } @@ -5164,164 +4689,155 @@ func (target *Node) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) return fmt.Errorf("Invalid Version Unmarshalling Node. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v0 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - a := new(AssetProperties) + v1 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := a.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v2 := v1.UnmarshalBinaryWithContext(ctx) + if v2 != nil { + return v2 } - target.properties = a + v0 = v1 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v0 + var v3 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var b map[string]string + var v4 map[string]string if buff.ReadUInt8() == uint8(0) { - b = nil + v4 = nil } else { // --- [begin][read][map](map[string]string) --- - d := buff.ReadInt() // map len - c := make(map[string]string, d) - for range d { - var v string - var f string + v5 := buff.ReadInt() // map len + v4 = make(map[string]string, v5) + for range v5 { + var v6 string if ctx.IsStringTable() { - g := buff.ReadInt() // read string index - f = ctx.Table.At(g) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - f = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - e := f - v = e - - var z string - var l string + var v8 string if ctx.IsStringTable() { - m := buff.ReadInt() // read string index - l = ctx.Table.At(m) + v9 := buff.ReadInt() // read string index + v8 = ctx.Table.At(v9) } else { - l = buff.ReadString() // read string + v8 = buff.ReadString() // read string } - h := l - z = h - - c[v] = z + v4[v6] = v8 } - b = c // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(b) + v3 = AssetLabels(v4) // --- [end][read][alias](AssetLabels) --- - + target.labels = v3 + var v10 time.Time // --- [begin][read][reference](time.Time) --- - n := new(time.Time) - o := buff.ReadInt() // byte array length - p := buff.ReadBytes(o) - errB := n.UnmarshalBinary(p) - if errB != nil { - return errB - } - target.start = *n + v11 := new(time.Time) + v12 := buff.ReadInt() // byte array length + v13 := buff.ReadBytes(v12) + v14 := v11.UnmarshalBinary(v13) + if v14 != nil { + return v14 + } + v10 = *v11 // --- [end][read][reference](time.Time) --- - + target.start = v10 + var v15 time.Time // --- [begin][read][reference](time.Time) --- - q := new(time.Time) - r := buff.ReadInt() // byte array length - s := buff.ReadBytes(r) - errC := q.UnmarshalBinary(s) - if errC != nil { - return errC - } - target.end = *q + v16 := new(time.Time) + v17 := buff.ReadInt() // byte array length + v18 := buff.ReadBytes(v17) + v19 := v16.UnmarshalBinary(v18) + if v19 != nil { + return v19 + } + v15 = *v16 // --- [end][read][reference](time.Time) --- - + target.end = v15 + var v20 Window // --- [begin][read][struct](Window) --- - t := new(Window) + v21 := new(Window) buff.ReadInt() // [compatibility, unused] - errD := t.UnmarshalBinaryWithContext(ctx) - if errD != nil { - return errD + v22 := v21.UnmarshalBinaryWithContext(ctx) + if v22 != nil { + return v22 } - target.window = *t + v20 = *v21 // --- [end][read][struct](Window) --- - - u := buff.ReadFloat64() // read float64 - target.adjustment = u - - var x string + target.window = v20 + var v23 float64 + v23 = buff.ReadFloat64() + target.adjustment = v23 + var v24 string if ctx.IsStringTable() { - y := buff.ReadInt() // read string index - x = ctx.Table.At(y) + v25 := buff.ReadInt() // read string index + v24 = ctx.Table.At(v25) } else { - x = buff.ReadString() // read string - } - w := x - target.NodeType = w - - aa := buff.ReadFloat64() // read float64 - target.CPUCoreHours = aa - - bb := buff.ReadFloat64() // read float64 - target.RAMByteHours = bb - - cc := buff.ReadFloat64() // read float64 - target.GPUHours = cc - + v24 = buff.ReadString() // read string + } + target.NodeType = v24 + var v26 float64 + v26 = buff.ReadFloat64() + target.CPUCoreHours = v26 + var v27 float64 + v27 = buff.ReadFloat64() + target.RAMByteHours = v27 + var v28 float64 + v28 = buff.ReadFloat64() + target.GPUHours = v28 + var v29 *Breakdown if buff.ReadUInt8() == uint8(0) { - target.CPUBreakdown = nil + v29 = nil } else { // --- [begin][read][struct](Breakdown) --- - dd := new(Breakdown) + v30 := new(Breakdown) buff.ReadInt() // [compatibility, unused] - errE := dd.UnmarshalBinaryWithContext(ctx) - if errE != nil { - return errE + v31 := v30.UnmarshalBinaryWithContext(ctx) + if v31 != nil { + return v31 } - target.CPUBreakdown = dd + v29 = v30 // --- [end][read][struct](Breakdown) --- - } - + target.CPUBreakdown = v29 + var v32 *Breakdown if buff.ReadUInt8() == uint8(0) { - target.RAMBreakdown = nil + v32 = nil } else { // --- [begin][read][struct](Breakdown) --- - ee := new(Breakdown) + v33 := new(Breakdown) buff.ReadInt() // [compatibility, unused] - errF := ee.UnmarshalBinaryWithContext(ctx) - if errF != nil { - return errF + v34 := v33.UnmarshalBinaryWithContext(ctx) + if v34 != nil { + return v34 } - target.RAMBreakdown = ee + v32 = v33 // --- [end][read][struct](Breakdown) --- - } - - ff := buff.ReadFloat64() // read float64 - target.CPUCost = ff - - gg := buff.ReadFloat64() // read float64 - target.GPUCost = gg - - hh := buff.ReadFloat64() // read float64 - target.GPUCount = hh - - ll := buff.ReadFloat64() // read float64 - target.RAMCost = ll - - mm := buff.ReadFloat64() // read float64 - target.Discount = mm - - nn := buff.ReadFloat64() // read float64 - target.Preemptible = nn + target.RAMBreakdown = v32 + var v35 float64 + v35 = buff.ReadFloat64() + target.CPUCost = v35 + var v36 float64 + v36 = buff.ReadFloat64() + target.GPUCost = v36 + var v37 float64 + v37 = buff.ReadFloat64() + target.GPUCount = v37 + var v38 float64 + v38 = buff.ReadFloat64() + target.RAMCost = v38 + var v39 float64 + v39 = buff.ReadFloat64() + target.Discount = v39 + var v40 float64 + v40 = buff.ReadFloat64() + target.Preemptible = v40 return nil } @@ -5373,9 +4889,8 @@ func (target *PVAllocation) MarshalBinaryWithContext(ctx *EncodingContext) (err buff := ctx.Buffer buff.WriteUInt8(AllocationCodecVersion) // version - buff.WriteFloat64(target.ByteHours) // write float64 - - buff.WriteFloat64(target.Cost) // write float64 + buff.WriteFloat64(target.ByteHours) + buff.WriteFloat64(target.Cost) return nil } @@ -5431,11 +4946,12 @@ func (target *PVAllocation) UnmarshalBinaryWithContext(ctx *DecodingContext) (er return fmt.Errorf("Invalid Version Unmarshalling PVAllocation. Expected %d or less, got %d", AllocationCodecVersion, version) } - a := buff.ReadFloat64() // read float64 - target.ByteHours = a - - b := buff.ReadFloat64() // read float64 - target.Cost = b + var v0 float64 + v0 = buff.ReadFloat64() + target.ByteHours = v0 + var v1 float64 + v1 = buff.ReadFloat64() + target.Cost = v1 return nil } @@ -5488,15 +5004,14 @@ func (target *PVKey) MarshalBinaryWithContext(ctx *EncodingContext) (err error) buff.WriteUInt8(AllocationCodecVersion) // version if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(target.Cluster) - buff.WriteInt(a) // write table index + v0 := ctx.Table.AddOrGet(target.Cluster) + buff.WriteInt(v0) // write table index } else { buff.WriteString(target.Cluster) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(target.Name) - buff.WriteInt(b) // write table index + v1 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v1) // write table index } else { buff.WriteString(target.Name) // write string } @@ -5555,25 +5070,22 @@ func (target *PVKey) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error return fmt.Errorf("Invalid Version Unmarshalling PVKey. Expected %d or less, got %d", AllocationCodecVersion, version) } - var b string + var v0 string if ctx.IsStringTable() { - c := buff.ReadInt() // read string index - b = ctx.Table.At(c) + v1 := buff.ReadInt() // read string index + v0 = ctx.Table.At(v1) } else { - b = buff.ReadString() // read string + v0 = buff.ReadString() // read string } - a := b - target.Cluster = a - - var e string + target.Cluster = v0 + var v2 string if ctx.IsStringTable() { - f := buff.ReadInt() // read string index - e = ctx.Table.At(f) + v3 := buff.ReadInt() // read string index + v2 = ctx.Table.At(v3) } else { - e = buff.ReadString() // read string + v2 = buff.ReadString() // read string } - d := e - target.Name = d + target.Name = v2 return nil } @@ -5625,9 +5137,8 @@ func (target *RawAllocationOnlyData) MarshalBinaryWithContext(ctx *EncodingConte buff := ctx.Buffer buff.WriteUInt8(AllocationCodecVersion) // version - buff.WriteFloat64(target.CPUCoreUsageMax) // write float64 - - buff.WriteFloat64(target.RAMBytesUsageMax) // write float64 + buff.WriteFloat64(target.CPUCoreUsageMax) + buff.WriteFloat64(target.RAMBytesUsageMax) return nil } @@ -5683,11 +5194,12 @@ func (target *RawAllocationOnlyData) UnmarshalBinaryWithContext(ctx *DecodingCon return fmt.Errorf("Invalid Version Unmarshalling RawAllocationOnlyData. Expected %d or less, got %d", AllocationCodecVersion, version) } - a := buff.ReadFloat64() // read float64 - target.CPUCoreUsageMax = a - - b := buff.ReadFloat64() // read float64 - target.RAMBytesUsageMax = b + var v0 float64 + v0 = buff.ReadFloat64() + target.CPUCoreUsageMax = v0 + var v1 float64 + v1 = buff.ReadFloat64() + target.RAMBytesUsageMax = v1 return nil } @@ -5743,55 +5255,46 @@ func (target *SharedAsset) MarshalBinaryWithContext(ctx *EncodingContext) (err e buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][struct](AssetProperties) --- buff.WriteInt(0) // [compatibility, unused] - errA := target.properties.MarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v0 := target.properties.MarshalBinaryWithContext(ctx) + if v0 != nil { + return v0 } // --- [end][write][struct](AssetProperties) --- - } - // --- [begin][write][alias](AssetLabels) --- if map[string]string(target.labels) == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][map](map[string]string) --- buff.WriteInt(len(map[string]string(target.labels))) // map length - for v, z := range map[string]string(target.labels) { + for v1, v2 := range map[string]string(target.labels) { if ctx.IsStringTable() { - a := ctx.Table.AddOrGet(v) - buff.WriteInt(a) // write table index + v3 := ctx.Table.AddOrGet(v1) + buff.WriteInt(v3) // write table index } else { - buff.WriteString(v) // write string + buff.WriteString(v1) // write string } - if ctx.IsStringTable() { - b := ctx.Table.AddOrGet(z) - buff.WriteInt(b) // write table index + v4 := ctx.Table.AddOrGet(v2) + buff.WriteInt(v4) // write table index } else { - buff.WriteString(z) // write string + buff.WriteString(v2) // write string } - } // --- [end][write][map](map[string]string) --- - } // --- [end][write][alias](AssetLabels) --- - // --- [begin][write][struct](Window) --- buff.WriteInt(0) // [compatibility, unused] - errB := target.window.MarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v5 := target.window.MarshalBinaryWithContext(ctx) + if v5 != nil { + return v5 } // --- [end][write][struct](Window) --- - - buff.WriteFloat64(target.Cost) // write float64 + buff.WriteFloat64(target.Cost) return nil } @@ -5847,75 +5350,66 @@ func (target *SharedAsset) UnmarshalBinaryWithContext(ctx *DecodingContext) (err return fmt.Errorf("Invalid Version Unmarshalling SharedAsset. Expected %d or less, got %d", AssetsCodecVersion, version) } + var v0 *AssetProperties if buff.ReadUInt8() == uint8(0) { - target.properties = nil + v0 = nil } else { - // --- [begin][read][struct](AssetProperties) --- - a := new(AssetProperties) + v1 := new(AssetProperties) buff.ReadInt() // [compatibility, unused] - errA := a.UnmarshalBinaryWithContext(ctx) - if errA != nil { - return errA + v2 := v1.UnmarshalBinaryWithContext(ctx) + if v2 != nil { + return v2 } - target.properties = a + v0 = v1 // --- [end][read][struct](AssetProperties) --- - } - + target.properties = v0 + var v3 AssetLabels // --- [begin][read][alias](AssetLabels) --- - var b map[string]string + var v4 map[string]string if buff.ReadUInt8() == uint8(0) { - b = nil + v4 = nil } else { // --- [begin][read][map](map[string]string) --- - d := buff.ReadInt() // map len - c := make(map[string]string, d) - for range d { - var v string - var f string + v5 := buff.ReadInt() // map len + v4 = make(map[string]string, v5) + for range v5 { + var v6 string if ctx.IsStringTable() { - g := buff.ReadInt() // read string index - f = ctx.Table.At(g) + v7 := buff.ReadInt() // read string index + v6 = ctx.Table.At(v7) } else { - f = buff.ReadString() // read string + v6 = buff.ReadString() // read string } - e := f - v = e - - var z string - var l string + var v8 string if ctx.IsStringTable() { - m := buff.ReadInt() // read string index - l = ctx.Table.At(m) + v9 := buff.ReadInt() // read string index + v8 = ctx.Table.At(v9) } else { - l = buff.ReadString() // read string + v8 = buff.ReadString() // read string } - h := l - z = h - - c[v] = z + v4[v6] = v8 } - b = c // --- [end][read][map](map[string]string) --- - } - - target.labels = AssetLabels(b) + v3 = AssetLabels(v4) // --- [end][read][alias](AssetLabels) --- - + target.labels = v3 + var v10 Window // --- [begin][read][struct](Window) --- - n := new(Window) + v11 := new(Window) buff.ReadInt() // [compatibility, unused] - errB := n.UnmarshalBinaryWithContext(ctx) - if errB != nil { - return errB + v12 := v11.UnmarshalBinaryWithContext(ctx) + if v12 != nil { + return v12 } - target.window = *n + v10 = *v11 // --- [end][read][struct](Window) --- - - o := buff.ReadFloat64() // read float64 - target.Cost = o + target.window = v10 + var v13 float64 + v13 = buff.ReadFloat64() + target.Cost = v13 return nil } @@ -5971,31 +5465,27 @@ func (target *Window) MarshalBinaryWithContext(ctx *EncodingContext) (err error) buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][reference](time.Time) --- - a, errA := target.start.MarshalBinary() - if errA != nil { - return errA + v0, v1 := target.start.MarshalBinary() + if v1 != nil { + return v1 } - buff.WriteInt(len(a)) - buff.WriteBytes(a) + buff.WriteInt(len(v0)) + buff.WriteBytes(v0) // --- [end][write][reference](time.Time) --- - } if target.end == nil { buff.WriteUInt8(uint8(0)) // write nil byte } else { buff.WriteUInt8(uint8(1)) // write non-nil byte - // --- [begin][write][reference](time.Time) --- - b, errB := target.end.MarshalBinary() - if errB != nil { - return errB + v2, v3 := target.end.MarshalBinary() + if v3 != nil { + return v3 } - buff.WriteInt(len(b)) - buff.WriteBytes(b) + buff.WriteInt(len(v2)) + buff.WriteBytes(v2) // --- [end][write][reference](time.Time) --- - } return nil @@ -6052,39 +5542,38 @@ func (target *Window) UnmarshalBinaryWithContext(ctx *DecodingContext) (err erro return fmt.Errorf("Invalid Version Unmarshalling Window. Expected %d or less, got %d", DefaultCodecVersion, version) } + var v0 *time.Time if buff.ReadUInt8() == uint8(0) { - target.start = nil + v0 = nil } else { - // --- [begin][read][reference](time.Time) --- - a := new(time.Time) - b := buff.ReadInt() // byte array length - c := buff.ReadBytes(b) - errA := a.UnmarshalBinary(c) - if errA != nil { - return errA - } - target.start = a + v1 := new(time.Time) + v2 := buff.ReadInt() // byte array length + v3 := buff.ReadBytes(v2) + v4 := v1.UnmarshalBinary(v3) + if v4 != nil { + return v4 + } + v0 = v1 // --- [end][read][reference](time.Time) --- - } - + target.start = v0 + var v5 *time.Time if buff.ReadUInt8() == uint8(0) { - target.end = nil + v5 = nil } else { - // --- [begin][read][reference](time.Time) --- - d := new(time.Time) - e := buff.ReadInt() // byte array length - f := buff.ReadBytes(e) - errB := d.UnmarshalBinary(f) - if errB != nil { - return errB - } - target.end = d + v6 := new(time.Time) + v7 := buff.ReadInt() // byte array length + v8 := buff.ReadBytes(v7) + v9 := v6.UnmarshalBinary(v8) + if v9 != nil { + return v9 + } + v5 = v6 // --- [end][read][reference](time.Time) --- - } + target.end = v5 return nil } diff --git a/tests/roundtrip_test.go b/tests/roundtrip_test.go new file mode 100644 index 0000000..c485582 --- /dev/null +++ b/tests/roundtrip_test.go @@ -0,0 +1,117 @@ +package test + +import ( + "bytes" + "reflect" + "testing" + "time" + + "github.com/opencost/bingen/tests/aliases" + "github.com/opencost/bingen/tests/containerv2" + "github.com/opencost/bingen/tests/opencost" +) + +// TestRoundTrip_Aliases is a wire-level safety net for the generated aliases +// codec: it exercises alias types, maps, pointers, slices, and external define +// types. Encode -> decode must reproduce the original value. This guards the +// generator (template or core backend) against wire regressions. +func TestRoundTrip_Aliases(t *testing.T) { + orig := aliases.NewGeneratedParent() + + data, err := orig.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary: %v", err) + } + + decoded := &aliases.Parent{} + if err := decoded.UnmarshalBinary(data); err != nil { + t.Fatalf("UnmarshalBinary: %v", err) + } + + if !reflect.DeepEqual(orig, decoded) { + t.Fatalf("round-trip mismatch:\n orig: %+v\n decoded: %+v", orig, decoded) + } +} + +// TestStream_Container exercises the generated streaming decoder at runtime: it +// marshals a Container, then streams its fields back, flattening the Children +// slice one element per yield. This validates the core-generated streamer, not +// just that it compiles. +func TestStream_Container(t *testing.T) { + value := 2.5 + orig := &containerv2.Container{ + Name: "box", + Children: []string{"a", "b", "c"}, + Value: &value, + } + + data, err := orig.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary: %v", err) + } + + stream := containerv2.NewContainerStream(bytes.NewReader(data)) + defer stream.Close() + + var fields []string + var children []string + for fi, v := range stream.Stream() { + fields = append(fields, fi.Name) + if fi.Name == "Children" && v != nil { + children = append(children, v.Value.(string)) + } + if fi.Name == "Value" && v != nil { + if got := *(v.Value.(*float64)); got != 2.5 { + t.Errorf("Value = %v, want 2.5", got) + } + } + } + if err := stream.Error(); err != nil { + t.Fatalf("stream error: %v", err) + } + + wantFields := []string{"Name", "Children", "Children", "Children", "oldValue", "Value"} + if !reflect.DeepEqual(fields, wantFields) { + t.Fatalf("streamed fields = %v, want %v", fields, wantFields) + } + if !reflect.DeepEqual(children, []string{"a", "b", "c"}) { + t.Fatalf("streamed children = %v, want [a b c]", children) + } +} + +// TestRoundTrip_Opencost is a wire-level safety net for the full opencost codec: +// an AssetSet exercises a string table, a map of interface values +// (map[string]Asset), nested time.Time (via Window), nested structs, and +// pre/post-process hooks. Encode -> decode -> re-encode must succeed and be +// length-stable (the encoded length is deterministic even though map and +// string-table ordering are not). +func TestRoundTrip_Opencost(t *testing.T) { + start := time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC) + end := time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC) + win := opencost.NewWindow(&start, &end) + + orig := opencost.NewAssetSet(start, end, + opencost.NewCloud("compute", "provider-1", start, end, win), + opencost.NewDisk("disk-1", "cluster-a", "provider-2", start, end, win), + opencost.NewNode("node-1", "cluster-a", "provider-3", start, end, win), + ) + + b1, err := orig.MarshalBinary() + if err != nil { + t.Fatalf("MarshalBinary: %v", err) + } + + decoded := &opencost.AssetSet{} + if err := decoded.UnmarshalBinary(b1); err != nil { + t.Fatalf("UnmarshalBinary: %v", err) + } + + b2, err := decoded.MarshalBinary() + if err != nil { + t.Fatalf("re-encode MarshalBinary: %v", err) + } + + if len(b1) != len(b2) { + t.Fatalf("round-trip encoded length changed: first=%d re-encoded=%d", len(b1), len(b2)) + } +} diff --git a/tests/shape/bingen.go b/tests/shape/bingen.go new file mode 100644 index 0000000..ddbbfe0 --- /dev/null +++ b/tests/shape/bingen.go @@ -0,0 +1,6 @@ +package shape + +// @bingen:generate:Shape +// @bingen:generate:Circle +// @bingen:generate:Square +// @bingen:generate:Drawing diff --git a/tests/shape/shape.go b/tests/shape/shape.go new file mode 100644 index 0000000..398ce5e --- /dev/null +++ b/tests/shape/shape.go @@ -0,0 +1,35 @@ +package shape + +import "math" + +// Shape is a simple interface implemented by several concrete shapes. It is used +// to exercise interface-typed field encoding/decoding. +type Shape interface { + Area() float64 +} + +// Circle is a Shape. +type Circle struct { + Radius float64 +} + +// Area implements Shape. +func (c *Circle) Area() float64 { + return math.Pi * c.Radius * c.Radius +} + +// Square is a Shape. +type Square struct { + Side float64 +} + +// Area implements Shape. +func (s *Square) Area() float64 { + return s.Side * s.Side +} + +// Drawing holds a name and a heterogeneous list of shapes. +type Drawing struct { + Name string + Shapes []Shape +} diff --git a/tests/shape/shape_codecs.go b/tests/shape/shape_codecs.go new file mode 100644 index 0000000..e3082b7 --- /dev/null +++ b/tests/shape/shape_codecs.go @@ -0,0 +1,708 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package shape + +import ( + "fmt" + "io" + "os" + "sync" + + "reflect" + "strings" + + stringtable "github.com/opencost/bingen/pkg/table" + util "github.com/opencost/bingen/pkg/util" +) + +const ( + // GeneratorPackageName is the package the generator is targetting + GeneratorPackageName string = "shape" + + // DefaultCodecVersion is used for any resources listed in the Default version set + DefaultCodecVersion uint8 = 1 +) + +//-------------------------------------------------------------------------- +// Configuration +//-------------------------------------------------------------------------- + +var ( + bingenConfigLock sync.RWMutex + bingenConfig *BingenConfiguration = DefaultBingenConfiguration() +) + +// BingenConfiguration is used to set any custom configuration in the way files are encoded +// or decoded. +type BingenConfiguration struct { + // FileBackedStringTableEnabled enables the use of file-backed string tables for streaming + // bingen decoding. + FileBackedStringTableEnabled bool + + // FileBackedStringTableDir is the directory to write the string table files for reading. + FileBackedStringTableDir string + + // FileBackedStringTableMemoMaxBytes limits in-memory memoization for file-backed table lookups. + // 0 disables memoization. + FileBackedStringTableMemoMaxBytes int64 +} + +// DefaultBingenConfiguration creates the default implementation of the bingen configuration +// and returns it. +func DefaultBingenConfiguration() *BingenConfiguration { + return &BingenConfiguration{ + FileBackedStringTableEnabled: false, + FileBackedStringTableDir: os.TempDir(), + FileBackedStringTableMemoMaxBytes: 0, + } +} + +// ConfigureBingen accepts a new *BingenConfiguration instance which updates the internal decoder +// and encoder behavior. +func ConfigureBingen(config *BingenConfiguration) { + bingenConfigLock.Lock() + defer bingenConfigLock.Unlock() + + if config == nil { + config = DefaultBingenConfiguration() + } + bingenConfig = config +} + +// IsBingenFileBackedStringTableEnabled accessor for file backed string table configuration +func IsBingenFileBackedStringTableEnabled() bool { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableEnabled +} + +// BingenFileBackedStringTableDir returns the directory configured for file backed string tables. +func BingenFileBackedStringTableDir() string { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableDir +} + +// BingenFileBackedStringTableMemoMaxBytes returns the maximum bytes used for file-backed memo cache. +func BingenFileBackedStringTableMemoMaxBytes() int64 { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableMemoMaxBytes +} + +//-------------------------------------------------------------------------- +// Type Map +//-------------------------------------------------------------------------- + +// Generated type map for resolving interface implementations to to concrete types +var typeMap map[string]reflect.Type = map[string]reflect.Type{ + "Circle": reflect.TypeFor[Circle](), + "Drawing": reflect.TypeFor[Drawing](), + "Square": reflect.TypeFor[Square](), +} + +//-------------------------------------------------------------------------- +// Type Helpers +//-------------------------------------------------------------------------- + +// isBinaryTag returns true when the first bytes in the provided binary matches the tag +func isBinaryTag(data []byte, tag string) bool { + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// isReaderBinaryTag is used to peek the header for an io.Reader Buffer +func isReaderBinaryTag(buff *util.Buffer, tag string) bool { + data, err := buff.Peek(len(tag)) + if err != nil && err != io.EOF { + panic(fmt.Sprintf("called Peek() on a non buffered reader: %s", err)) + } + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// typeToString determines the basic properties of the type, the qualifier, package path, and +// type name, and returns the qualified type +func typeToString(f interface{}) string { + qual := "" + t := reflect.TypeOf(f) + if t.Kind() == reflect.Ptr { + t = t.Elem() + qual = "*" + } + + return fmt.Sprintf("%s%s.%s", qual, t.PkgPath(), t.Name()) +} + +// resolveType uses the name of a type and returns the package, base type name, and whether +// or not it's a pointer. +func resolveType(t string) (pkg string, name string, isPtr bool) { + isPtr = t[:1] == "*" + if isPtr { + t = t[1:] + } + + slashIndex := strings.LastIndex(t, "/") + if slashIndex >= 0 { + t = t[slashIndex+1:] + } + parts := strings.Split(t, ".") + if parts[0] == GeneratorPackageName { + parts[0] = "" + } + + pkg = parts[0] + name = parts[1] + return +} + +//-------------------------------------------------------------------------- +// Codec Context +//-------------------------------------------------------------------------- + +// EncodingContext is a context object passed to the encoders to ensure reuse of buffer +// and table data +type EncodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableWriter +} + +// NewEncodingContext creates a new EncodingContext instance that will create a new []byte buffer +// for writing, and return the context +func NewEncodingContext(tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBuffer(), + Table: tableWriter, + } +} + +// NewEncodingContextFromWriter creates a new EncodingContext instance that will create a new Buffer +// from the provided io.Writer and StringTableWriter. +func NewEncodingContextFromWriter(writer io.Writer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBufferFromWriter(writer), + Table: tableWriter, + } +} + +// NewEncodingContextFromBuffer creates a new EncodingContext instance that will leverage an existing +// Buffer and StringTableWriter. +func NewEncodingContextFromBuffer(buffer *util.Buffer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: buffer, + Table: tableWriter, + } +} + +// ToBytes returns the encoded string table bytes (if applicable) combined with the encoded buffer bytes. If +// a string table is being used, the string table bytes will be written first to ensure correct ordering for +// decoding. +func (ec *EncodingContext) ToBytes() []byte { + encBytes := ec.Buffer.Bytes() + if ec.Table != nil { + buff := util.NewBuffer() + ec.Table.WriteTo(buff) + buff.WriteBytes(encBytes) + return buff.Bytes() + } + + return encBytes +} + +// IsStringTable returns true if the table is available +func (ec *EncodingContext) IsStringTable() bool { + return ec.Table != nil +} + +// DecodingContext is a context object passed to the decoders to ensure parent objects +// reuse as much data as possible +type DecodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableReader +} + +// NewDecodingContextFromBytes creates a new DecodingContext instance using an byte slice +func NewDecodingContextFromBytes(data []byte) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromBytes(data) + + // string table header validation + if isBinaryTag(data, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // always use a slice string table with a byte array since the + // data is already in memory + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// NewDecodingContextFromReader creates a new DecodingContext instance using an io.Reader +// implementation +func NewDecodingContextFromReader(reader io.Reader) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromReader(reader) + + if isReaderBinaryTag(buff, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // create correct string table implementation + if IsBingenFileBackedStringTableEnabled() { + table = stringtable.NewFileStringTableReaderFrom(buff, BingenFileBackedStringTableDir(), GeneratorPackageName, BingenFileBackedStringTableMemoMaxBytes()) + } else { + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// IsStringTable returns true if the table is available +func (dc *DecodingContext) IsStringTable() bool { + return dc.Table != nil && dc.Table.Len() > 0 +} + +// Close will ensure that any string table resources and buffer resources are +// cleaned up. +func (dc *DecodingContext) Close() { + if dc.Table != nil { + _ = dc.Table.Close() + dc.Table = nil + } +} + +//-------------------------------------------------------------------------- +// Binary Codec +//-------------------------------------------------------------------------- + +// BinEncoder is an encoding interface which defines a context based marshal contract. +type BinEncoder interface { + MarshalBinaryWithContext(*EncodingContext) error +} + +// BinDecoder is a decoding interface which defines a context based unmarshal contract. +type BinDecoder interface { + UnmarshalBinaryWithContext(*DecodingContext) error +} + +//-------------------------------------------------------------------------- +// Circle +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Circle instance +// into a byte array +func (target *Circle) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(nil) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Circle instance +// into an io.Writer. +func (target *Circle) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + ctx := NewEncodingContextFromBuffer(buff, nil) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Circle instance +// into a byte array leveraging a predefined context. +func (target *Circle) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + buff.WriteFloat64(target.Radius) + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Circle type +func (target *Circle) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Circle type +func (target *Circle) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Circle type +func (target *Circle) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Circle. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 float64 + v0 = buff.ReadFloat64() + target.Radius = v0 + + return nil +} + +//-------------------------------------------------------------------------- +// Drawing +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Drawing instance +// into a byte array +func (target *Drawing) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(nil) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Drawing instance +// into an io.Writer. +func (target *Drawing) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + ctx := NewEncodingContextFromBuffer(buff, nil) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Drawing instance +// into a byte array leveraging a predefined context. +func (target *Drawing) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + if ctx.IsStringTable() { + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) + } else { + buff.WriteString(target.Name) + } + if target.Shapes == nil { + buff.WriteUInt8(uint8(0)) + } else { + buff.WriteUInt8(uint8(1)) + buff.WriteInt(len(target.Shapes)) + for v1 := range target.Shapes { + if target.Shapes[v1] == nil { + buff.WriteUInt8(uint8(0)) + } else { + buff.WriteUInt8(uint8(1)) + v2 := reflect.ValueOf(target.Shapes[v1]).Interface() + v3, v4 := v2.(BinEncoder) + if !v4 { + return fmt.Errorf("type: %s does not implement %s.BinEncoder", typeToString(target.Shapes[v1]), GeneratorPackageName) + } + buff.WriteString(typeToString(target.Shapes[v1])) + buff.WriteInt(0) + v5 := v3.MarshalBinaryWithContext(ctx) + if v5 != nil { + return v5 + } + } + } + } + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Drawing type +func (target *Drawing) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Drawing type +func (target *Drawing) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Drawing type +func (target *Drawing) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Drawing. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 string + if ctx.IsStringTable() { + v1 := buff.ReadInt() + v0 = ctx.Table.At(v1) + } else { + v0 = buff.ReadString() + } + target.Name = v0 + var v2 []Shape + if buff.ReadUInt8() == uint8(0) { + v2 = nil + } else { + v3 := buff.ReadInt() + v2 = make([]Shape, v3) + for v4 := range v3 { + var v5 Shape + if buff.ReadUInt8() == uint8(0) { + v5 = nil + } else { + v6 := buff.ReadString() + _, v7, _ := resolveType(v6) + if _, ok := typeMap[v7]; !ok { + return fmt.Errorf("Unknown Type: %s", v7) + } + v8, v9 := reflect.New(typeMap[v7]).Interface().(BinDecoder) + if !v9 { + return fmt.Errorf("Type: %s does not implement %s.BinDecoder.", v7, GeneratorPackageName) + } + buff.ReadInt() + v10 := v8.UnmarshalBinaryWithContext(ctx) + if v10 != nil { + return v10 + } + v5 = v8.(Shape) + } + v2[v4] = v5 + } + } + target.Shapes = v2 + + return nil +} + +//-------------------------------------------------------------------------- +// Square +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Square instance +// into a byte array +func (target *Square) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(nil) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Square instance +// into an io.Writer. +func (target *Square) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + ctx := NewEncodingContextFromBuffer(buff, nil) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Square instance +// into a byte array leveraging a predefined context. +func (target *Square) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + buff.WriteFloat64(target.Side) + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Square type +func (target *Square) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Square type +func (target *Square) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Square type +func (target *Square) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Square. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 float64 + v0 = buff.ReadFloat64() + target.Side = v0 + + return nil +} diff --git a/tests/streamfeed/bingen.go b/tests/streamfeed/bingen.go new file mode 100644 index 0000000..917b325 --- /dev/null +++ b/tests/streamfeed/bingen.go @@ -0,0 +1,3 @@ +package streamfeed + +// @bingen:generate[streamable]:Feed diff --git a/tests/streamfeed/streamfeed.go b/tests/streamfeed/streamfeed.go new file mode 100644 index 0000000..48c7e87 --- /dev/null +++ b/tests/streamfeed/streamfeed.go @@ -0,0 +1,11 @@ +package streamfeed + +// Feed is a streamable type using only string/int/collection fields so that a +// streamed value's textual form is identical in Go and Java, enabling a +// cross-language stream-sequence comparison. +type Feed struct { + Name string + Tags []string + Count int + Meta map[string]string +} diff --git a/tests/streamfeed/streamfeed_codecs.go b/tests/streamfeed/streamfeed_codecs.go new file mode 100644 index 0000000..c3ca57d --- /dev/null +++ b/tests/streamfeed/streamfeed_codecs.go @@ -0,0 +1,671 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package streamfeed + +import ( + "fmt" + "io" + "iter" + "os" + "reflect" + "strings" + "sync" + + bstream "github.com/opencost/bingen/pkg/stream" + stringtable "github.com/opencost/bingen/pkg/table" + util "github.com/opencost/bingen/pkg/util" +) + +const ( + // GeneratorPackageName is the package the generator is targetting + GeneratorPackageName string = "streamfeed" + + // DefaultCodecVersion is used for any resources listed in the Default version set + DefaultCodecVersion uint8 = 1 +) + +//-------------------------------------------------------------------------- +// Configuration +//-------------------------------------------------------------------------- + +var ( + bingenConfigLock sync.RWMutex + bingenConfig *BingenConfiguration = DefaultBingenConfiguration() +) + +// BingenConfiguration is used to set any custom configuration in the way files are encoded +// or decoded. +type BingenConfiguration struct { + // FileBackedStringTableEnabled enables the use of file-backed string tables for streaming + // bingen decoding. + FileBackedStringTableEnabled bool + + // FileBackedStringTableDir is the directory to write the string table files for reading. + FileBackedStringTableDir string + + // FileBackedStringTableMemoMaxBytes limits in-memory memoization for file-backed table lookups. + // 0 disables memoization. + FileBackedStringTableMemoMaxBytes int64 +} + +// DefaultBingenConfiguration creates the default implementation of the bingen configuration +// and returns it. +func DefaultBingenConfiguration() *BingenConfiguration { + return &BingenConfiguration{ + FileBackedStringTableEnabled: false, + FileBackedStringTableDir: os.TempDir(), + FileBackedStringTableMemoMaxBytes: 0, + } +} + +// ConfigureBingen accepts a new *BingenConfiguration instance which updates the internal decoder +// and encoder behavior. +func ConfigureBingen(config *BingenConfiguration) { + bingenConfigLock.Lock() + defer bingenConfigLock.Unlock() + + if config == nil { + config = DefaultBingenConfiguration() + } + bingenConfig = config +} + +// IsBingenFileBackedStringTableEnabled accessor for file backed string table configuration +func IsBingenFileBackedStringTableEnabled() bool { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableEnabled +} + +// BingenFileBackedStringTableDir returns the directory configured for file backed string tables. +func BingenFileBackedStringTableDir() string { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableDir +} + +// BingenFileBackedStringTableMemoMaxBytes returns the maximum bytes used for file-backed memo cache. +func BingenFileBackedStringTableMemoMaxBytes() int64 { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableMemoMaxBytes +} + +//-------------------------------------------------------------------------- +// Type Map +//-------------------------------------------------------------------------- + +// Generated type map for resolving interface implementations to to concrete types +var typeMap map[string]reflect.Type = map[string]reflect.Type{ + "Feed": reflect.TypeFor[Feed](), +} + +//-------------------------------------------------------------------------- +// Type Helpers +//-------------------------------------------------------------------------- + +// isBinaryTag returns true when the first bytes in the provided binary matches the tag +func isBinaryTag(data []byte, tag string) bool { + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// isReaderBinaryTag is used to peek the header for an io.Reader Buffer +func isReaderBinaryTag(buff *util.Buffer, tag string) bool { + data, err := buff.Peek(len(tag)) + if err != nil && err != io.EOF { + panic(fmt.Sprintf("called Peek() on a non buffered reader: %s", err)) + } + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// typeToString determines the basic properties of the type, the qualifier, package path, and +// type name, and returns the qualified type +func typeToString(f interface{}) string { + qual := "" + t := reflect.TypeOf(f) + if t.Kind() == reflect.Ptr { + t = t.Elem() + qual = "*" + } + + return fmt.Sprintf("%s%s.%s", qual, t.PkgPath(), t.Name()) +} + +// resolveType uses the name of a type and returns the package, base type name, and whether +// or not it's a pointer. +func resolveType(t string) (pkg string, name string, isPtr bool) { + isPtr = t[:1] == "*" + if isPtr { + t = t[1:] + } + + slashIndex := strings.LastIndex(t, "/") + if slashIndex >= 0 { + t = t[slashIndex+1:] + } + parts := strings.Split(t, ".") + if parts[0] == GeneratorPackageName { + parts[0] = "" + } + + pkg = parts[0] + name = parts[1] + return +} + +//-------------------------------------------------------------------------- +// Stream Helpers +//-------------------------------------------------------------------------- + +// StreamFactoryFunc is an alias for a func that creates a BingenStream implementation. +type StreamFactoryFunc func(io.Reader) bstream.BingenStream + +// Generated streamable factory map for finding the specific new stream methods +// by T type +var streamFactoryMap map[reflect.Type]StreamFactoryFunc = map[reflect.Type]StreamFactoryFunc{ + reflect.TypeFor[Feed](): NewFeedStream, +} + +// NewStreamFor accepts an io.Reader, and returns a new BingenStream for the generic T +// type provided _if_ it is a registered bingen type that is annotated as 'streamable'. See +// the streamFactoryMap for generated type listings. +func NewStreamFor[T any](reader io.Reader) (bstream.BingenStream, error) { + typeKey := reflect.TypeFor[T]() + + factory, ok := streamFactoryMap[typeKey] + if !ok { + return nil, fmt.Errorf("the type: %s is not a registered bingen streamable type", typeKey.Name()) + } + + return factory(reader), nil +} + +//-------------------------------------------------------------------------- +// Codec Context +//-------------------------------------------------------------------------- + +// EncodingContext is a context object passed to the encoders to ensure reuse of buffer +// and table data +type EncodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableWriter +} + +// NewEncodingContext creates a new EncodingContext instance that will create a new []byte buffer +// for writing, and return the context +func NewEncodingContext(tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBuffer(), + Table: tableWriter, + } +} + +// NewEncodingContextFromWriter creates a new EncodingContext instance that will create a new Buffer +// from the provided io.Writer and StringTableWriter. +func NewEncodingContextFromWriter(writer io.Writer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBufferFromWriter(writer), + Table: tableWriter, + } +} + +// NewEncodingContextFromBuffer creates a new EncodingContext instance that will leverage an existing +// Buffer and StringTableWriter. +func NewEncodingContextFromBuffer(buffer *util.Buffer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: buffer, + Table: tableWriter, + } +} + +// ToBytes returns the encoded string table bytes (if applicable) combined with the encoded buffer bytes. If +// a string table is being used, the string table bytes will be written first to ensure correct ordering for +// decoding. +func (ec *EncodingContext) ToBytes() []byte { + encBytes := ec.Buffer.Bytes() + if ec.Table != nil { + buff := util.NewBuffer() + ec.Table.WriteTo(buff) + buff.WriteBytes(encBytes) + return buff.Bytes() + } + + return encBytes +} + +// IsStringTable returns true if the table is available +func (ec *EncodingContext) IsStringTable() bool { + return ec.Table != nil +} + +// DecodingContext is a context object passed to the decoders to ensure parent objects +// reuse as much data as possible +type DecodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableReader +} + +// NewDecodingContextFromBytes creates a new DecodingContext instance using an byte slice +func NewDecodingContextFromBytes(data []byte) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromBytes(data) + + // string table header validation + if isBinaryTag(data, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // always use a slice string table with a byte array since the + // data is already in memory + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// NewDecodingContextFromReader creates a new DecodingContext instance using an io.Reader +// implementation +func NewDecodingContextFromReader(reader io.Reader) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromReader(reader) + + if isReaderBinaryTag(buff, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // create correct string table implementation + if IsBingenFileBackedStringTableEnabled() { + table = stringtable.NewFileStringTableReaderFrom(buff, BingenFileBackedStringTableDir(), GeneratorPackageName, BingenFileBackedStringTableMemoMaxBytes()) + } else { + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// IsStringTable returns true if the table is available +func (dc *DecodingContext) IsStringTable() bool { + return dc.Table != nil && dc.Table.Len() > 0 +} + +// Close will ensure that any string table resources and buffer resources are +// cleaned up. +func (dc *DecodingContext) Close() { + if dc.Table != nil { + _ = dc.Table.Close() + dc.Table = nil + } +} + +//-------------------------------------------------------------------------- +// Binary Codec +//-------------------------------------------------------------------------- + +// BinEncoder is an encoding interface which defines a context based marshal contract. +type BinEncoder interface { + MarshalBinaryWithContext(*EncodingContext) error +} + +// BinDecoder is a decoding interface which defines a context based unmarshal contract. +type BinDecoder interface { + UnmarshalBinaryWithContext(*DecodingContext) error +} + +//-------------------------------------------------------------------------- +// Feed +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Feed instance +// into a byte array +func (target *Feed) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(nil) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Feed instance +// into an io.Writer. +func (target *Feed) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + ctx := NewEncodingContextFromBuffer(buff, nil) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Feed instance +// into a byte array leveraging a predefined context. +func (target *Feed) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + if ctx.IsStringTable() { + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) + } else { + buff.WriteString(target.Name) + } + if target.Tags == nil { + buff.WriteUInt8(uint8(0)) + } else { + buff.WriteUInt8(uint8(1)) + buff.WriteInt(len(target.Tags)) + for v1 := range target.Tags { + if ctx.IsStringTable() { + v2 := ctx.Table.AddOrGet(target.Tags[v1]) + buff.WriteInt(v2) + } else { + buff.WriteString(target.Tags[v1]) + } + } + } + buff.WriteInt(target.Count) + if target.Meta == nil { + buff.WriteUInt8(uint8(0)) + } else { + buff.WriteUInt8(uint8(1)) + buff.WriteInt(len(target.Meta)) + for v3, v4 := range target.Meta { + if ctx.IsStringTable() { + v5 := ctx.Table.AddOrGet(v3) + buff.WriteInt(v5) + } else { + buff.WriteString(v3) + } + if ctx.IsStringTable() { + v6 := ctx.Table.AddOrGet(v4) + buff.WriteInt(v6) + } else { + buff.WriteString(v4) + } + } + } + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Feed type +func (target *Feed) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Feed type +func (target *Feed) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Feed type +func (target *Feed) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Feed. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 string + if ctx.IsStringTable() { + v1 := buff.ReadInt() + v0 = ctx.Table.At(v1) + } else { + v0 = buff.ReadString() + } + target.Name = v0 + var v2 []string + if buff.ReadUInt8() == uint8(0) { + v2 = nil + } else { + v3 := buff.ReadInt() + v2 = make([]string, v3) + for v4 := range v3 { + var v5 string + if ctx.IsStringTable() { + v6 := buff.ReadInt() + v5 = ctx.Table.At(v6) + } else { + v5 = buff.ReadString() + } + v2[v4] = v5 + } + } + target.Tags = v2 + var v7 int + v7 = buff.ReadInt() + target.Count = v7 + var v8 map[string]string + if buff.ReadUInt8() == uint8(0) { + v8 = nil + } else { + v9 := buff.ReadInt() + v8 = make(map[string]string, v9) + for range v9 { + var v10 string + if ctx.IsStringTable() { + v11 := buff.ReadInt() + v10 = ctx.Table.At(v11) + } else { + v10 = buff.ReadString() + } + var v12 string + if ctx.IsStringTable() { + v13 := buff.ReadInt() + v12 = ctx.Table.At(v13) + } else { + v12 = buff.ReadString() + } + v8[v10] = v12 + } + } + target.Meta = v8 + + return nil +} + +//-------------------------------------------------------------------------- +// FeedStream +//-------------------------------------------------------------------------- + +// FeedStream is a single use field stream for the contents of an Feed instance. Instead of creating an instance and populating +// the fields on that instance, we provide a streaming iterator which yields (BingenFieldInfo, *BingenValue) tuples for each +// streamable element. All slices and maps will be flattened one depth and each element streamed individually. +type FeedStream struct { + reader io.Reader + ctx *DecodingContext + err error +} + +// Closes closes the internal io.Reader used to read and parse the Feed fields. +// This should be called once the stream is no longer needed. +func (stream *FeedStream) Close() { + if closer, ok := stream.reader.(io.Closer); ok { + closer.Close() + } + stream.ctx.Close() +} + +// Error returns an error if one occurred during the process of streaming the Feed +// This can be checked after iterating through the Stream(). +func (stream *FeedStream) Error() error { + return stream.err +} + +// NewFeedStream creates a new FeedStream, which uses the io.Reader data to stream all internal fields of an Feed instance +func NewFeedStream(reader io.Reader) bstream.BingenStream { + ctx := NewDecodingContextFromReader(reader) + + return &FeedStream{ + ctx: ctx, + reader: reader, + } +} + +// Stream returns the iterator which will stream each field of the target type. +func (stream *FeedStream) Stream() iter.Seq2[bstream.BingenFieldInfo, *bstream.BingenValue] { + return func(yield func(bstream.BingenFieldInfo, *bstream.BingenValue) bool) { + var fi bstream.BingenFieldInfo + + ctx := stream.ctx + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + stream.err = fmt.Errorf("Invalid Version Unmarshalling Feed. Expected %d or less, got %d", DefaultCodecVersion, version) + return + } + + fi = bstream.BingenFieldInfo{ + Type: reflect.TypeFor[string](), + Name: "Name", + } + var v0 string + if ctx.IsStringTable() { + v1 := buff.ReadInt() + v0 = ctx.Table.At(v1) + } else { + v0 = buff.ReadString() + } + if !yield(fi, bstream.SingleV(v0)) { + return + } + fi = bstream.BingenFieldInfo{ + Type: reflect.TypeFor[[]string](), + Name: "Tags", + } + if buff.ReadUInt8() == uint8(0) { + if !yield(fi, nil) { + return + } + } else { + v2 := buff.ReadInt() + for v3 := range v2 { + var v4 string + if ctx.IsStringTable() { + v5 := buff.ReadInt() + v4 = ctx.Table.At(v5) + } else { + v4 = buff.ReadString() + } + if !yield(fi, bstream.PairV(v3, v4)) { + return + } + } + } + fi = bstream.BingenFieldInfo{ + Type: reflect.TypeFor[int](), + Name: "Count", + } + var v6 int + v6 = buff.ReadInt() + if !yield(fi, bstream.SingleV(v6)) { + return + } + fi = bstream.BingenFieldInfo{ + Type: reflect.TypeFor[map[string]string](), + Name: "Meta", + } + if buff.ReadUInt8() == uint8(0) { + if !yield(fi, nil) { + return + } + } else { + v7 := buff.ReadInt() + for range v7 { + var v8 string + if ctx.IsStringTable() { + v9 := buff.ReadInt() + v8 = ctx.Table.At(v9) + } else { + v8 = buff.ReadString() + } + var v10 string + if ctx.IsStringTable() { + v11 := buff.ReadInt() + v10 = ctx.Table.At(v11) + } else { + v10 = buff.ReadString() + } + if !yield(fi, bstream.PairV(v8, v10)) { + return + } + } + } + } +} diff --git a/tests/sttable/bingen.go b/tests/sttable/bingen.go new file mode 100644 index 0000000..c61631b --- /dev/null +++ b/tests/sttable/bingen.go @@ -0,0 +1,3 @@ +package sttable + +// @bingen:generate[stringtable]:Doc diff --git a/tests/sttable/sttable.go b/tests/sttable/sttable.go new file mode 100644 index 0000000..3835c5e --- /dev/null +++ b/tests/sttable/sttable.go @@ -0,0 +1,9 @@ +package sttable + +// Doc exercises string-table encoding: repeated strings across fields should be +// deduplicated into a shared table. +type Doc struct { + Title string + Tags []string + Author string +} diff --git a/tests/sttable/sttable_codecs.go b/tests/sttable/sttable_codecs.go new file mode 100644 index 0000000..85d5e8d --- /dev/null +++ b/tests/sttable/sttable_codecs.go @@ -0,0 +1,489 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package sttable + +import ( + "fmt" + "io" + "os" + "sync" + + "reflect" + "strings" + + stringtable "github.com/opencost/bingen/pkg/table" + util "github.com/opencost/bingen/pkg/util" +) + +const ( + // GeneratorPackageName is the package the generator is targetting + GeneratorPackageName string = "sttable" + + // DefaultCodecVersion is used for any resources listed in the Default version set + DefaultCodecVersion uint8 = 1 +) + +//-------------------------------------------------------------------------- +// Configuration +//-------------------------------------------------------------------------- + +var ( + bingenConfigLock sync.RWMutex + bingenConfig *BingenConfiguration = DefaultBingenConfiguration() +) + +// BingenConfiguration is used to set any custom configuration in the way files are encoded +// or decoded. +type BingenConfiguration struct { + // FileBackedStringTableEnabled enables the use of file-backed string tables for streaming + // bingen decoding. + FileBackedStringTableEnabled bool + + // FileBackedStringTableDir is the directory to write the string table files for reading. + FileBackedStringTableDir string + + // FileBackedStringTableMemoMaxBytes limits in-memory memoization for file-backed table lookups. + // 0 disables memoization. + FileBackedStringTableMemoMaxBytes int64 +} + +// DefaultBingenConfiguration creates the default implementation of the bingen configuration +// and returns it. +func DefaultBingenConfiguration() *BingenConfiguration { + return &BingenConfiguration{ + FileBackedStringTableEnabled: false, + FileBackedStringTableDir: os.TempDir(), + FileBackedStringTableMemoMaxBytes: 0, + } +} + +// ConfigureBingen accepts a new *BingenConfiguration instance which updates the internal decoder +// and encoder behavior. +func ConfigureBingen(config *BingenConfiguration) { + bingenConfigLock.Lock() + defer bingenConfigLock.Unlock() + + if config == nil { + config = DefaultBingenConfiguration() + } + bingenConfig = config +} + +// IsBingenFileBackedStringTableEnabled accessor for file backed string table configuration +func IsBingenFileBackedStringTableEnabled() bool { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableEnabled +} + +// BingenFileBackedStringTableDir returns the directory configured for file backed string tables. +func BingenFileBackedStringTableDir() string { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableDir +} + +// BingenFileBackedStringTableMemoMaxBytes returns the maximum bytes used for file-backed memo cache. +func BingenFileBackedStringTableMemoMaxBytes() int64 { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableMemoMaxBytes +} + +//-------------------------------------------------------------------------- +// Type Map +//-------------------------------------------------------------------------- + +// Generated type map for resolving interface implementations to to concrete types +var typeMap map[string]reflect.Type = map[string]reflect.Type{ + "Doc": reflect.TypeFor[Doc](), +} + +//-------------------------------------------------------------------------- +// Type Helpers +//-------------------------------------------------------------------------- + +// isBinaryTag returns true when the first bytes in the provided binary matches the tag +func isBinaryTag(data []byte, tag string) bool { + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// isReaderBinaryTag is used to peek the header for an io.Reader Buffer +func isReaderBinaryTag(buff *util.Buffer, tag string) bool { + data, err := buff.Peek(len(tag)) + if err != nil && err != io.EOF { + panic(fmt.Sprintf("called Peek() on a non buffered reader: %s", err)) + } + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// typeToString determines the basic properties of the type, the qualifier, package path, and +// type name, and returns the qualified type +func typeToString(f interface{}) string { + qual := "" + t := reflect.TypeOf(f) + if t.Kind() == reflect.Ptr { + t = t.Elem() + qual = "*" + } + + return fmt.Sprintf("%s%s.%s", qual, t.PkgPath(), t.Name()) +} + +// resolveType uses the name of a type and returns the package, base type name, and whether +// or not it's a pointer. +func resolveType(t string) (pkg string, name string, isPtr bool) { + isPtr = t[:1] == "*" + if isPtr { + t = t[1:] + } + + slashIndex := strings.LastIndex(t, "/") + if slashIndex >= 0 { + t = t[slashIndex+1:] + } + parts := strings.Split(t, ".") + if parts[0] == GeneratorPackageName { + parts[0] = "" + } + + pkg = parts[0] + name = parts[1] + return +} + +//-------------------------------------------------------------------------- +// Codec Context +//-------------------------------------------------------------------------- + +// EncodingContext is a context object passed to the encoders to ensure reuse of buffer +// and table data +type EncodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableWriter +} + +// NewEncodingContext creates a new EncodingContext instance that will create a new []byte buffer +// for writing, and return the context +func NewEncodingContext(tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBuffer(), + Table: tableWriter, + } +} + +// NewEncodingContextFromWriter creates a new EncodingContext instance that will create a new Buffer +// from the provided io.Writer and StringTableWriter. +func NewEncodingContextFromWriter(writer io.Writer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBufferFromWriter(writer), + Table: tableWriter, + } +} + +// NewEncodingContextFromBuffer creates a new EncodingContext instance that will leverage an existing +// Buffer and StringTableWriter. +func NewEncodingContextFromBuffer(buffer *util.Buffer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: buffer, + Table: tableWriter, + } +} + +// ToBytes returns the encoded string table bytes (if applicable) combined with the encoded buffer bytes. If +// a string table is being used, the string table bytes will be written first to ensure correct ordering for +// decoding. +func (ec *EncodingContext) ToBytes() []byte { + encBytes := ec.Buffer.Bytes() + if ec.Table != nil { + buff := util.NewBuffer() + ec.Table.WriteTo(buff) + buff.WriteBytes(encBytes) + return buff.Bytes() + } + + return encBytes +} + +// IsStringTable returns true if the table is available +func (ec *EncodingContext) IsStringTable() bool { + return ec.Table != nil +} + +// DecodingContext is a context object passed to the decoders to ensure parent objects +// reuse as much data as possible +type DecodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableReader +} + +// NewDecodingContextFromBytes creates a new DecodingContext instance using an byte slice +func NewDecodingContextFromBytes(data []byte) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromBytes(data) + + // string table header validation + if isBinaryTag(data, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // always use a slice string table with a byte array since the + // data is already in memory + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// NewDecodingContextFromReader creates a new DecodingContext instance using an io.Reader +// implementation +func NewDecodingContextFromReader(reader io.Reader) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromReader(reader) + + if isReaderBinaryTag(buff, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // create correct string table implementation + if IsBingenFileBackedStringTableEnabled() { + table = stringtable.NewFileStringTableReaderFrom(buff, BingenFileBackedStringTableDir(), GeneratorPackageName, BingenFileBackedStringTableMemoMaxBytes()) + } else { + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// IsStringTable returns true if the table is available +func (dc *DecodingContext) IsStringTable() bool { + return dc.Table != nil && dc.Table.Len() > 0 +} + +// Close will ensure that any string table resources and buffer resources are +// cleaned up. +func (dc *DecodingContext) Close() { + if dc.Table != nil { + _ = dc.Table.Close() + dc.Table = nil + } +} + +//-------------------------------------------------------------------------- +// Binary Codec +//-------------------------------------------------------------------------- + +// BinEncoder is an encoding interface which defines a context based marshal contract. +type BinEncoder interface { + MarshalBinaryWithContext(*EncodingContext) error +} + +// BinDecoder is a decoding interface which defines a context based unmarshal contract. +type BinDecoder interface { + UnmarshalBinaryWithContext(*DecodingContext) error +} + +//-------------------------------------------------------------------------- +// Doc +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Doc instance +// into a byte array +func (target *Doc) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(stringtable.NewIndexedStringTableWriter()) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Doc instance +// into an io.Writer. +func (target *Doc) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + // run a pre-pass to collect all strings into the string table and discard all writes to the main + // buffer. Then, we write the string table, sorted by number of repeated uses (descending), to the + // main buffer, and use the resulting table as part of the context for the main pass. + prepass := stringtable.NewPrepassStringTableWriter() + prepassCtx := NewEncodingContextFromWriter(io.Discard, prepass) + + e := target.MarshalBinaryWithContext(prepassCtx) + if e != nil { + return e + } + + tableWriter := prepass.WriteSortedTo(buff) + ctx := NewEncodingContextFromBuffer(buff, tableWriter) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Doc instance +// into a byte array leveraging a predefined context. +func (target *Doc) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + if ctx.IsStringTable() { + v0 := ctx.Table.AddOrGet(target.Title) + buff.WriteInt(v0) + } else { + buff.WriteString(target.Title) + } + if target.Tags == nil { + buff.WriteUInt8(uint8(0)) + } else { + buff.WriteUInt8(uint8(1)) + buff.WriteInt(len(target.Tags)) + for v1 := range target.Tags { + if ctx.IsStringTable() { + v2 := ctx.Table.AddOrGet(target.Tags[v1]) + buff.WriteInt(v2) + } else { + buff.WriteString(target.Tags[v1]) + } + } + } + if ctx.IsStringTable() { + v3 := ctx.Table.AddOrGet(target.Author) + buff.WriteInt(v3) + } else { + buff.WriteString(target.Author) + } + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Doc type +func (target *Doc) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Doc type +func (target *Doc) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Doc type +func (target *Doc) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Doc. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 string + if ctx.IsStringTable() { + v1 := buff.ReadInt() + v0 = ctx.Table.At(v1) + } else { + v0 = buff.ReadString() + } + target.Title = v0 + var v2 []string + if buff.ReadUInt8() == uint8(0) { + v2 = nil + } else { + v3 := buff.ReadInt() + v2 = make([]string, v3) + for v4 := range v3 { + var v5 string + if ctx.IsStringTable() { + v6 := buff.ReadInt() + v5 = ctx.Table.At(v6) + } else { + v5 = buff.ReadString() + } + v2[v4] = v5 + } + } + target.Tags = v2 + var v7 string + if ctx.IsStringTable() { + v8 := buff.ReadInt() + v7 = ctx.Table.At(v8) + } else { + v7 = buff.ReadString() + } + target.Author = v7 + + return nil +} diff --git a/tests/timerec/bingen.go b/tests/timerec/bingen.go new file mode 100644 index 0000000..7600150 --- /dev/null +++ b/tests/timerec/bingen.go @@ -0,0 +1,3 @@ +package timerec + +// @bingen:generate:Event diff --git a/tests/timerec/timerec.go b/tests/timerec/timerec.go new file mode 100644 index 0000000..5ef2fee --- /dev/null +++ b/tests/timerec/timerec.go @@ -0,0 +1,11 @@ +package timerec + +import "time" + +// Event exercises a time.Time field, which bingen encodes as an external +// reference (length-prefixed time.Time.MarshalBinary output). +type Event struct { + Name string + At time.Time + Seq int +} diff --git a/tests/timerec/timerec_codecs.go b/tests/timerec/timerec_codecs.go new file mode 100644 index 0000000..c040168 --- /dev/null +++ b/tests/timerec/timerec_codecs.go @@ -0,0 +1,452 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// DO NOT MODIFY +// +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// +// +// This source file was automatically generated by bingen. +// +//////////////////////////////////////////////////////////////////////////////// + +package timerec + +import ( + "fmt" + "io" + "os" + "sync" + + "reflect" + "strings" + "time" + + stringtable "github.com/opencost/bingen/pkg/table" + util "github.com/opencost/bingen/pkg/util" +) + +const ( + // GeneratorPackageName is the package the generator is targetting + GeneratorPackageName string = "timerec" + + // DefaultCodecVersion is used for any resources listed in the Default version set + DefaultCodecVersion uint8 = 1 +) + +//-------------------------------------------------------------------------- +// Configuration +//-------------------------------------------------------------------------- + +var ( + bingenConfigLock sync.RWMutex + bingenConfig *BingenConfiguration = DefaultBingenConfiguration() +) + +// BingenConfiguration is used to set any custom configuration in the way files are encoded +// or decoded. +type BingenConfiguration struct { + // FileBackedStringTableEnabled enables the use of file-backed string tables for streaming + // bingen decoding. + FileBackedStringTableEnabled bool + + // FileBackedStringTableDir is the directory to write the string table files for reading. + FileBackedStringTableDir string + + // FileBackedStringTableMemoMaxBytes limits in-memory memoization for file-backed table lookups. + // 0 disables memoization. + FileBackedStringTableMemoMaxBytes int64 +} + +// DefaultBingenConfiguration creates the default implementation of the bingen configuration +// and returns it. +func DefaultBingenConfiguration() *BingenConfiguration { + return &BingenConfiguration{ + FileBackedStringTableEnabled: false, + FileBackedStringTableDir: os.TempDir(), + FileBackedStringTableMemoMaxBytes: 0, + } +} + +// ConfigureBingen accepts a new *BingenConfiguration instance which updates the internal decoder +// and encoder behavior. +func ConfigureBingen(config *BingenConfiguration) { + bingenConfigLock.Lock() + defer bingenConfigLock.Unlock() + + if config == nil { + config = DefaultBingenConfiguration() + } + bingenConfig = config +} + +// IsBingenFileBackedStringTableEnabled accessor for file backed string table configuration +func IsBingenFileBackedStringTableEnabled() bool { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableEnabled +} + +// BingenFileBackedStringTableDir returns the directory configured for file backed string tables. +func BingenFileBackedStringTableDir() string { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableDir +} + +// BingenFileBackedStringTableMemoMaxBytes returns the maximum bytes used for file-backed memo cache. +func BingenFileBackedStringTableMemoMaxBytes() int64 { + bingenConfigLock.RLock() + defer bingenConfigLock.RUnlock() + + return bingenConfig.FileBackedStringTableMemoMaxBytes +} + +//-------------------------------------------------------------------------- +// Type Map +//-------------------------------------------------------------------------- + +// Generated type map for resolving interface implementations to to concrete types +var typeMap map[string]reflect.Type = map[string]reflect.Type{ + "Event": reflect.TypeFor[Event](), +} + +//-------------------------------------------------------------------------- +// Type Helpers +//-------------------------------------------------------------------------- + +// isBinaryTag returns true when the first bytes in the provided binary matches the tag +func isBinaryTag(data []byte, tag string) bool { + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// isReaderBinaryTag is used to peek the header for an io.Reader Buffer +func isReaderBinaryTag(buff *util.Buffer, tag string) bool { + data, err := buff.Peek(len(tag)) + if err != nil && err != io.EOF { + panic(fmt.Sprintf("called Peek() on a non buffered reader: %s", err)) + } + if len(data) < len(tag) { + return false + } + + return string(data[:len(tag)]) == tag +} + +// typeToString determines the basic properties of the type, the qualifier, package path, and +// type name, and returns the qualified type +func typeToString(f interface{}) string { + qual := "" + t := reflect.TypeOf(f) + if t.Kind() == reflect.Ptr { + t = t.Elem() + qual = "*" + } + + return fmt.Sprintf("%s%s.%s", qual, t.PkgPath(), t.Name()) +} + +// resolveType uses the name of a type and returns the package, base type name, and whether +// or not it's a pointer. +func resolveType(t string) (pkg string, name string, isPtr bool) { + isPtr = t[:1] == "*" + if isPtr { + t = t[1:] + } + + slashIndex := strings.LastIndex(t, "/") + if slashIndex >= 0 { + t = t[slashIndex+1:] + } + parts := strings.Split(t, ".") + if parts[0] == GeneratorPackageName { + parts[0] = "" + } + + pkg = parts[0] + name = parts[1] + return +} + +//-------------------------------------------------------------------------- +// Codec Context +//-------------------------------------------------------------------------- + +// EncodingContext is a context object passed to the encoders to ensure reuse of buffer +// and table data +type EncodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableWriter +} + +// NewEncodingContext creates a new EncodingContext instance that will create a new []byte buffer +// for writing, and return the context +func NewEncodingContext(tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBuffer(), + Table: tableWriter, + } +} + +// NewEncodingContextFromWriter creates a new EncodingContext instance that will create a new Buffer +// from the provided io.Writer and StringTableWriter. +func NewEncodingContextFromWriter(writer io.Writer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: util.NewBufferFromWriter(writer), + Table: tableWriter, + } +} + +// NewEncodingContextFromBuffer creates a new EncodingContext instance that will leverage an existing +// Buffer and StringTableWriter. +func NewEncodingContextFromBuffer(buffer *util.Buffer, tableWriter stringtable.StringTableWriter) *EncodingContext { + return &EncodingContext{ + Buffer: buffer, + Table: tableWriter, + } +} + +// ToBytes returns the encoded string table bytes (if applicable) combined with the encoded buffer bytes. If +// a string table is being used, the string table bytes will be written first to ensure correct ordering for +// decoding. +func (ec *EncodingContext) ToBytes() []byte { + encBytes := ec.Buffer.Bytes() + if ec.Table != nil { + buff := util.NewBuffer() + ec.Table.WriteTo(buff) + buff.WriteBytes(encBytes) + return buff.Bytes() + } + + return encBytes +} + +// IsStringTable returns true if the table is available +func (ec *EncodingContext) IsStringTable() bool { + return ec.Table != nil +} + +// DecodingContext is a context object passed to the decoders to ensure parent objects +// reuse as much data as possible +type DecodingContext struct { + Buffer *util.Buffer + Table stringtable.StringTableReader +} + +// NewDecodingContextFromBytes creates a new DecodingContext instance using an byte slice +func NewDecodingContextFromBytes(data []byte) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromBytes(data) + + // string table header validation + if isBinaryTag(data, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // always use a slice string table with a byte array since the + // data is already in memory + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// NewDecodingContextFromReader creates a new DecodingContext instance using an io.Reader +// implementation +func NewDecodingContextFromReader(reader io.Reader) *DecodingContext { + var table stringtable.StringTableReader + + buff := util.NewBufferFromReader(reader) + + if isReaderBinaryTag(buff, stringtable.BinaryTagStringTable) { + buff.ReadBytes(len(stringtable.BinaryTagStringTable)) // strip tag length + + // create correct string table implementation + if IsBingenFileBackedStringTableEnabled() { + table = stringtable.NewFileStringTableReaderFrom(buff, BingenFileBackedStringTableDir(), GeneratorPackageName, BingenFileBackedStringTableMemoMaxBytes()) + } else { + table = stringtable.NewSliceStringTableReaderFrom(buff) + } + } + + return &DecodingContext{ + Buffer: buff, + Table: table, + } +} + +// IsStringTable returns true if the table is available +func (dc *DecodingContext) IsStringTable() bool { + return dc.Table != nil && dc.Table.Len() > 0 +} + +// Close will ensure that any string table resources and buffer resources are +// cleaned up. +func (dc *DecodingContext) Close() { + if dc.Table != nil { + _ = dc.Table.Close() + dc.Table = nil + } +} + +//-------------------------------------------------------------------------- +// Binary Codec +//-------------------------------------------------------------------------- + +// BinEncoder is an encoding interface which defines a context based marshal contract. +type BinEncoder interface { + MarshalBinaryWithContext(*EncodingContext) error +} + +// BinDecoder is a decoding interface which defines a context based unmarshal contract. +type BinDecoder interface { + UnmarshalBinaryWithContext(*DecodingContext) error +} + +//-------------------------------------------------------------------------- +// Event +//-------------------------------------------------------------------------- + +// MarshalBinary serializes the internal properties of this Event instance +// into a byte array +func (target *Event) MarshalBinary() (data []byte, err error) { + ctx := NewEncodingContext(nil) + + e := target.MarshalBinaryWithContext(ctx) + if e != nil { + return nil, e + } + + return ctx.ToBytes(), nil +} + +// MarshalBinary serializes the internal properties of this Event instance +// into an io.Writer. +func (target *Event) MarshalBinaryTo(writer io.Writer) error { + buff := util.NewBufferFromWriter(writer) + defer buff.Flush() + + ctx := NewEncodingContextFromBuffer(buff, nil) + + return target.MarshalBinaryWithContext(ctx) +} + +// MarshalBinaryWithContext serializes the internal properties of this Event instance +// into a byte array leveraging a predefined context. +func (target *Event) MarshalBinaryWithContext(ctx *EncodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + buff.WriteUInt8(DefaultCodecVersion) // version + + if ctx.IsStringTable() { + v0 := ctx.Table.AddOrGet(target.Name) + buff.WriteInt(v0) + } else { + buff.WriteString(target.Name) + } + v1, v2 := target.At.MarshalBinary() + if v2 != nil { + return v2 + } + buff.WriteInt(len(v1)) + buff.WriteBytes(v1) + buff.WriteInt(target.Seq) + + return nil +} + +// UnmarshalBinary uses the data passed byte array to set all the internal properties of +// the Event type +func (target *Event) UnmarshalBinary(data []byte) error { + ctx := NewDecodingContextFromBytes(data) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryFromReader uses the io.Reader data to set all the internal properties of +// the Event type +func (target *Event) UnmarshalBinaryFromReader(reader io.Reader) error { + ctx := NewDecodingContextFromReader(reader) + defer ctx.Close() + + err := target.UnmarshalBinaryWithContext(ctx) + if err != nil { + return err + } + + return nil +} + +// UnmarshalBinaryWithContext uses the context containing a string table and binary buffer to set all the internal properties of +// the Event type +func (target *Event) UnmarshalBinaryWithContext(ctx *DecodingContext) (err error) { + // panics are recovered and propagated as errors + defer func() { + if r := recover(); r != nil { + if e, ok := r.(error); ok { + err = e + } else if s, ok := r.(string); ok { + err = fmt.Errorf("unexpected panic: %s", s) + } else { + err = fmt.Errorf("unexpected panic: %+v", r) + } + } + }() + + buff := ctx.Buffer + version := buff.ReadUInt8() + + if version > DefaultCodecVersion { + return fmt.Errorf("Invalid Version Unmarshalling Event. Expected %d or less, got %d", DefaultCodecVersion, version) + } + + var v0 string + if ctx.IsStringTable() { + v1 := buff.ReadInt() + v0 = ctx.Table.At(v1) + } else { + v0 = buff.ReadString() + } + target.Name = v0 + var v2 time.Time + v3 := new(time.Time) + v4 := buff.ReadInt() + v5 := buff.ReadBytes(v4) + v6 := v3.UnmarshalBinary(v5) + if v6 != nil { + return v6 + } + v2 = *v3 + target.At = v2 + var v7 int + v7 = buff.ReadInt() + target.Seq = v7 + + return nil +} diff --git a/tests/var_test.go b/tests/var_test.go deleted file mode 100644 index 9d751ed..0000000 --- a/tests/var_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package test - -import ( - "fmt" - "strings" - "testing" - - "github.com/opencost/bingen/internal/generator/vars" -) - -func checkVarNames(t *testing.T, current string, varName ...string) bool { - var b strings.Builder - for _, vn := range varName { - if strings.Contains(current, vn) { - fmt.Fprintf(&b, "Unexpected '%s' found in variable name.\n", vn) - } - } - - r := b.String() - if r != "" { - t.Error(r) - return false - } - - return true -} - -func TestVarNames(t *testing.T) { - varNames := vars.NewAlphaVarNames() - - current := "" - for i := 0; i < 100; i++ { - current = varNames.Next() - fmt.Println(current) - } - - if current != "vvvv" { - t.Errorf("Expected \"vvvv\", got: \"%s\"\n", current) - } -} - -func TestVarNamesIgnoreFront(t *testing.T) { - varNames := vars.NewAlphaVarNames(vars.A) - - current := "" - for i := 0; i < 100; i++ { - current = varNames.Next() - fmt.Println(current) - if !checkVarNames(t, current, "a") { - return - } - } - - if current != "zzzz" { - t.Errorf("Expected \"vvvv\", got: \"%s\"\n", current) - } - -} - -func TestVarNamesIgnoreBack(t *testing.T) { - varNames := vars.NewAlphaVarNames(vars.Z) - - current := "" - for i := 0; i < 100; i++ { - current = varNames.Next() - fmt.Println(current) - if !checkVarNames(t, current, "z") { - return - } - } - - if current != "yyyy" { - t.Errorf("Expected \"yyyy\", got: \"%s\"\n", current) - } -} - -func TestVarNamesIgnoreFrontBack(t *testing.T) { - varNames := vars.NewAlphaVarNames(vars.A, vars.Z) - - current := "" - for i := 0; i < 100; i++ { - current = varNames.Next() - fmt.Println(current) - if !checkVarNames(t, current, "a", "z") { - return - } - } -} - -func TestVarNamesIgnoreSequence(t *testing.T) { - ignore := []rune{vars.A, vars.B, vars.C, vars.D} - varNames := vars.NewAlphaVarNames(ignore...) - chars := vars.ToAlphaChars(ignore...) - - current := "" - for i := 0; i < 100; i++ { - current = varNames.Next() - fmt.Println(current) - - if !checkVarNames(t, current, chars...) { - return - } - } -} - -func TestAllBut(t *testing.T) { - ignore := vars.SkipAllBut(vars.I, vars.J, vars.K) - varNames := vars.NewAlphaVarNames(ignore...) - chars := vars.ToAlphaChars(ignore...) - - current := "" - for i := 0; i < 100; i++ { - current = varNames.Next() - fmt.Println(current) - - if !checkVarNames(t, current, chars...) { - return - } - } -} - -func TestVarNamesIgnoreAllButOne(t *testing.T) { - ignore := vars.AllAlphaRunes() - varNames := vars.NewAlphaVarNames(ignore[:len(ignore)-1]...) - - current := "" - for i := 0; i < 10; i++ { - current = varNames.Next() - fmt.Println(current) - } -} - -func TestVarAlphaStrings(t *testing.T) { - for _, r := range vars.AllAlphaRunes() { - fmt.Println(vars.AlphaCharFor(r)) - } -} From f4d066bc25cabf265acdc9b868ecff0848e68841 Mon Sep 17 00:00:00 2001 From: Matt Bolt Date: Fri, 31 Jul 2026 14:34:09 -0400 Subject: [PATCH 2/3] Formatting Updates --- .../java/templates/java/BinDecoder.java.tmpl | 2 + .../java/templates/java/BinEncoder.java.tmpl | 2 + .../templates/java/BingenConsumer.java.tmpl | 2 + .../templates/java/BingenElement.java.tmpl | 2 + .../templates/java/BingenFieldInfo.java.tmpl | 2 + .../templates/java/BingenPullStream.java.tmpl | 2 + .../java/BingenStreamException.java.tmpl | 2 + .../templates/java/BingenStreamFn.java.tmpl | 2 + .../java/templates/java/BingenValue.java.tmpl | 2 + .../templates/java/DecodingContext.java.tmpl | 2 + .../templates/java/EncodingContext.java.tmpl | 2 + .../java/templates/java/GoTime.java.tmpl | 10 ++- .../java/templates/java/ReadBuffer.java.tmpl | 14 ++-- .../java/StringTableReader.java.tmpl | 2 + .../java/StringTableWriter.java.tmpl | 2 + .../java/templates/java/WriteBuffer.java.tmpl | 14 ++-- .../java/templates/java/decoder.java.tmpl | 2 + .../java/templates/java/encoder.java.tmpl | 2 + .../java/templates/java/interface.java.tmpl | 2 + .../templates/java/package-info.java.tmpl | 2 + .../java/templates/java/record.java.tmpl | 2 + .../java/templates/java/registry.java.tmpl | 2 + .../java/templates/java/streamer.java.tmpl | 2 + pkg/util/stringutil/lrubank_test.go | 36 +++++----- .../opencost/java/com/bingen/BinDecoder.java | 2 + .../opencost/java/com/bingen/BinEncoder.java | 2 + .../java/com/bingen/BingenConsumer.java | 2 + .../java/com/bingen/BingenElement.java | 2 + .../java/com/bingen/BingenFieldInfo.java | 6 +- .../java/com/bingen/BingenPullStream.java | 11 ++- .../com/bingen/BingenStreamException.java | 6 +- .../java/com/bingen/BingenStreamFn.java | 2 + .../opencost/java/com/bingen/BingenValue.java | 10 ++- .../java/com/bingen/DecodingContext.java | 18 +++-- .../java/com/bingen/EncodingContext.java | 22 ++++-- tests/opencost/java/com/bingen/GoTime.java | 10 ++- .../opencost/java/com/bingen/ReadBuffer.java | 44 ++++++++---- .../java/com/bingen/StringTableReader.java | 10 ++- .../java/com/bingen/StringTableWriter.java | 10 ++- .../opencost/java/com/bingen/WriteBuffer.java | 71 +++++++++++++++---- .../com/opencost/opencost/Allocation.java | 10 ++- .../opencost/opencost/AllocationDecoder.java | 10 ++- .../opencost/opencost/AllocationEncoder.java | 6 +- .../opencost/AllocationProperties.java | 10 ++- .../opencost/AllocationPropertiesDecoder.java | 10 ++- .../opencost/AllocationPropertiesEncoder.java | 6 +- .../com/opencost/opencost/AllocationSet.java | 10 ++- .../opencost/AllocationSetDecoder.java | 10 ++- .../opencost/AllocationSetEncoder.java | 6 +- .../opencost/opencost/AllocationSetRange.java | 10 ++- .../opencost/AllocationSetRangeDecoder.java | 10 ++- .../opencost/AllocationSetRangeEncoder.java | 6 +- .../opencost/AllocationSetStreamer.java | 6 +- .../java/com/opencost/opencost/Any.java | 10 ++- .../com/opencost/opencost/AnyDecoder.java | 10 ++- .../com/opencost/opencost/AnyEncoder.java | 6 +- .../java/com/opencost/opencost/Asset.java | 2 + .../opencost/opencost/AssetProperties.java | 10 ++- .../opencost/AssetPropertiesDecoder.java | 10 ++- .../opencost/AssetPropertiesEncoder.java | 6 +- .../java/com/opencost/opencost/AssetSet.java | 10 ++- .../opencost/opencost/AssetSetDecoder.java | 10 ++- .../opencost/opencost/AssetSetEncoder.java | 6 +- .../com/opencost/opencost/AssetSetRange.java | 10 ++- .../opencost/AssetSetRangeDecoder.java | 10 ++- .../opencost/AssetSetRangeEncoder.java | 6 +- .../opencost/opencost/AssetSetStreamer.java | 6 +- .../java/com/opencost/opencost/Breakdown.java | 10 ++- .../opencost/opencost/BreakdownDecoder.java | 10 ++- .../opencost/opencost/BreakdownEncoder.java | 6 +- .../java/com/opencost/opencost/Cloud.java | 10 ++- .../com/opencost/opencost/CloudDecoder.java | 10 ++- .../com/opencost/opencost/CloudEncoder.java | 6 +- .../opencost/opencost/ClusterManagement.java | 10 ++- .../opencost/ClusterManagementDecoder.java | 10 ++- .../opencost/ClusterManagementEncoder.java | 6 +- .../java/com/opencost/opencost/Disk.java | 10 ++- .../com/opencost/opencost/DiskDecoder.java | 10 ++- .../com/opencost/opencost/DiskEncoder.java | 6 +- .../com/opencost/opencost/LoadBalancer.java | 10 ++- .../opencost/LoadBalancerDecoder.java | 10 ++- .../opencost/LoadBalancerEncoder.java | 6 +- .../java/com/opencost/opencost/Network.java | 10 ++- .../com/opencost/opencost/NetworkDecoder.java | 10 ++- .../com/opencost/opencost/NetworkEncoder.java | 6 +- .../java/com/opencost/opencost/Node.java | 10 ++- .../com/opencost/opencost/NodeDecoder.java | 10 ++- .../com/opencost/opencost/NodeEncoder.java | 6 +- .../com/opencost/opencost/PVAllocation.java | 10 ++- .../opencost/PVAllocationDecoder.java | 10 ++- .../opencost/PVAllocationEncoder.java | 6 +- .../java/com/opencost/opencost/PVKey.java | 10 ++- .../com/opencost/opencost/PVKeyDecoder.java | 10 ++- .../com/opencost/opencost/PVKeyEncoder.java | 6 +- .../opencost/RawAllocationOnlyData.java | 10 ++- .../RawAllocationOnlyDataDecoder.java | 10 ++- .../RawAllocationOnlyDataEncoder.java | 6 +- .../com/opencost/opencost/SharedAsset.java | 10 ++- .../opencost/opencost/SharedAssetDecoder.java | 10 ++- .../opencost/opencost/SharedAssetEncoder.java | 6 +- .../com/opencost/opencost/TypeRegistry.java | 10 ++- .../java/com/opencost/opencost/Window.java | 10 ++- .../com/opencost/opencost/WindowDecoder.java | 10 ++- .../com/opencost/opencost/WindowEncoder.java | 6 +- .../com/opencost/opencost/package-info.java | 2 + 105 files changed, 704 insertions(+), 184 deletions(-) diff --git a/internal/generator/java/templates/java/BinDecoder.java.tmpl b/internal/generator/java/templates/java/BinDecoder.java.tmpl index 4ee1014..746670f 100644 --- a/internal/generator/java/templates/java/BinDecoder.java.tmpl +++ b/internal/generator/java/templates/java/BinDecoder.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BinEncoder.java.tmpl b/internal/generator/java/templates/java/BinEncoder.java.tmpl index 44e5193..0c43183 100644 --- a/internal/generator/java/templates/java/BinEncoder.java.tmpl +++ b/internal/generator/java/templates/java/BinEncoder.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenConsumer.java.tmpl b/internal/generator/java/templates/java/BingenConsumer.java.tmpl index 435d614..d61e6ab 100644 --- a/internal/generator/java/templates/java/BingenConsumer.java.tmpl +++ b/internal/generator/java/templates/java/BingenConsumer.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenElement.java.tmpl b/internal/generator/java/templates/java/BingenElement.java.tmpl index cea955a..59cc9d5 100644 --- a/internal/generator/java/templates/java/BingenElement.java.tmpl +++ b/internal/generator/java/templates/java/BingenElement.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl b/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl index 391e6aa..1823529 100644 --- a/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl +++ b/internal/generator/java/templates/java/BingenFieldInfo.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenPullStream.java.tmpl b/internal/generator/java/templates/java/BingenPullStream.java.tmpl index 1113325..e8dac0b 100644 --- a/internal/generator/java/templates/java/BingenPullStream.java.tmpl +++ b/internal/generator/java/templates/java/BingenPullStream.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenStreamException.java.tmpl b/internal/generator/java/templates/java/BingenStreamException.java.tmpl index bed8f94..8108c29 100644 --- a/internal/generator/java/templates/java/BingenStreamException.java.tmpl +++ b/internal/generator/java/templates/java/BingenStreamException.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenStreamFn.java.tmpl b/internal/generator/java/templates/java/BingenStreamFn.java.tmpl index d534ce9..9046503 100644 --- a/internal/generator/java/templates/java/BingenStreamFn.java.tmpl +++ b/internal/generator/java/templates/java/BingenStreamFn.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/BingenValue.java.tmpl b/internal/generator/java/templates/java/BingenValue.java.tmpl index 44e5841..6ae157f 100644 --- a/internal/generator/java/templates/java/BingenValue.java.tmpl +++ b/internal/generator/java/templates/java/BingenValue.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/DecodingContext.java.tmpl b/internal/generator/java/templates/java/DecodingContext.java.tmpl index 7e2e794..89f6c78 100644 --- a/internal/generator/java/templates/java/DecodingContext.java.tmpl +++ b/internal/generator/java/templates/java/DecodingContext.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/EncodingContext.java.tmpl b/internal/generator/java/templates/java/EncodingContext.java.tmpl index eb65c67..d614e94 100644 --- a/internal/generator/java/templates/java/EncodingContext.java.tmpl +++ b/internal/generator/java/templates/java/EncodingContext.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/GoTime.java.tmpl b/internal/generator/java/templates/java/GoTime.java.tmpl index 044e5e0..b252f0d 100644 --- a/internal/generator/java/templates/java/GoTime.java.tmpl +++ b/internal/generator/java/templates/java/GoTime.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -30,14 +32,18 @@ public final class GoTime { private GoTime() { } - /** Writes the length-prefixed go time payload. */ + /** + * Writes the length-prefixed go time payload. + */ public static void encode(OffsetDateTime t, WriteBuffer buff) { byte[] payload = marshal(t); buff.writeInt(payload.length); buff.writeBytes(payload); } - /** Reads a length-prefixed go time payload. */ + /** + * Reads a length-prefixed go time payload. + */ public static OffsetDateTime decode(ReadBuffer buff) { int len = buff.readInt(); return unmarshal(buff.readBytes(len)); diff --git a/internal/generator/java/templates/java/ReadBuffer.java.tmpl b/internal/generator/java/templates/java/ReadBuffer.java.tmpl index dcaa784..dc60988 100644 --- a/internal/generator/java/templates/java/ReadBuffer.java.tmpl +++ b/internal/generator/java/templates/java/ReadBuffer.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -57,9 +59,9 @@ public final class ReadBuffer { return fromBytes(wb.bytes()); } - // ------------------------------------------------------------------------- - // Read API - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Read API + //-------------------------------------------------------------------------- public boolean readBool() { return readRawByte() != 0; @@ -212,9 +214,9 @@ public final class ReadBuffer { } } - // ------------------------------------------------------------------------- - // Internal helpers - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- private byte readRawByte() { int b; diff --git a/internal/generator/java/templates/java/StringTableReader.java.tmpl b/internal/generator/java/templates/java/StringTableReader.java.tmpl index df3b89f..d778991 100644 --- a/internal/generator/java/templates/java/StringTableReader.java.tmpl +++ b/internal/generator/java/templates/java/StringTableReader.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/StringTableWriter.java.tmpl b/internal/generator/java/templates/java/StringTableWriter.java.tmpl index e199f1e..99e5204 100644 --- a/internal/generator/java/templates/java/StringTableWriter.java.tmpl +++ b/internal/generator/java/templates/java/StringTableWriter.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/WriteBuffer.java.tmpl b/internal/generator/java/templates/java/WriteBuffer.java.tmpl index e5c7327..dcb2ff4 100644 --- a/internal/generator/java/templates/java/WriteBuffer.java.tmpl +++ b/internal/generator/java/templates/java/WriteBuffer.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -32,9 +34,9 @@ public final class WriteBuffer { return new WriteBuffer(); } - // ------------------------------------------------------------------------- - // Write API - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Write API + //-------------------------------------------------------------------------- /** * Writes a boolean as a single byte (0 or 1). @@ -156,9 +158,9 @@ public final class WriteBuffer { bos.write(bytes, 0, bytes.length); } - // ------------------------------------------------------------------------- - // Utility - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Utility + //-------------------------------------------------------------------------- /** * Returns a copy of all bytes written so far. diff --git a/internal/generator/java/templates/java/decoder.java.tmpl b/internal/generator/java/templates/java/decoder.java.tmpl index c9523e0..30fa407 100644 --- a/internal/generator/java/templates/java/decoder.java.tmpl +++ b/internal/generator/java/templates/java/decoder.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/encoder.java.tmpl b/internal/generator/java/templates/java/encoder.java.tmpl index e476a13..7b766b0 100644 --- a/internal/generator/java/templates/java/encoder.java.tmpl +++ b/internal/generator/java/templates/java/encoder.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/interface.java.tmpl b/internal/generator/java/templates/java/interface.java.tmpl index df99d8f..4e8524f 100644 --- a/internal/generator/java/templates/java/interface.java.tmpl +++ b/internal/generator/java/templates/java/interface.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/package-info.java.tmpl b/internal/generator/java/templates/java/package-info.java.tmpl index 11f3b47..75bb610 100644 --- a/internal/generator/java/templates/java/package-info.java.tmpl +++ b/internal/generator/java/templates/java/package-info.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/record.java.tmpl b/internal/generator/java/templates/java/record.java.tmpl index e7fc558..ddeb9c5 100644 --- a/internal/generator/java/templates/java/record.java.tmpl +++ b/internal/generator/java/templates/java/record.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/registry.java.tmpl b/internal/generator/java/templates/java/registry.java.tmpl index 6c92a0e..dd3d24a 100644 --- a/internal/generator/java/templates/java/registry.java.tmpl +++ b/internal/generator/java/templates/java/registry.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/internal/generator/java/templates/java/streamer.java.tmpl b/internal/generator/java/templates/java/streamer.java.tmpl index 07f4863..20dd2ed 100644 --- a/internal/generator/java/templates/java/streamer.java.tmpl +++ b/internal/generator/java/templates/java/streamer.java.tmpl @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/pkg/util/stringutil/lrubank_test.go b/pkg/util/stringutil/lrubank_test.go index 66b8273..d9fd70b 100644 --- a/pkg/util/stringutil/lrubank_test.go +++ b/pkg/util/stringutil/lrubank_test.go @@ -38,9 +38,9 @@ func TestBasicLruEvict(t *testing.T) { lruBank.lock.Unlock() } -// --------------------------------------------------------------------------- -// LoadOrStore -// --------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// Load and Store +//-------------------------------------------------------------------------- // A stored value must be retrievable and LoadOrStore must signal the hit/miss // correctly via the boolean return. @@ -98,9 +98,9 @@ func TestLoadOrStore_HitUpdateRecency(t *testing.T) { } } -// --------------------------------------------------------------------------- -// LoadOrStoreFunc -// --------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// LoadOrStoreFunc +//-------------------------------------------------------------------------- // The factory function must only be called on a cache miss, not on a hit. func TestLoadOrStoreFunc_FactoryCalledOnMissOnly(t *testing.T) { @@ -121,9 +121,9 @@ func TestLoadOrStoreFunc_FactoryCalledOnMissOnly(t *testing.T) { } } -// --------------------------------------------------------------------------- -// Capacity / eviction -// --------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// Capacity/Eviction +//-------------------------------------------------------------------------- // If the bank never exceeds capacity, nothing should be evicted. func TestEviction_BelowCapacityNoEviction(t *testing.T) { @@ -196,9 +196,9 @@ func TestEviction_MRUSurvives(t *testing.T) { } } -// --------------------------------------------------------------------------- -// Clear -// --------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// Clear +//-------------------------------------------------------------------------- func TestClear_EmptiesMap(t *testing.T) { bank := NewLruStringBank(10, time.Minute).(*lruStringBank) @@ -232,9 +232,9 @@ func TestClear_PreviousKeysGone(t *testing.T) { } } -// --------------------------------------------------------------------------- -// nOldest helper -// --------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// n-Oldest Helper +//-------------------------------------------------------------------------- func TestNOldest_ReturnsCorrectCount(t *testing.T) { now := time.Now() @@ -300,9 +300,9 @@ func TestNOldest_NIsZero(t *testing.T) { } } -// --------------------------------------------------------------------------- -// Concurrency -// --------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// Concurrency +//-------------------------------------------------------------------------- // Concurrent LoadOrStore calls must not race or panic. func TestConcurrentLoadOrStore(t *testing.T) { diff --git a/tests/opencost/java/com/bingen/BinDecoder.java b/tests/opencost/java/com/bingen/BinDecoder.java index 44337a3..4497a06 100644 --- a/tests/opencost/java/com/bingen/BinDecoder.java +++ b/tests/opencost/java/com/bingen/BinDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/opencost/java/com/bingen/BinEncoder.java b/tests/opencost/java/com/bingen/BinEncoder.java index 468d28b..2d270ad 100644 --- a/tests/opencost/java/com/bingen/BinEncoder.java +++ b/tests/opencost/java/com/bingen/BinEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/opencost/java/com/bingen/BingenConsumer.java b/tests/opencost/java/com/bingen/BingenConsumer.java index 169532e..1fe9648 100644 --- a/tests/opencost/java/com/bingen/BingenConsumer.java +++ b/tests/opencost/java/com/bingen/BingenConsumer.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/opencost/java/com/bingen/BingenElement.java b/tests/opencost/java/com/bingen/BingenElement.java index d4f8f8d..681aed1 100644 --- a/tests/opencost/java/com/bingen/BingenElement.java +++ b/tests/opencost/java/com/bingen/BingenElement.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/opencost/java/com/bingen/BingenFieldInfo.java b/tests/opencost/java/com/bingen/BingenFieldInfo.java index 4d2462a..5711ead 100644 --- a/tests/opencost/java/com/bingen/BingenFieldInfo.java +++ b/tests/opencost/java/com/bingen/BingenFieldInfo.java @@ -2,12 +2,16 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// package com.bingen; -/** Describes the struct field currently being streamed. */ +/** + * Describes the struct field currently being streamed. + */ public record BingenFieldInfo(String name) { } diff --git a/tests/opencost/java/com/bingen/BingenPullStream.java b/tests/opencost/java/com/bingen/BingenPullStream.java index 6f601ba..b906bc8 100644 --- a/tests/opencost/java/com/bingen/BingenPullStream.java +++ b/tests/opencost/java/com/bingen/BingenPullStream.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -42,7 +44,9 @@ private BingenPullStream(InputStream in, BingenStreamFn fn) { this.producer = Thread.ofVirtual().name("bingen-pull-stream").start(() -> run(in, fn)); } - /** Creates a pull stream driving the push streamer over an in-memory payload. */ + /** + * Creates a pull stream driving the push streamer over an in-memory payload. + */ public static BingenPullStream of(byte[] data, BingenStreamFn fn) { return new BingenPullStream(new ByteArrayInputStream(data), fn); } @@ -133,10 +137,13 @@ public BingenElement next() { }; } - /** A sequential {@link Stream}; closing it closes this pull stream. */ + /** + * A sequential {@link Stream}; closing it closes this pull stream. + */ public Stream stream() { Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED); + return StreamSupport.stream(spliterator, false).onClose(this::close); } diff --git a/tests/opencost/java/com/bingen/BingenStreamException.java b/tests/opencost/java/com/bingen/BingenStreamException.java index 6155266..227e67b 100644 --- a/tests/opencost/java/com/bingen/BingenStreamException.java +++ b/tests/opencost/java/com/bingen/BingenStreamException.java @@ -2,13 +2,17 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// package com.bingen; -/** Wraps an error thrown by the underlying push streamer during pull iteration. */ +/** + * Wraps an error thrown by the underlying push streamer during pull iteration. + */ public final class BingenStreamException extends RuntimeException { public BingenStreamException(Throwable cause) { super(cause); diff --git a/tests/opencost/java/com/bingen/BingenStreamFn.java b/tests/opencost/java/com/bingen/BingenStreamFn.java index 4438ef2..853a67d 100644 --- a/tests/opencost/java/com/bingen/BingenStreamFn.java +++ b/tests/opencost/java/com/bingen/BingenStreamFn.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/opencost/java/com/bingen/BingenValue.java b/tests/opencost/java/com/bingen/BingenValue.java index 955ebad..b76b58c 100644 --- a/tests/opencost/java/com/bingen/BingenValue.java +++ b/tests/opencost/java/com/bingen/BingenValue.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -14,12 +16,16 @@ */ public record BingenValue(Object value, Object index) { - /** A single value with no index or key. */ + /** + * A single value with no index or key. + */ public static BingenValue single(Object value) { return new BingenValue(value, null); } - /** One element of a flattened slice or map, with its index or key. */ + /** + * One element of a flattened slice or map, with its index or key. + */ public static BingenValue pair(Object index, Object value) { return new BingenValue(value, index); } diff --git a/tests/opencost/java/com/bingen/DecodingContext.java b/tests/opencost/java/com/bingen/DecodingContext.java index 67b8e6d..14cdd2d 100644 --- a/tests/opencost/java/com/bingen/DecodingContext.java +++ b/tests/opencost/java/com/bingen/DecodingContext.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,7 +28,9 @@ private DecodingContext(ReadBuffer buffer, StringTableReader table) { this.table = table; } - /** Creates a context over an in-memory payload. */ + /** + * Creates a context over an in-memory payload. + */ public static DecodingContext fromBytes(byte[] data) { return from(ReadBuffer.fromBytes(data)); } @@ -50,17 +54,23 @@ private static DecodingContext from(ReadBuffer buffer) { return new DecodingContext(buffer, table); } - /** The read buffer the decoders consume from. */ + /** + * The read buffer the decoders consume from. + */ public ReadBuffer buffer() { return buffer; } - /** The string table, or null when string-table decoding is inactive. */ + /** + * The string table, or null when string-table decoding is inactive. + */ public StringTableReader table() { return table; } - /** Whether string-table decoding is active. */ + /** + * Whether string-table decoding is active. + */ public boolean isStringTable() { return table != null && table.len() > 0; } diff --git a/tests/opencost/java/com/bingen/EncodingContext.java b/tests/opencost/java/com/bingen/EncodingContext.java index 62e8941..c3a0504 100644 --- a/tests/opencost/java/com/bingen/EncodingContext.java +++ b/tests/opencost/java/com/bingen/EncodingContext.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,27 +24,37 @@ private EncodingContext(WriteBuffer buffer, StringTableWriter table) { this.table = table; } - /** Creates a context backed by a fresh write buffer with no string table. */ + /** + * Creates a context backed by a fresh write buffer with no string table. + */ public static EncodingContext create() { return new EncodingContext(WriteBuffer.create(), null); } - /** Creates a context whose string fields are indexed into a string table. */ + /** + * Creates a context whose string fields are indexed into a string table. + */ public static EncodingContext withStringTable() { return new EncodingContext(WriteBuffer.create(), new StringTableWriter()); } - /** The write buffer the encoders emit into. */ + /** + * The write buffer the encoders emit into. + */ public WriteBuffer buffer() { return buffer; } - /** The string table, or null when string-table encoding is inactive. */ + /** + * The string table, or null when string-table encoding is inactive. + */ public StringTableWriter table() { return table; } - /** Whether string-table encoding is active. */ + /** + * Whether string-table encoding is active. + */ public boolean isStringTable() { return table != null; } diff --git a/tests/opencost/java/com/bingen/GoTime.java b/tests/opencost/java/com/bingen/GoTime.java index 72a6c41..e90962b 100644 --- a/tests/opencost/java/com/bingen/GoTime.java +++ b/tests/opencost/java/com/bingen/GoTime.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -30,14 +32,18 @@ public final class GoTime { private GoTime() { } - /** Writes the length-prefixed go time payload. */ + /** + * Writes the length-prefixed go time payload. + */ public static void encode(OffsetDateTime t, WriteBuffer buff) { byte[] payload = marshal(t); buff.writeInt(payload.length); buff.writeBytes(payload); } - /** Reads a length-prefixed go time payload. */ + /** + * Reads a length-prefixed go time payload. + */ public static OffsetDateTime decode(ReadBuffer buff) { int len = buff.readInt(); return unmarshal(buff.readBytes(len)); diff --git a/tests/opencost/java/com/bingen/ReadBuffer.java b/tests/opencost/java/com/bingen/ReadBuffer.java index 9ad2660..00c3a9e 100644 --- a/tests/opencost/java/com/bingen/ReadBuffer.java +++ b/tests/opencost/java/com/bingen/ReadBuffer.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -57,9 +59,9 @@ public static ReadBuffer from(WriteBuffer wb) { return fromBytes(wb.bytes()); } - // ------------------------------------------------------------------------- - // Read API - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Read API + //-------------------------------------------------------------------------- public boolean readBool() { return readRawByte() != 0; @@ -107,35 +109,51 @@ public long readInt64() { | ((b7 & 0xFFL) << 56); } - /** Reads a 32-bit unsigned value, returned as a long. */ + /** + * Reads a 32-bit unsigned value, returned as a long. + */ public long readUInt() { return readInt32() & 0xFFFFFFFFL; } - /** Reads an 8-bit unsigned value (0–255), returned as int. */ + /** + * Reads an 8-bit unsigned value (0–255), returned as int. + */ public int readUInt8() { return readRawByte() & 0xFF; } - /** Reads a 16-bit unsigned value (0–65535), returned as int. */ + /** + * Reads a 16-bit unsigned value (0–65535), returned as int. + */ public int readUInt16() { return readInt16() & 0xFFFF; } - /** Reads a 32-bit unsigned value (0–4294967295), returned as long. */ + /** + * Reads a 32-bit unsigned value (0–4294967295), returned as long. + */ public long readUInt32() { return readInt32() & 0xFFFFFFFFL; } - /** Reads a 64-bit unsigned value (same bit pattern as signed long). */ + /** + * Reads a 64-bit unsigned value (same bit pattern as signed long). + */ public long readUInt64() { return readInt64(); } + /** + * Reads a 32-bit floating point value (IEEE 754). + */ public float readFloat32() { return Float.intBitsToFloat(readInt32()); } + /** + * Reads a 64-bit floating point value (IEEE 754). + */ public double readFloat64() { return Double.longBitsToDouble(readInt64()); } @@ -150,7 +168,9 @@ public String readString() { return new String(strBytes, StandardCharsets.UTF_8); } - /** Reads exactly {@code length} bytes from the buffer. */ + /** + * Reads exactly {@code length} bytes from the buffer. + */ public byte[] readBytes(int length) { byte[] result = new byte[length]; int remaining = length; @@ -194,9 +214,9 @@ public boolean startsWith(byte[] tag) { } } - // ------------------------------------------------------------------------- - // Internal helpers - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- private byte readRawByte() { int b; diff --git a/tests/opencost/java/com/bingen/StringTableReader.java b/tests/opencost/java/com/bingen/StringTableReader.java index c5326ff..8a62f30 100644 --- a/tests/opencost/java/com/bingen/StringTableReader.java +++ b/tests/opencost/java/com/bingen/StringTableReader.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -33,12 +35,16 @@ public static StringTableReader from(ReadBuffer buff) { return new StringTableReader(table); } - /** Returns the string at {@code index}. */ + /** + * Returns the string at {@code index}. + */ public String at(int index) { return table[index]; } - /** Returns the number of strings in the table. */ + /** + * Returns the number of strings in the table. + */ public int len() { return table.length; } diff --git a/tests/opencost/java/com/bingen/StringTableWriter.java b/tests/opencost/java/com/bingen/StringTableWriter.java index 1d77d93..cb37230 100644 --- a/tests/opencost/java/com/bingen/StringTableWriter.java +++ b/tests/opencost/java/com/bingen/StringTableWriter.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,7 +24,9 @@ public final class StringTableWriter { private final Map indices = new LinkedHashMap<>(); private int next = 0; - /** Returns the existing index for {@code s}, or assigns and returns a new one. */ + /** + * Returns the existing index for {@code s}, or assigns and returns a new one. + */ public int addOrGet(String s) { Integer existing = indices.get(s); if (existing != null) { @@ -33,7 +37,9 @@ public int addOrGet(String s) { return current; } - /** Writes the tag, the string count, and each string in index order. */ + /** + * Writes the tag, the string count, and each string in index order. + */ public void writeTo(WriteBuffer buff) { buff.writeBytes(TAG); diff --git a/tests/opencost/java/com/bingen/WriteBuffer.java b/tests/opencost/java/com/bingen/WriteBuffer.java index ce727a5..554c767 100644 --- a/tests/opencost/java/com/bingen/WriteBuffer.java +++ b/tests/opencost/java/com/bingen/WriteBuffer.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,33 +27,49 @@ private WriteBuffer() { this.bos = new ByteArrayOutputStream(64); } - /** Creates a new empty write buffer. */ + /** + * Creates a new empty write buffer. + */ public static WriteBuffer create() { return new WriteBuffer(); } - // ------------------------------------------------------------------------- - // Write API - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Write API + //-------------------------------------------------------------------------- + /** + * Writes a boolean as a single byte (0 or 1). + */ public void writeBool(boolean v) { bos.write(v ? 1 : 0); } - /** Writes a 32-bit signed integer (same as writeInt32). */ + /** + * Writes a 32-bit signed integer (same as writeInt32). + */ public void writeInt(int v) { writeInt32(v); } + /** + * Writes a single byte + */ public void writeInt8(byte v) { bos.write(v); } + /** + * Writes a 16-bit signed integer + */ public void writeInt16(short v) { bos.write(v & 0xFF); bos.write((v >>> 8) & 0xFF); } + /** + * Writes a 32-bit signed integer + */ public void writeInt32(int v) { bos.write(v & 0xFF); bos.write((v >>> 8) & 0xFF); @@ -59,6 +77,9 @@ public void writeInt32(int v) { bos.write((v >>> 24) & 0xFF); } + /** + * Writes a 64-bit signed integer + */ public void writeInt64(long v) { bos.write((int) (v & 0xFF)); bos.write((int) ((v >>> 8) & 0xFF)); @@ -70,35 +91,51 @@ public void writeInt64(long v) { bos.write((int) ((v >>> 56) & 0xFF)); } - /** Writes a 32-bit unsigned value (accepts long to cover full 0–4294967295 range). */ + /** + * Writes a 32-bit unsigned value (accepts long to cover full 0–4294967295 range). + */ public void writeUInt(long v) { writeInt32((int) (v & 0xFFFFFFFFL)); } - /** Writes an 8-bit unsigned value (0–255). */ + /** + * Writes an 8-bit unsigned value (0–255). + */ public void writeUInt8(int v) { bos.write(v); } - /** Writes a 16-bit unsigned value (0–65535). */ + /** + * Writes a 16-bit unsigned value (0–65535). + */ public void writeUInt16(int v) { writeInt16((short) (v & 0xFFFF)); } - /** Writes a 32-bit unsigned value. */ + /** + * Writes a 32-bit unsigned value. + */ public void writeUInt32(long v) { writeInt32((int) (v & 0xFFFFFFFFL)); } - /** Writes a 64-bit unsigned value (same bit pattern as signed long). */ + /** + * Writes a 64-bit unsigned value (same bit pattern as signed long). + */ public void writeUInt64(long v) { writeInt64(v); } + /** + * Writes a 32-bit float. + */ public void writeFloat32(float v) { writeInt32(Float.floatToRawIntBits(v)); } + /** + * Writes a 64-bit float. + */ public void writeFloat64(double v) { writeInt64(Double.doubleToRawLongBits(v)); } @@ -114,16 +151,20 @@ public void writeString(String s) { bos.write(strBytes, 0, len); } - /** Writes the raw byte array contents into the buffer. */ + /** + * Writes the raw byte array contents into the buffer. + */ public void writeBytes(byte[] bytes) { bos.write(bytes, 0, bytes.length); } - // ------------------------------------------------------------------------- - // Utility - // ------------------------------------------------------------------------- + //-------------------------------------------------------------------------- + // Utility + //-------------------------------------------------------------------------- - /** Returns a copy of all bytes written so far. */ + /** + * Returns a copy of all bytes written so far. + */ public byte[] bytes() { return bos.toByteArray(); } diff --git a/tests/opencost/java/com/opencost/opencost/Allocation.java b/tests/opencost/java/com/opencost/opencost/Allocation.java index 381dcd5..53fe884 100644 --- a/tests/opencost/java/com/opencost/opencost/Allocation.java +++ b/tests/opencost/java/com/opencost/opencost/Allocation.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record Allocation(String name, AllocationProperties properties, Window window, OffsetDateTime start, OffsetDateTime end, double cPUCoreHours, double cPUCoreRequestAverage, double cPUCoreUsageAverage, double cPUCost, double cPUCostAdjustment, double gPUHours, double gPUCost, double gPUCostAdjustment, double networkTransferBytes, double networkReceiveBytes, double networkCost, double networkCostAdjustment, double loadBalancerCost, double loadBalancerCostAdjustment, Map pVs, double pVCostAdjustment, double rAMByteHours, double rAMBytesRequestAverage, double rAMBytesUsageAverage, double rAMCost, double rAMCostAdjustment, double sharedCost, double externalCost, RawAllocationOnlyData rawAllocationOnly, int testProperty, String testStr) { - /** Creates a new builder for {@link Allocation}. */ + /** + * Creates a new builder for {@link Allocation}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private String name; private AllocationProperties properties; diff --git a/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java index d03cd7d..e3cf0d8 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class AllocationDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Allocation} from a standalone byte array. */ + /** + * Decodes a {@link Allocation} from a standalone byte array. + */ public static Allocation fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Allocation} read incrementally from a stream. */ + /** + * Decodes a {@link Allocation} read incrementally from a stream. + */ public static Allocation fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java b/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java index 78715d4..50bf734 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class AllocationEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Allocation value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/AllocationProperties.java b/tests/opencost/java/com/opencost/opencost/AllocationProperties.java index 23bf9d7..a650456 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationProperties.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationProperties.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record AllocationProperties(String cluster, String node, String container, String controller, String controllerKind, String namespace, String pod, List services, String providerID, Map labels, Map annotations) { - /** Creates a new builder for {@link AllocationProperties}. */ + /** + * Creates a new builder for {@link AllocationProperties}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private String cluster; private String node; diff --git a/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java index 1c6a135..a73cdb6 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationPropertiesDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class AllocationPropertiesDecoder implements BinDecoder allocations, Map externalKeys, Map idleKeys, String fromSource, Window window, List warnings, List errors) { - /** Creates a new builder for {@link AllocationSet}. */ + /** + * Creates a new builder for {@link AllocationSet}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private Map allocations; private Map externalKeys; diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java index beaaa1a..43ee63c 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class AllocationSetDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link AllocationSet} from a standalone byte array. */ + /** + * Decodes a {@link AllocationSet} from a standalone byte array. + */ public static AllocationSet fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link AllocationSet} read incrementally from a stream. */ + /** + * Decodes a {@link AllocationSet} read incrementally from a stream. + */ public static AllocationSet fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java index e1060b0..05ff0fe 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -23,7 +25,9 @@ public final class AllocationSetEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = true; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(AllocationSet value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java b/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java index c5f94b4..2764f9d 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetRange.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -15,12 +17,16 @@ */ public record AllocationSetRange(List allocations, String fromStore) { - /** Creates a new builder for {@link AllocationSetRange}. */ + /** + * Creates a new builder for {@link AllocationSetRange}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private List allocations; private String fromStore; diff --git a/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java b/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java index b0c2b5d..e415ea1 100644 --- a/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AllocationSetRangeDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -24,12 +26,16 @@ public final class AllocationSetRangeDecoder implements BinDecoder labels, AssetProperties properties, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost) implements Asset { - /** Creates a new builder for {@link Any}. */ + /** + * Creates a new builder for {@link Any}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private Map labels; private AssetProperties properties; diff --git a/tests/opencost/java/com/opencost/opencost/AnyDecoder.java b/tests/opencost/java/com/opencost/opencost/AnyDecoder.java index fb8bba0..5574972 100644 --- a/tests/opencost/java/com/opencost/opencost/AnyDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AnyDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class AnyDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Any} from a standalone byte array. */ + /** + * Decodes a {@link Any} from a standalone byte array. + */ public static Any fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Any} read incrementally from a stream. */ + /** + * Decodes a {@link Any} read incrementally from a stream. + */ public static Any fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/AnyEncoder.java b/tests/opencost/java/com/opencost/opencost/AnyEncoder.java index ef5b0e4..683601f 100644 --- a/tests/opencost/java/com/opencost/opencost/AnyEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/AnyEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class AnyEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Any value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/Asset.java b/tests/opencost/java/com/opencost/opencost/Asset.java index 9f0ee8b..d84c996 100644 --- a/tests/opencost/java/com/opencost/opencost/Asset.java +++ b/tests/opencost/java/com/opencost/opencost/Asset.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/opencost/java/com/opencost/opencost/AssetProperties.java b/tests/opencost/java/com/opencost/opencost/AssetProperties.java index 6e380d5..93211eb 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetProperties.java +++ b/tests/opencost/java/com/opencost/opencost/AssetProperties.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -14,12 +16,16 @@ */ public record AssetProperties(String category, String provider, String account, String project, String service, String cluster, String name, String providerID) { - /** Creates a new builder for {@link AssetProperties}. */ + /** + * Creates a new builder for {@link AssetProperties}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private String category; private String provider; diff --git a/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java b/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java index 2dca273..e8c967e 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AssetPropertiesDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,12 +24,16 @@ public final class AssetPropertiesDecoder implements BinDecoder private static final int VERSION = 16; - /** Decodes a {@link AssetProperties} from a standalone byte array. */ + /** + * Decodes a {@link AssetProperties} from a standalone byte array. + */ public static AssetProperties fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link AssetProperties} read incrementally from a stream. */ + /** + * Decodes a {@link AssetProperties} read incrementally from a stream. + */ public static AssetProperties fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java b/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java index aa74228..0568674 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/AssetPropertiesEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,7 +24,9 @@ public final class AssetPropertiesEncoder implements BinEncoder private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(AssetProperties value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/AssetSet.java b/tests/opencost/java/com/opencost/opencost/AssetSet.java index 3033f57..40c4b04 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSet.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSet.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record AssetSet(List aggregateBy, Map assets, String fromSource, Window window, List warnings, List errors) { - /** Creates a new builder for {@link AssetSet}. */ + /** + * Creates a new builder for {@link AssetSet}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private List aggregateBy; private Map assets; diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java index 5953a3c..38af03c 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSetDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class AssetSetDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link AssetSet} from a standalone byte array. */ + /** + * Decodes a {@link AssetSet} from a standalone byte array. + */ public static AssetSet fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link AssetSet} read incrementally from a stream. */ + /** + * Decodes a {@link AssetSet} read incrementally from a stream. + */ public static AssetSet fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java index ca2650f..89fcc5e 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSetEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -23,7 +25,9 @@ public final class AssetSetEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = true; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(AssetSet value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetRange.java b/tests/opencost/java/com/opencost/opencost/AssetSetRange.java index 69e39b8..7dd0586 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSetRange.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSetRange.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -15,12 +17,16 @@ */ public record AssetSetRange(List assets, String fromStore) { - /** Creates a new builder for {@link AssetSetRange}. */ + /** + * Creates a new builder for {@link AssetSetRange}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private List assets; private String fromStore; diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java index b9b7fc4..36ec944 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSetRangeDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -24,12 +26,16 @@ public final class AssetSetRangeDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link AssetSetRange} from a standalone byte array. */ + /** + * Decodes a {@link AssetSetRange} from a standalone byte array. + */ public static AssetSetRange fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link AssetSetRange} read incrementally from a stream. */ + /** + * Decodes a {@link AssetSetRange} read incrementally from a stream. + */ public static AssetSetRange fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java b/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java index 8ccd9a3..23eb52c 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSetRangeEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,7 +24,9 @@ public final class AssetSetRangeEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(AssetSetRange value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java b/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java index 8d4d08d..fe8d2db 100644 --- a/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java +++ b/tests/opencost/java/com/opencost/opencost/AssetSetStreamer.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -28,7 +30,9 @@ public final class AssetSetStreamer { private AssetSetStreamer() { } - /** Streams the fields of an encoded {@link AssetSet} held in memory. */ + /** + * Streams the fields of an encoded {@link AssetSet} held in memory. + */ public static void stream(byte[] data, BingenConsumer consumer) { stream(new ByteArrayInputStream(data), consumer); } diff --git a/tests/opencost/java/com/opencost/opencost/Breakdown.java b/tests/opencost/java/com/opencost/opencost/Breakdown.java index 4f56fd9..b08f20c 100644 --- a/tests/opencost/java/com/opencost/opencost/Breakdown.java +++ b/tests/opencost/java/com/opencost/opencost/Breakdown.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -14,12 +16,16 @@ */ public record Breakdown(double idle, double other, double system, double user) { - /** Creates a new builder for {@link Breakdown}. */ + /** + * Creates a new builder for {@link Breakdown}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private double idle; private double other; diff --git a/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java b/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java index a21e38b..bc4f249 100644 --- a/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/BreakdownDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,12 +24,16 @@ public final class BreakdownDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Breakdown} from a standalone byte array. */ + /** + * Decodes a {@link Breakdown} from a standalone byte array. + */ public static Breakdown fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Breakdown} read incrementally from a stream. */ + /** + * Decodes a {@link Breakdown} read incrementally from a stream. + */ public static Breakdown fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java b/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java index eb0b9b9..0ae07f8 100644 --- a/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/BreakdownEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,7 +24,9 @@ public final class BreakdownEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Breakdown value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/Cloud.java b/tests/opencost/java/com/opencost/opencost/Cloud.java index aaef223..bb2b4db 100644 --- a/tests/opencost/java/com/opencost/opencost/Cloud.java +++ b/tests/opencost/java/com/opencost/opencost/Cloud.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record Cloud(Map labels, AssetProperties properties, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost, double credit) implements Asset { - /** Creates a new builder for {@link Cloud}. */ + /** + * Creates a new builder for {@link Cloud}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private Map labels; private AssetProperties properties; diff --git a/tests/opencost/java/com/opencost/opencost/CloudDecoder.java b/tests/opencost/java/com/opencost/opencost/CloudDecoder.java index 34560dc..61f00c5 100644 --- a/tests/opencost/java/com/opencost/opencost/CloudDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/CloudDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class CloudDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Cloud} from a standalone byte array. */ + /** + * Decodes a {@link Cloud} from a standalone byte array. + */ public static Cloud fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Cloud} read incrementally from a stream. */ + /** + * Decodes a {@link Cloud} read incrementally from a stream. + */ public static Cloud fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/CloudEncoder.java b/tests/opencost/java/com/opencost/opencost/CloudEncoder.java index 63abbc5..20edc15 100644 --- a/tests/opencost/java/com/opencost/opencost/CloudEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/CloudEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class CloudEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Cloud value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/ClusterManagement.java b/tests/opencost/java/com/opencost/opencost/ClusterManagement.java index 44d030c..0d35029 100644 --- a/tests/opencost/java/com/opencost/opencost/ClusterManagement.java +++ b/tests/opencost/java/com/opencost/opencost/ClusterManagement.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -15,12 +17,16 @@ */ public record ClusterManagement(Map labels, AssetProperties properties, Window window, double cost) implements Asset { - /** Creates a new builder for {@link ClusterManagement}. */ + /** + * Creates a new builder for {@link ClusterManagement}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private Map labels; private AssetProperties properties; diff --git a/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java b/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java index d66177d..26ebe69 100644 --- a/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/ClusterManagementDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -24,12 +26,16 @@ public final class ClusterManagementDecoder implements BinDecoder labels, AssetProperties properties, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost, double byteHours, double local, Breakdown breakdown) implements Asset { - /** Creates a new builder for {@link Disk}. */ + /** + * Creates a new builder for {@link Disk}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private Map labels; private AssetProperties properties; diff --git a/tests/opencost/java/com/opencost/opencost/DiskDecoder.java b/tests/opencost/java/com/opencost/opencost/DiskDecoder.java index d7bcae8..0ebd631 100644 --- a/tests/opencost/java/com/opencost/opencost/DiskDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/DiskDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class DiskDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Disk} from a standalone byte array. */ + /** + * Decodes a {@link Disk} from a standalone byte array. + */ public static Disk fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Disk} read incrementally from a stream. */ + /** + * Decodes a {@link Disk} read incrementally from a stream. + */ public static Disk fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/DiskEncoder.java b/tests/opencost/java/com/opencost/opencost/DiskEncoder.java index b3004f8..e9598da 100644 --- a/tests/opencost/java/com/opencost/opencost/DiskEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/DiskEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class DiskEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Disk value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/LoadBalancer.java b/tests/opencost/java/com/opencost/opencost/LoadBalancer.java index ac5d5c3..f35bd2e 100644 --- a/tests/opencost/java/com/opencost/opencost/LoadBalancer.java +++ b/tests/opencost/java/com/opencost/opencost/LoadBalancer.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record LoadBalancer(AssetProperties properties, Map labels, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost) implements Asset { - /** Creates a new builder for {@link LoadBalancer}. */ + /** + * Creates a new builder for {@link LoadBalancer}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private AssetProperties properties; private Map labels; diff --git a/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java b/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java index bf46c9b..c5111fa 100644 --- a/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/LoadBalancerDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class LoadBalancerDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link LoadBalancer} from a standalone byte array. */ + /** + * Decodes a {@link LoadBalancer} from a standalone byte array. + */ public static LoadBalancer fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link LoadBalancer} read incrementally from a stream. */ + /** + * Decodes a {@link LoadBalancer} read incrementally from a stream. + */ public static LoadBalancer fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java b/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java index e335df9..7f8c43e 100644 --- a/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/LoadBalancerEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class LoadBalancerEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(LoadBalancer value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/Network.java b/tests/opencost/java/com/opencost/opencost/Network.java index eb3067c..738eeec 100644 --- a/tests/opencost/java/com/opencost/opencost/Network.java +++ b/tests/opencost/java/com/opencost/opencost/Network.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record Network(AssetProperties properties, Map labels, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, double cost) implements Asset { - /** Creates a new builder for {@link Network}. */ + /** + * Creates a new builder for {@link Network}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private AssetProperties properties; private Map labels; diff --git a/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java b/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java index ccd41f8..fe489f3 100644 --- a/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/NetworkDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class NetworkDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Network} from a standalone byte array. */ + /** + * Decodes a {@link Network} from a standalone byte array. + */ public static Network fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Network} read incrementally from a stream. */ + /** + * Decodes a {@link Network} read incrementally from a stream. + */ public static Network fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java b/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java index fbb5af2..897ac39 100644 --- a/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/NetworkEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class NetworkEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Network value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/Node.java b/tests/opencost/java/com/opencost/opencost/Node.java index 84631c3..3e5da9a 100644 --- a/tests/opencost/java/com/opencost/opencost/Node.java +++ b/tests/opencost/java/com/opencost/opencost/Node.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -16,12 +18,16 @@ */ public record Node(AssetProperties properties, Map labels, OffsetDateTime start, OffsetDateTime end, Window window, double adjustment, String nodeType, double cPUCoreHours, double rAMByteHours, double gPUHours, Breakdown cPUBreakdown, Breakdown rAMBreakdown, double cPUCost, double gPUCost, double gPUCount, double rAMCost, double discount, double preemptible) implements Asset { - /** Creates a new builder for {@link Node}. */ + /** + * Creates a new builder for {@link Node}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private AssetProperties properties; private Map labels; diff --git a/tests/opencost/java/com/opencost/opencost/NodeDecoder.java b/tests/opencost/java/com/opencost/opencost/NodeDecoder.java index cd66c63..ac3bc92 100644 --- a/tests/opencost/java/com/opencost/opencost/NodeDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/NodeDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -26,12 +28,16 @@ public final class NodeDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Node} from a standalone byte array. */ + /** + * Decodes a {@link Node} from a standalone byte array. + */ public static Node fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Node} read incrementally from a stream. */ + /** + * Decodes a {@link Node} read incrementally from a stream. + */ public static Node fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/NodeEncoder.java b/tests/opencost/java/com/opencost/opencost/NodeEncoder.java index 0d72150..e60d5a4 100644 --- a/tests/opencost/java/com/opencost/opencost/NodeEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/NodeEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +27,9 @@ public final class NodeEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Node value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/PVAllocation.java b/tests/opencost/java/com/opencost/opencost/PVAllocation.java index b0e0839..e460178 100644 --- a/tests/opencost/java/com/opencost/opencost/PVAllocation.java +++ b/tests/opencost/java/com/opencost/opencost/PVAllocation.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -14,12 +16,16 @@ */ public record PVAllocation(double byteHours, double cost) { - /** Creates a new builder for {@link PVAllocation}. */ + /** + * Creates a new builder for {@link PVAllocation}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private double byteHours; private double cost; diff --git a/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java b/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java index 81e6068..4889475 100644 --- a/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/PVAllocationDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,12 +24,16 @@ public final class PVAllocationDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link PVAllocation} from a standalone byte array. */ + /** + * Decodes a {@link PVAllocation} from a standalone byte array. + */ public static PVAllocation fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link PVAllocation} read incrementally from a stream. */ + /** + * Decodes a {@link PVAllocation} read incrementally from a stream. + */ public static PVAllocation fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java b/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java index d4e38ba..9a819a4 100644 --- a/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/PVAllocationEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,7 +24,9 @@ public final class PVAllocationEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(PVAllocation value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/PVKey.java b/tests/opencost/java/com/opencost/opencost/PVKey.java index 4ef6439..87dddad 100644 --- a/tests/opencost/java/com/opencost/opencost/PVKey.java +++ b/tests/opencost/java/com/opencost/opencost/PVKey.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -14,12 +16,16 @@ */ public record PVKey(String cluster, String name) { - /** Creates a new builder for {@link PVKey}. */ + /** + * Creates a new builder for {@link PVKey}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private String cluster; private String name; diff --git a/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java b/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java index a2264da..33b8aa8 100644 --- a/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/PVKeyDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,12 +24,16 @@ public final class PVKeyDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link PVKey} from a standalone byte array. */ + /** + * Decodes a {@link PVKey} from a standalone byte array. + */ public static PVKey fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link PVKey} read incrementally from a stream. */ + /** + * Decodes a {@link PVKey} read incrementally from a stream. + */ public static PVKey fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java b/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java index 7c6c3c8..d6411d0 100644 --- a/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/PVKeyEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,7 +24,9 @@ public final class PVKeyEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(PVKey value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java index b631e44..4106eac 100644 --- a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java +++ b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyData.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -14,12 +16,16 @@ */ public record RawAllocationOnlyData(double cPUCoreUsageMax, double rAMBytesUsageMax) { - /** Creates a new builder for {@link RawAllocationOnlyData}. */ + /** + * Creates a new builder for {@link RawAllocationOnlyData}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private double cPUCoreUsageMax; private double rAMBytesUsageMax; diff --git a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java index d0584a5..2b5101f 100644 --- a/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/RawAllocationOnlyDataDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -22,12 +24,16 @@ public final class RawAllocationOnlyDataDecoder implements BinDecoder labels, Window window, double cost) implements Asset { - /** Creates a new builder for {@link SharedAsset}. */ + /** + * Creates a new builder for {@link SharedAsset}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private AssetProperties properties; private Map labels; diff --git a/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java b/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java index 301b646..0d16631 100644 --- a/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/SharedAssetDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -24,12 +26,16 @@ public final class SharedAssetDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link SharedAsset} from a standalone byte array. */ + /** + * Decodes a {@link SharedAsset} from a standalone byte array. + */ public static SharedAsset fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link SharedAsset} read incrementally from a stream. */ + /** + * Decodes a {@link SharedAsset} read incrementally from a stream. + */ public static SharedAsset fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java b/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java index 20f8db3..d18c472 100644 --- a/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/SharedAssetEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -23,7 +25,9 @@ public final class SharedAssetEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(SharedAsset value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/TypeRegistry.java b/tests/opencost/java/com/opencost/opencost/TypeRegistry.java index c095514..b195c29 100644 --- a/tests/opencost/java/com/opencost/opencost/TypeRegistry.java +++ b/tests/opencost/java/com/opencost/opencost/TypeRegistry.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -58,7 +60,9 @@ private static void register(String wire, Class cls, BinEncoder enc, B ENCODERS.put(cls, enc); } - /** Writes the wire type string + compatibility marker, then the value body. */ + /** + * Writes the wire type string + compatibility marker, then the value body. + */ @SuppressWarnings("unchecked") public static void encode(Object value, EncodingContext ctx) { String wire = WIRE_NAMES.get(value.getClass()); @@ -71,7 +75,9 @@ public static void encode(Object value, EncodingContext ctx) { enc.encode(value, ctx); } - /** Reads the compatibility marker, then decodes the concrete value. */ + /** + * Reads the compatibility marker, then decodes the concrete value. + */ public static Object decode(String wire, DecodingContext ctx) { BinDecoder dec = DECODERS.get(wire); if (dec == null) { diff --git a/tests/opencost/java/com/opencost/opencost/Window.java b/tests/opencost/java/com/opencost/opencost/Window.java index d8914ee..803d7d3 100644 --- a/tests/opencost/java/com/opencost/opencost/Window.java +++ b/tests/opencost/java/com/opencost/opencost/Window.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -15,12 +17,16 @@ */ public record Window(OffsetDateTime start, OffsetDateTime end) { - /** Creates a new builder for {@link Window}. */ + /** + * Creates a new builder for {@link Window}. + */ public static Builder builder() { return new Builder(); } - /** Mutable builder the decoder uses to accumulate fields and apply defaults. */ + /** + * Mutable builder the decoder uses to accumulate fields and apply defaults. + */ public static final class Builder { private OffsetDateTime start; private OffsetDateTime end; diff --git a/tests/opencost/java/com/opencost/opencost/WindowDecoder.java b/tests/opencost/java/com/opencost/opencost/WindowDecoder.java index e0196ca..7d18130 100644 --- a/tests/opencost/java/com/opencost/opencost/WindowDecoder.java +++ b/tests/opencost/java/com/opencost/opencost/WindowDecoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -24,12 +26,16 @@ public final class WindowDecoder implements BinDecoder { private static final int VERSION = 16; - /** Decodes a {@link Window} from a standalone byte array. */ + /** + * Decodes a {@link Window} from a standalone byte array. + */ public static Window fromBytes(byte[] data) { return INSTANCE.decode(DecodingContext.fromBytes(data)); } - /** Decodes a {@link Window} read incrementally from a stream. */ + /** + * Decodes a {@link Window} read incrementally from a stream. + */ public static Window fromStream(InputStream in) { return INSTANCE.decode(DecodingContext.fromStream(in)); } diff --git a/tests/opencost/java/com/opencost/opencost/WindowEncoder.java b/tests/opencost/java/com/opencost/opencost/WindowEncoder.java index ecbf130..00cc4ee 100644 --- a/tests/opencost/java/com/opencost/opencost/WindowEncoder.java +++ b/tests/opencost/java/com/opencost/opencost/WindowEncoder.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// @@ -24,7 +26,9 @@ public final class WindowEncoder implements BinEncoder { private static final int VERSION = 16; private static final boolean STRING_TABLE = false; - /** Encodes {@code value} to a standalone byte array. */ + /** + * Encodes {@code value} to a standalone byte array. + */ public static byte[] toBytes(Window value) { EncodingContext ctx = STRING_TABLE ? EncodingContext.withStringTable() : EncodingContext.create(); INSTANCE.encode(value, ctx); diff --git a/tests/opencost/java/com/opencost/opencost/package-info.java b/tests/opencost/java/com/opencost/opencost/package-info.java index 10691d5..ccd9617 100644 --- a/tests/opencost/java/com/opencost/opencost/package-info.java +++ b/tests/opencost/java/com/opencost/opencost/package-info.java @@ -2,6 +2,8 @@ // // DO NOT MODIFY // +// ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ +// // This source file was automatically generated by bingen. // //////////////////////////////////////////////////////////////////////////////// From 59f95274ec2c610456350593b975e32e4f66a6df Mon Sep 17 00:00:00 2001 From: Matt Bolt Date: Tue, 4 Aug 2026 17:05:53 -0400 Subject: [PATCH 3/3] Cleanup java roundtrip testing --- internal/generator/java/roundtrip_test.go | 110 ++++++---------------- tests/roundtrip_test.go | 4 +- 2 files changed, 33 insertions(+), 81 deletions(-) diff --git a/internal/generator/java/roundtrip_test.go b/internal/generator/java/roundtrip_test.go index a28609f..f5c2622 100644 --- a/internal/generator/java/roundtrip_test.go +++ b/internal/generator/java/roundtrip_test.go @@ -1,6 +1,7 @@ package java import ( + "fmt" "testing" "time" @@ -12,28 +13,41 @@ import ( "github.com/opencost/bingen/tests/timerec" ) -// TestRoundTrip_Decoder marshals a Container in go, has java decode and -// re-encode it, and asserts the bytes are identical and the values survived. -func TestRoundTrip_Decoder(t *testing.T) { - const decodeReencodeHarness = `import com.opencost.container.Container; -import com.opencost.container.ContainerDecoder; -import com.opencost.container.ContainerEncoder; +// RoundTripJavaSourceFor generates a java program which will read a binary file from the first argument, +// decode it into the proper type, then re-encode it back into binary and write it to the second argument. +func RoundTripJavaSourceFor(baseJavaPackage, goPackage, typeName, harnessName string) string { + fullPkg := fmt.Sprintf("%s.%s", baseJavaPackage, goPackage) + encoder := fmt.Sprintf("%sEncoder", typeName) + decoder := fmt.Sprintf("%sDecoder", typeName) + + return fmt.Sprintf(`import %s.%s; +import %s.%s; +import %s.%s; import com.bingen.DecodingContext; import com.bingen.EncodingContext; import java.nio.file.Files; import java.nio.file.Path; -public final class DecodeReencodeMain { +public final class %s { public static void main(String[] args) throws Exception { byte[] in = Files.readAllBytes(Path.of(args[0])); - Container c = ContainerDecoder.INSTANCE.decode(DecodingContext.fromBytes(in)); - EncodingContext ctx = EncodingContext.create(); - ContainerEncoder.INSTANCE.encode(c, ctx); - Files.write(Path.of(args[1]), ctx.toBytes()); + %s c = %s.fromBytes(in); + Files.write(Path.of(args[1]), %s.toBytes(c)); } } -` +`, + fullPkg, typeName, + fullPkg, decoder, + fullPkg, encoder, + harnessName, + typeName, decoder, + encoder, + ) +} +// TestRoundTrip_Decoder marshals a Container in go, has java decode and +// re-encode it, and asserts the bytes are identical and the values survived. +func TestRoundTrip_Decoder(t *testing.T) { const goPackage = "container" const harnessName = "DecodeReencodeMain" @@ -41,7 +55,7 @@ public final class DecodeReencodeMain { javaMain := &javaSource{ FileName: harnessName, - Source: decodeReencodeHarness, + Source: RoundTripJavaSourceFor(BaseJavaPackage, goPackage, "Container", harnessName), } testRunner := newRoundTripTestBuilder[container.Container](goPackage, javaMain). @@ -67,24 +81,6 @@ public final class DecodeReencodeMain { // go, has java decode + re-encode it through the TypeRegistry, and asserts the // bytes are identical and the concrete types survived. func TestRoundTripInterface_Shape(t *testing.T) { - const drawingReencodeHarness = `import com.opencost.shape.Drawing; -import com.opencost.shape.DrawingDecoder; -import com.opencost.shape.DrawingEncoder; -import com.bingen.DecodingContext; -import com.bingen.EncodingContext; -import java.nio.file.Files; -import java.nio.file.Path; - -public final class DrawingReencodeMain { - public static void main(String[] args) throws Exception { - byte[] in = Files.readAllBytes(Path.of(args[0])); - Drawing d = DrawingDecoder.INSTANCE.decode(DecodingContext.fromBytes(in)); - EncodingContext ctx = EncodingContext.create(); - DrawingEncoder.INSTANCE.encode(d, ctx); - Files.write(Path.of(args[1]), ctx.toBytes()); - } -} -` const goPackage = "shape" const harnessName = "DrawingReencodeMain" @@ -92,7 +88,7 @@ public final class DrawingReencodeMain { javaMain := &javaSource{ FileName: harnessName, - Source: drawingReencodeHarness, + Source: RoundTripJavaSourceFor(BaseJavaPackage, goPackage, "Drawing", harnessName), } testRunner := newRoundTripTestBuilder[shape.Drawing](goPackage, javaMain). WithAssertion(func(t *testing.T, t1 *shape.Drawing, t2 *shape.Drawing) { @@ -133,21 +129,6 @@ public final class DrawingReencodeMain { // deduplicated into a BGST-prefixed table), has java decode + re-encode it, and // asserts the bytes are identical and the values survived. func TestRoundTrip_StringTable(t *testing.T) { - const docReencodeHarness = `import com.opencost.sttable.Doc; -import com.opencost.sttable.DocDecoder; -import com.opencost.sttable.DocEncoder; -import java.nio.file.Files; -import java.nio.file.Path; - -public final class DocReencodeMain { - public static void main(String[] args) throws Exception { - byte[] in = Files.readAllBytes(Path.of(args[0])); - Doc d = DocDecoder.fromBytes(in); - Files.write(Path.of(args[1]), DocEncoder.toBytes(d)); - } -} -` - const goPackage = "sttable" const harnessName = "DocReencodeMain" @@ -155,7 +136,7 @@ public final class DocReencodeMain { javaMain := &javaSource{ FileName: harnessName, - Source: docReencodeHarness, + Source: RoundTripJavaSourceFor(BaseJavaPackage, goPackage, "Doc", harnessName), } testRunner := newRoundTripTestBuilder[sttable.Doc](goPackage, javaMain). WithAssertion(func(t *testing.T, t1 *sttable.Doc, t2 *sttable.Doc) { @@ -191,21 +172,6 @@ public final class DocReencodeMain { // decode + re-encode it through GoTime, and asserts the bytes are identical and // the instant survived. func TestRoundTrip_Time(t *testing.T) { - const eventReencodeHarness = `import com.opencost.timerec.Event; -import com.opencost.timerec.EventDecoder; -import com.opencost.timerec.EventEncoder; -import java.nio.file.Files; -import java.nio.file.Path; - -public final class EventReencodeMain { - public static void main(String[] args) throws Exception { - byte[] in = Files.readAllBytes(Path.of(args[0])); - Event e = EventDecoder.fromBytes(in); - Files.write(Path.of(args[1]), EventEncoder.toBytes(e)); - } -} -` - const goPackage = "timerec" const harnessName = "EventReencodeMain" @@ -213,7 +179,7 @@ public final class EventReencodeMain { javaMain := &javaSource{ FileName: harnessName, - Source: eventReencodeHarness, + Source: RoundTripJavaSourceFor(BaseJavaPackage, goPackage, "Event", harnessName), } testRunner := newRoundTripTestBuilder[timerec.Event](goPackage, javaMain). @@ -255,20 +221,6 @@ public final class EventReencodeMain { // (Tags = []string). The nil-flag byte must be read symmetrically or the // trailing Count field is corrupted. func TestRoundTrip_NilableAlias(t *testing.T) { - const holderReencodeHarness = `import com.opencost.aliasnil.Holder; -import com.opencost.aliasnil.HolderDecoder; -import com.opencost.aliasnil.HolderEncoder; -import java.nio.file.Files; -import java.nio.file.Path; - -public final class HolderReencodeMain { - public static void main(String[] args) throws Exception { - byte[] in = Files.readAllBytes(Path.of(args[0])); - Holder h = HolderDecoder.fromBytes(in); - Files.write(Path.of(args[1]), HolderEncoder.toBytes(h)); - } -} -` const goPackage = "aliasnil" const harnessName = "HolderReencodeMain" @@ -276,7 +228,7 @@ public final class HolderReencodeMain { javaMain := &javaSource{ FileName: harnessName, - Source: holderReencodeHarness, + Source: RoundTripJavaSourceFor(BaseJavaPackage, goPackage, "Holder", harnessName), } testRunner := newRoundTripTestBuilder[aliasnil.Holder](goPackage, javaMain). diff --git a/tests/roundtrip_test.go b/tests/roundtrip_test.go index c485582..8fbb215 100644 --- a/tests/roundtrip_test.go +++ b/tests/roundtrip_test.go @@ -23,7 +23,7 @@ func TestRoundTrip_Aliases(t *testing.T) { t.Fatalf("MarshalBinary: %v", err) } - decoded := &aliases.Parent{} + decoded := new(aliases.Parent) if err := decoded.UnmarshalBinary(data); err != nil { t.Fatalf("UnmarshalBinary: %v", err) } @@ -101,7 +101,7 @@ func TestRoundTrip_Opencost(t *testing.T) { t.Fatalf("MarshalBinary: %v", err) } - decoded := &opencost.AssetSet{} + decoded := new(opencost.AssetSet) if err := decoded.UnmarshalBinary(b1); err != nil { t.Fatalf("UnmarshalBinary: %v", err) }