| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // DO NOT MODIFY
- //
- // ┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻
- //
- //
- // This source file was automatically generated by bingen.
- //
- ////////////////////////////////////////////////////////////////////////////////
- package shared
- import (
- "fmt"
- util "github.com/opencost/opencost/core/pkg/util"
- "io"
- "iter"
- "os"
- "reflect"
- "strings"
- "sync"
- "unsafe"
- )
- const (
- // GeneratorPackageName is the package the generator is targetting
- GeneratorPackageName string = "shared"
- )
- // BinaryTags represent the formatting tag used for specific optimization features
- const (
- // BinaryTagStringTable is written and/or read prior to the existence of a string
- // table (where each index is encoded as a string entry in the resource
- BinaryTagStringTable string = "BGST"
- )
- const (
- // 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
- }
- // DefaultBingenConfiguration creates the default implementation of the bingen configuration
- // and returns it.
- func DefaultBingenConfiguration() *BingenConfiguration {
- return &BingenConfiguration{
- FileBackedStringTableEnabled: false,
- FileBackedStringTableDir: os.TempDir(),
- }
- }
- // 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
- }
- //--------------------------------------------------------------------------
- // Type Map
- //--------------------------------------------------------------------------
- // Generated type map for resolving interface implementations to
- // to concrete types
- var typeMap map[string]reflect.Type = map[string]reflect.Type{}
- //--------------------------------------------------------------------------
- // 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
- }
- // appendBytes combines a and b into a new byte array
- func appendBytes(a []byte, b []byte) []byte {
- al := len(a)
- bl := len(b)
- tl := al + bl
- // allocate a new byte array for the combined
- // use native copy for speedy byte copying
- result := make([]byte, tl)
- copy(result, a)
- copy(result[al:], b)
- return result
- }
- // 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) 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{}
- // 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) (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
- }
- // BingenStream is the stream interface for all streamable types
- type BingenStream interface {
- // Stream returns the iterator which will stream each field of the target type and
- // return the field info as well as the value.
- Stream() iter.Seq2[BingenFieldInfo, *BingenValue]
- // Close will close any dynamic io.Reader used to stream in the fields
- Close()
- // Error returns an error if one occurred during the process of streaming the type's fields.
- // This can be checked after iterating through the Stream().
- Error() error
- }
- // BingenValue contains the value of a field as well as any index/key associated with that value.
- type BingenValue struct {
- Value any
- Index any
- }
- // IsNil is just a method accessor way to check to see if the value returned was nil
- func (bv *BingenValue) IsNil() bool {
- return bv == nil
- }
- // creates a single BingenValue instance without a key or index
- func singleV(value any) *BingenValue {
- return &BingenValue{
- Value: value,
- }
- }
- // creates a pair of key/index and value.
- func pairV(index any, value any) *BingenValue {
- return &BingenValue{
- Value: value,
- Index: index,
- }
- }
- // BingenFieldInfo contains the type of the field being streamed as well as the name of the field.
- type BingenFieldInfo struct {
- Type reflect.Type
- Name string
- }
- //--------------------------------------------------------------------------
- // String Table Writer
- //--------------------------------------------------------------------------
- // StringTableWriter maps strings to specific indices for encoding
- type StringTableWriter struct {
- l sync.Mutex
- indices map[string]int
- next int
- }
- // NewStringTableWriter Creates a new StringTableWriter instance with provided contents
- func NewStringTableWriter(contents ...string) *StringTableWriter {
- st := &StringTableWriter{
- indices: make(map[string]int, len(contents)),
- next: len(contents),
- }
- for i, entry := range contents {
- st.indices[entry] = i
- }
- return st
- }
- // AddOrGet atomically retrieves a string entry's index if it exist. Otherwise, it will
- // add the entry and return the index.
- func (st *StringTableWriter) AddOrGet(s string) int {
- st.l.Lock()
- defer st.l.Unlock()
- if ind, ok := st.indices[s]; ok {
- return ind
- }
- current := st.next
- st.next++
- st.indices[s] = current
- return current
- }
- // ToSlice Converts the contents to a string array for encoding.
- func (st *StringTableWriter) ToSlice() []string {
- st.l.Lock()
- defer st.l.Unlock()
- if st.next == 0 {
- return []string{}
- }
- sl := make([]string, st.next)
- for s, i := range st.indices {
- sl[i] = s
- }
- return sl
- }
- // ToBytes Converts the contents to a binary encoded representation
- func (st *StringTableWriter) ToBytes() []byte {
- buff := util.NewBuffer()
- buff.WriteBytes([]byte(BinaryTagStringTable)) // bingen table header
- strs := st.ToSlice()
- buff.WriteInt(len(strs)) // table length
- for _, s := range strs {
- buff.WriteString(s)
- }
- return buff.Bytes()
- }
- //--------------------------------------------------------------------------
- // String Table Reader
- //--------------------------------------------------------------------------
- // StringTableReader is the interface used to read the string table from the decoding.
- type StringTableReader interface {
- // At returns the string entry at a specific index, or panics on out of bounds.
- At(index int) string
- // Len returns the total number of strings loaded in the string table.
- Len() int
- // Close will clear the loaded table, and drop any external resources used.
- Close() error
- }
- // SliceStringTableReader is a basic pre-loaded []string that provides index-based access.
- // The cost of this implementation is holding all strings in memory, which provides faster
- // lookup performance for memory usage.
- type SliceStringTableReader struct {
- table []string
- }
- // NewSliceStringTableReaderFrom creates a new SliceStringTableReader instance loading
- // data directly from the buffer. The buffer's position should start at the table length.
- func NewSliceStringTableReaderFrom(buffer *util.Buffer) StringTableReader {
- // table length
- tl := buffer.ReadInt()
- var table []string
- if tl > 0 {
- table = make([]string, tl)
- for i := range tl {
- table[i] = buffer.ReadString()
- }
- }
- return &SliceStringTableReader{
- table: table,
- }
- }
- // At returns the string entry at a specific index, or panics on out of bounds.
- func (sstr *SliceStringTableReader) At(index int) string {
- if index < 0 || index >= len(sstr.table) {
- panic(fmt.Errorf("%s: string table index out of bounds: %d", GeneratorPackageName, index))
- }
- return sstr.table[index]
- }
- // Len returns the total number of strings loaded in the string table.
- func (sstr *SliceStringTableReader) Len() int {
- if sstr == nil {
- return 0
- }
- return len(sstr.table)
- }
- // Close for the slice tables just nils out the slice and returns
- func (sstr *SliceStringTableReader) Close() error {
- sstr.table = nil
- return nil
- }
- // fileStringRef maps a bingen string-table index to a payload stored in a temp file.
- type fileStringRef struct {
- off int64
- length int
- }
- // FileStringTableReader leverages a local file to write string table data for lookup. On
- // memory focused systems, this allows a slower parse with a significant decrease in memory
- // usage. This implementation is often pair with streaming readers for high throughput with
- // reduced memory usage.
- type FileStringTableReader struct {
- f *os.File
- refs []fileStringRef
- }
- // NewFileStringTableFromBuffer reads exactly tl length-prefixed (uint16) string payloads from buffer
- // and appends each payload to a new temp file. It does not retain full strings in memory.
- func NewFileStringTableReaderFrom(buffer *util.Buffer, dir string) StringTableReader {
- // helper func to cast a string in-place to a byte slice.
- // NOTE: Return value is READ-ONLY. DO NOT MODIFY!
- byteSliceFor := func(s string) []byte {
- return unsafe.Slice(unsafe.StringData(s), len(s))
- }
- err := os.MkdirAll(dir, 0755)
- if err != nil {
- panic(fmt.Errorf("%s: failed to create string table directory: %w", GeneratorPackageName, err))
- }
- f, err := os.CreateTemp(dir, fmt.Sprintf("%s-bgst-*", GeneratorPackageName))
- if err != nil {
- panic(fmt.Errorf("%s: failed to create string table file: %w", GeneratorPackageName, err))
- }
- var writeErr error
- defer func() {
- if writeErr != nil {
- _ = f.Close()
- }
- }()
- // table length
- tl := buffer.ReadInt()
- var refs []fileStringRef
- if tl > 0 {
- refs = make([]fileStringRef, tl)
- for i := range tl {
- payload := byteSliceFor(buffer.ReadString())
- var off int64
- if len(payload) > 0 {
- off, err = f.Seek(0, io.SeekEnd)
- if err != nil {
- writeErr = fmt.Errorf("%s: failed to seek string table file: %w", GeneratorPackageName, err)
- panic(writeErr)
- }
- if _, err := f.Write(payload); err != nil {
- writeErr = fmt.Errorf("%s: failed to write string table entry %d: %w", GeneratorPackageName, i, err)
- panic(writeErr)
- }
- }
- refs[i] = fileStringRef{
- off: off,
- length: len(payload),
- }
- }
- }
- return &FileStringTableReader{
- f: f,
- refs: refs,
- }
- }
- // At returns the string from the internal file using the reference's offset and length.
- func (fstr *FileStringTableReader) At(index int) string {
- if fstr == nil || fstr.f == nil {
- panic(fmt.Errorf("%s: failed to read file string table data", GeneratorPackageName))
- }
- if index < 0 || index >= len(fstr.refs) {
- panic(fmt.Errorf("%s: string table index out of bounds: %d", GeneratorPackageName, index))
- }
- ref := fstr.refs[index]
- if ref.length == 0 {
- return ""
- }
- b := make([]byte, ref.length)
- _, err := fstr.f.ReadAt(b, ref.off)
- if err != nil {
- return ""
- }
- // cast the allocated bytes to a string in-place, as we
- // were the ones that allocated the bytes
- return unsafe.String(unsafe.SliceData(b), len(b))
- }
- // Len returns the total number of strings loaded in the string table.
- func (fstr *FileStringTableReader) Len() int {
- if fstr == nil {
- return 0
- }
- return len(fstr.refs)
- }
- // Close for the file string table reader closes the file and deletes it.
- func (fstr *FileStringTableReader) Close() error {
- if fstr == nil || fstr.f == nil {
- return nil
- }
- path := fstr.f.Name()
- err := fstr.f.Close()
- fstr.f = nil
- fstr.refs = nil
- if path != "" {
- _ = os.Remove(path)
- }
- return err
- }
- //--------------------------------------------------------------------------
- // 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 *StringTableWriter
- }
- // 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 StringTableReader
- }
- // NewDecodingContextFromBytes creates a new DecodingContext instance using an byte slice
- func NewDecodingContextFromBytes(data []byte) *DecodingContext {
- var table StringTableReader
- buff := util.NewBufferFromBytes(data)
- // string table header validation
- if isBinaryTag(data, BinaryTagStringTable) {
- buff.ReadBytes(len(BinaryTagStringTable)) // strip tag length
- // always use a slice string table with a byte array since the
- // data is already in memory
- table = 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 StringTableReader
- buff := util.NewBufferFromReader(reader)
- if isReaderBinaryTag(buff, BinaryTagStringTable) {
- buff.ReadBytes(len(BinaryTagStringTable)) // strip tag length
- // create correct string table implementation
- if IsBingenFileBackedStringTableEnabled() {
- table = NewFileStringTableReaderFrom(buff, BingenFileBackedStringTableDir())
- } else {
- table = 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
- }
|