typegen

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2025 License: MIT Imports: 19 Imported by: 1,067

README

cbor-gen

cbor-gen is a code generation tool that automatically creates CBOR (Concise Binary Object Representation) marshaling and unmarshaling functions for Go types.

Overview

The library generates MarshalCBOR and UnmarshalCBOR methods for your Go structs and types, allowing them to be encoded to and decoded from CBOR format. This is particularly useful when you need efficient binary serialization with CBOR support.

Usage

  1. Define your types in a .go file:
type MyStruct struct {
    Field1 string
    Field2 uint64
    Field3 []byte
    Field4 *CustomType
}
  1. Create a generator file (e.g., gen/main.go):
package main

import (
    cbg "github.com/whyrusleeping/cbor-gen"
)

func main() {
    // Generate tuple-style encoders (list of fields)...
    if err := cbg.WriteTupleEncodersToFile("cbor_gen.go", "mypackage",
        MyStruct{},
        // Add other types here...
    ); err != nil {
        panic(err)
    }

    // Or generate map-style encoders (map of field names to field values)...
    if err := cbg.WriteMapEncodersToFile("cbor_map_gen.go", "mypackage",
        MyStruct{},
        // Add other types here...
    ); err != nil {
        panic(err)
    }
}
  1. Run the generator:
go run gen/main.go

Features

Encoding Styles
  • Tuple encoding (WriteTupleEncodersToFile): Encodes structs as CBOR arrays, more space-efficient but order-dependent.
  • Map encoding (WriteMapEncodersToFile): Encodes structs as CBOR maps with field names, more verbose but order-independent.
Field Tags

The library supports several struct tags to customize encoding:

type Example struct {
    // Rename field in CBOR output
    Field1 string `cborgen:"renamed_field"`

    // Preserve nil slices (encode nil as null, not as an empty cbor list)
    Field2 []uint64 `cborgen:"preservenil"`

    // Skip encoding this field when it matches its zero value. This is only applicable
    // when map-encoding; when tuple-encoding, all fields are always written.
    Field3 string `cborgen:"omitempty"`

    // Set constant value XXX WTF IS THIS?
    Field4 string `cborgen:"const=somevalue"`

    // Maximum length for slices/strings, defaults to 8192 for lists,
    // 2MiB for strings/bytes unless otherwise specified in cbg.Gen.
    Field5 []byte `cborgen:"maxlen=1000000"`

    // Allow this field to be missing when decoding a tuple-style struct. Optional fields
    // may only appear at the end of of structs and cannot be followed by mandatory fields.
    //
    // This tag is ignored when decoding map-style structs as all fields are optional in
    // map-style structs.
    Field6 string `cborgen:"optional"`
}

Additionally, you can specify that struct with a single field should be encoded as that field alone as if it didn't appear in a struct by specifying the "transparent" tag. For example, the following TransparentExample will encode as a string (regardless of whether tuple or map encoding was specified when generating the UnmarshalCBOR and MarshalCBOR functions):

type TransparentExample struct {
	TheOneAndOnlyField string `cborgen:"transparent"`
}
Upgrading Type Schemas

When working with map-encoded types, all fields are optional when decoding (they default to the field's zero-value) and unknown fields are skipped.

When working with tuple-encoded types, fields are mandatory by default and unknown (additional) fields will be rejected. However, it's possible to add additional optional fields to the end of the tuple-encoded struct by tagging them as cborgen:"optional"; this makes it possible to decode a tuple-encoded struct that omits a suffix of the expected fields. On encoding, optional fields will always be included.

Customizing Generation

You can customize generation parameters using the Gen type:

err := cbg.Gen{
    MaxArrayLength:  8192,    // Maximum length for arrays
    MaxByteLength:   2<<20,   // Maximum length for byte slices
    MaxStringLength: 2<<20,   // Maximum length for strings
}.WriteTupleEncodersToFile("cbor_gen.go", "mypackage",
    MyType{},
)

Supported Types

The library can generate encoders/decoders for:

  • Basic Go types (integers, strings, etc.)
  • Slices, arrays, and maps.
  • Custom types that implement UnmarshalCBOR and MarshalCBOR (usually generated with this library).
  • cid.Cid from github.com/ipfs/go-cid
  • big.Int

Generated Code

The tool will generate MarshalCBOR(w io.Writer) error and UnmarshalCBOR(r io.Reader) error methods for each type. These methods handle the CBOR encoding and decoding respectively.

License

MIT

Documentation

Index

Constants

View Source
const (
	MajUnsignedInt = 0
	MajNegativeInt = 1
	MajByteString  = 2
	MajTextString  = 3
	MajArray       = 4
	MajMap         = 5
	MajTag         = 6
	MajOther       = 7
)
View Source
const ByteArrayMaxLen = 2 << 20
View Source
const FieldNameSelf = "."

FieldNameSelf is the name of the field that is the marshal target itself. This is used in non-struct types which are handled like transparent structs.

View Source
const MaxLenTag = "maxlen"
View Source
const MaxLength = 8192
View Source
const NoUsrMaxLen = -1

Variables

View Source
var (
	CborBoolFalse = []byte{0xf4}
	CborBoolTrue  = []byte{0xf5}
	CborNull      = []byte{0xf6}
)

Functions

func CborEncodeMajorType

func CborEncodeMajorType(t byte, l uint64) []byte

func CborReadHeader

func CborReadHeader(br io.Reader) (byte, uint64, error)

func CborReadHeaderBuf

func CborReadHeaderBuf(br io.Reader, scratch []byte) (byte, uint64, error)

same as the above, just tries to allocate less by using a passed in scratch buffer

func CborWriteHeader

func CborWriteHeader(w io.Writer, t byte, l uint64) error

func EncodeBool

func EncodeBool(b bool) []byte

func GenMapEncodersForType

func GenMapEncodersForType(gti *GenTypeInfo, w io.Writer) error

GenMapEncodersForType is a convenience wrapper around Gen.GenMapEncodersForType using default options.

func GenTupleEncodersForType

func GenTupleEncodersForType(gti *GenTypeInfo, w io.Writer) error

GenTupleEncodersForType is a convenience wrapper around Gen.GenTupleEncodersForType using default options.

func MakeByteString

func MakeByteString(h []byte) string

func PrintHeaderAndUtilityMethods

func PrintHeaderAndUtilityMethods(w io.Writer, pkg string, typeInfos []*GenTypeInfo) error

PrintHeaderAndUtilityMethods is a convenience wrapper around Gen.PrintHeaderAndUtilityMethods using default options.

func ReadByteArray

func ReadByteArray(br io.Reader, maxlen uint64) ([]byte, error)

func ReadCid

func ReadCid(br io.Reader) (cid.Cid, error)

func ReadFullStringIntoBuf added in v0.3.0

func ReadFullStringIntoBuf(cr *CborReader, buf []byte, maxLength uint64) (int, bool, error)

ReadFullStringIntoBuf will read a string off the given stream, consuming the entire cbor item if the string on the stream is longer than the buffer, the string is discarded and 'false' is returned Note: Will only read data into the buffer if the data fits into the buffer, otherwise the bytes are discarded entirely

func ReadString

func ReadString(r io.Reader) (string, error)

func ReadStringBuf deprecated

func ReadStringBuf(r io.Reader, _ []byte) (string, error)

Deprecated: use ReadString

func ReadStringWithMax

func ReadStringWithMax(r io.Reader, maxLength uint64) (string, error)

func ReadTaggedByteArray

func ReadTaggedByteArray(br io.Reader, exptag uint64, maxlen uint64) (bs []byte, err error)
func ScanForLinks(br io.Reader, cb func(cid.Cid)) (err error)

func ValidateCBOR

func ValidateCBOR(b []byte) error

ValidateCBOR validates that a byte array is a single valid CBOR object.

func WriteBool

func WriteBool(w io.Writer, b bool) error

func WriteByteArray

func WriteByteArray(bw io.Writer, bytes []byte) error

WriteByteArray encodes a byte array as a cbor byte-string.

func WriteCid

func WriteCid(w io.Writer, c cid.Cid) error

func WriteCidBuf

func WriteCidBuf(buf []byte, w io.Writer, c cid.Cid) error

func WriteMajorTypeHeader

func WriteMajorTypeHeader(w io.Writer, t byte, l uint64) error

TODO: No matter what I do, this function *still* allocates. Its super frustrating. See issue: https://github.com/golang/go/issues/33160

func WriteMajorTypeHeaderBuf

func WriteMajorTypeHeaderBuf(buf []byte, w io.Writer, t byte, l uint64) error

Same as the above, but uses a passed in buffer to avoid allocations

func WriteMapEncodersToFile

func WriteMapEncodersToFile(fname, pkg string, types ...interface{}) error

WriteMapFileEncodersToFile is a convenience wrapper around Gen.WriteMapEncodersToFile using default options.

func WriteTupleEncodersToFile

func WriteTupleEncodersToFile(fname, pkg string, types ...interface{}) error

WriteTupleFileEncodersToFile is a convenience wrapper around Gen.WriteTupleEncodersToFile using default options.

Types

type BytePeeker

type BytePeeker interface {
	io.Reader
	io.ByteScanner
}

BytePeeker combines the Reader and ByteScanner interfaces.

func GetPeeker

func GetPeeker(r io.Reader) BytePeeker

type CBORMarshaler

type CBORMarshaler interface {
	MarshalCBOR(io.Writer) error
}

type CBORUnmarshaler

type CBORUnmarshaler interface {
	UnmarshalCBOR(io.Reader) error
}

type CborBool

type CborBool bool

func (CborBool) MarshalCBOR

func (cb CborBool) MarshalCBOR(w io.Writer) error

func (*CborBool) UnmarshalCBOR

func (cb *CborBool) UnmarshalCBOR(r io.Reader) error

type CborCid

type CborCid cid.Cid

func (CborCid) MarshalCBOR

func (c CborCid) MarshalCBOR(w io.Writer) error

func (*CborCid) UnmarshalCBOR

func (c *CborCid) UnmarshalCBOR(r io.Reader) error

type CborInt

type CborInt int64

func (CborInt) MarshalCBOR

func (ci CborInt) MarshalCBOR(w io.Writer) error

func (*CborInt) UnmarshalCBOR

func (ci *CborInt) UnmarshalCBOR(r io.Reader) error

type CborReader

type CborReader struct {
	// contains filtered or unexported fields
}

func NewCborReader

func NewCborReader(r io.Reader) *CborReader

func (*CborReader) Read

func (cr *CborReader) Read(p []byte) (n int, err error)

func (*CborReader) ReadByte

func (cr *CborReader) ReadByte() (byte, error)

func (*CborReader) ReadHeader

func (cr *CborReader) ReadHeader() (byte, uint64, error)

func (*CborReader) SetReader

func (cr *CborReader) SetReader(r io.Reader)

func (*CborReader) UnreadByte

func (cr *CborReader) UnreadByte() error

type CborTime

type CborTime time.Time

func (CborTime) MarshalCBOR

func (ct CborTime) MarshalCBOR(w io.Writer) error

func (CborTime) MarshalJSON

func (ct CborTime) MarshalJSON() ([]byte, error)

func (CborTime) Time

func (ct CborTime) Time() time.Time

func (*CborTime) UnmarshalCBOR

func (ct *CborTime) UnmarshalCBOR(r io.Reader) error

func (*CborTime) UnmarshalJSON

func (ct *CborTime) UnmarshalJSON(b []byte) error

type CborWriter

type CborWriter struct {
	// contains filtered or unexported fields
}

func NewCborWriter

func NewCborWriter(w io.Writer) *CborWriter

func (*CborWriter) CborWriteHeader

func (cw *CborWriter) CborWriteHeader(t byte, l uint64) error

func (*CborWriter) SetWriter

func (cw *CborWriter) SetWriter(w io.Writer)

func (*CborWriter) Write

func (cw *CborWriter) Write(p []byte) (n int, err error)

func (*CborWriter) WriteMajorTypeHeader

func (cw *CborWriter) WriteMajorTypeHeader(t byte, l uint64) error

func (*CborWriter) WriteString

func (cw *CborWriter) WriteString(s string) (int, error)

type Deferred

type Deferred struct {
	Raw []byte
}

func (*Deferred) MarshalCBOR

func (d *Deferred) MarshalCBOR(w io.Writer) error

func (*Deferred) UnmarshalCBOR

func (d *Deferred) UnmarshalCBOR(br io.Reader) (err error)

type Field

type Field struct {
	Name    string
	MapKey  string
	Pointer bool
	Type    reflect.Type
	Pkg     string
	Const   *string

	OmitEmpty   bool
	Optional    bool
	PreserveNil bool
	IterLabel   string

	MaxLen int
}

func (Field) ElemName

func (f Field) ElemName() string

func (Field) EmptyVal

func (f Field) EmptyVal() (string, error)

func (Field) IsArray

func (f Field) IsArray() bool

func (Field) Len

func (f Field) Len() int

func (Field) TypeName

func (f Field) TypeName() string

type Gen

type Gen struct {
	MaxArrayLength  int // Default: 8192 (MaxLength)
	MaxByteLength   int // Default: 2<<20 (ByteArrayMaxLen)
	MaxStringLength int // Default: 8192 (MaxLength)

	// Write output file in order of type names
	SortTypeNames bool
}

Gen is a configurable code generator for CBOR types. Use this instead of the convenience functions to have more control over the generated code.

func (Gen) GenMapEncodersForType

func (g Gen) GenMapEncodersForType(gti *GenTypeInfo, w io.Writer) error

Generates 'tuple representation' cbor encoders for the given type

func (Gen) GenTupleEncodersForType

func (g Gen) GenTupleEncodersForType(gti *GenTypeInfo, w io.Writer) error

Generates 'tuple representation' cbor encoders for the given type

func (Gen) PrintHeaderAndUtilityMethods

func (g Gen) PrintHeaderAndUtilityMethods(w io.Writer, pkg string, typeInfos []*GenTypeInfo) error

func (Gen) WriteMapEncodersToFile

func (g Gen) WriteMapEncodersToFile(fname, pkg string, types ...interface{}) error

WriteMapFileEncodersToFile generates map backed MarshalCBOR and UnmarshalCBOR implementations for the given types in the specified file, with the specified package name.

The MarshalCBOR and UnmarshalCBOR implementations will marshal/unmarshal each type's fields as a map of field names to field values.

func (Gen) WriteTupleEncodersToFile

func (g Gen) WriteTupleEncodersToFile(fname, pkg string, types ...interface{}) error

WriteTupleFileEncodersToFile generates array backed MarshalCBOR and UnmarshalCBOR implementations for the given types in the specified file, with the specified package name.

The MarshalCBOR and UnmarshalCBOR implementations will marshal/unmarshal each type's fields as a fixed-length CBOR array of field values.

type GenTypeInfo

type GenTypeInfo struct {
	Name                string
	Fields              []Field
	MandatoryFieldCount int
	Transparent         bool
}

func ParseTypeInfo

func ParseTypeInfo(itype interface{}) (*GenTypeInfo, error)

func (*GenTypeInfo) Imports

func (gti *GenTypeInfo) Imports() []Import

func (GenTypeInfo) MapHeader

func (gti GenTypeInfo) MapHeader() []byte

func (GenTypeInfo) MapHeaderAsByteString

func (gti GenTypeInfo) MapHeaderAsByteString() string

func (*GenTypeInfo) MaxMapKeyLength added in v0.3.0

func (gti *GenTypeInfo) MaxMapKeyLength() int

func (GenTypeInfo) TupleHeader

func (gti GenTypeInfo) TupleHeader() []byte

func (GenTypeInfo) TupleHeaderAsByteString

func (gti GenTypeInfo) TupleHeaderAsByteString() string

type Import

type Import struct {
	Name, PkgPath string
}

func ImportsForType

func ImportsForType(currPkg string, t reflect.Type) []Import

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
JackTT - Gopher 🇻🇳