Documentation
¶
Overview ¶
Package codegen provides code generation for dynamic SSZ types.
Index ¶
- Constants
- Variables
- func ParseTags(tag string) ([]ssztypes.SszTypeHint, []ssztypes.SszSizeHint, []ssztypes.SszMaxSizeHint, ...)
- type CodeGenerator
- func (cg *CodeGenerator) BuildFile(fileName string, opts ...CodeGeneratorOption)
- func (cg *CodeGenerator) Generate() error
- func (cg *CodeGenerator) GenerateToMap() (map[string]string, error)
- func (cg *CodeGenerator) SetAnnotationResolver(resolver func(types.Type) string)
- func (cg *CodeGenerator) SetHeaderTemplate(template string) error
- func (cg *CodeGenerator) SetPackageName(packageName string) error
- func (cg *CodeGenerator) Warnings() []string
- type CodeGeneratorFileOptions
- type CodeGeneratorOption
- func WithCreateDecoderFn() CodeGeneratorOption
- func WithCreateEncoderFn() CodeGeneratorOption
- func WithCreateLegacyFn() CodeGeneratorOption
- func WithExtendedTypes() CodeGeneratorOption
- func WithGoTypesType(t types.Type, typeOpts ...CodeGeneratorOption) CodeGeneratorOption
- func WithGoTypesViewTypes(viewTypes ...types.Type) CodeGeneratorOption
- func WithMaxSizeHints(hints []ssztypes.SszMaxSizeHint) CodeGeneratorOption
- func WithNoFastSsz() CodeGeneratorOption
- func WithNoHashTreeRoot() CodeGeneratorOption
- func WithNoMarshalSSZ() CodeGeneratorOption
- func WithNoSizeSSZ() CodeGeneratorOption
- func WithNoUnmarshalSSZ() CodeGeneratorOption
- func WithRecursionDepth(depth int) CodeGeneratorOption
- func WithReflectType(t reflect.Type, typeOpts ...CodeGeneratorOption) CodeGeneratorOption
- func WithReflectViewTypes(viewTypes ...reflect.Type) CodeGeneratorOption
- func WithSizeHints(hints []ssztypes.SszSizeHint) CodeGeneratorOption
- func WithTypeHints(hints []ssztypes.SszTypeHint) CodeGeneratorOption
- func WithViewOnly() CodeGeneratorOption
- func WithoutDynamicExpressions() CodeGeneratorOption
- type CodeGeneratorOptions
- type CodeGeneratorTypeOption
- type CodeGeneratorTypeOptions
- type CodegenInfo
- type Parser
- type TypeImport
- type TypePrinter
- func (p *TypePrinter) AddAlias(path, alias string)
- func (p *TypePrinter) AddImport(path, alias string) string
- func (p *TypePrinter) Aliases() map[string]string
- func (p *TypePrinter) Imports() map[string]string
- func (p *TypePrinter) InnerTypeString(t *ssztypes.TypeDescriptor) string
- func (p *TypePrinter) InnerViewTypeString(t *ssztypes.TypeDescriptor) string
- func (p *TypePrinter) ReserveNames(names []string)
- func (p *TypePrinter) TypeString(t *ssztypes.TypeDescriptor) string
- func (p *TypePrinter) TypeStringWithoutTracking(t *ssztypes.TypeDescriptor, viewType bool) string
- func (p *TypePrinter) ViewTypeString(t *ssztypes.TypeDescriptor, ensurePointer bool) string
Constants ¶
const DefaultHeaderTemplate = "// Code generated by dynamic-ssz. DO NOT EDIT.\n" +
"// Hash: {hash}\n" +
"// Version: {version} (https://github.com/pk910/dynamic-ssz)\n"
DefaultHeaderTemplate is the header comment emitted at the top of generated files when no custom template is set via SetHeaderTemplate. The {hash} and {version} placeholders are substituted during generation.
Variables ¶
var BuildCommit = ""
BuildCommit is the git commit hash, set via ldflags at build time.
var BuildTime = ""
BuildTime is the build timestamp, set via ldflags at build time.
var ErrInvalidHeaderTemplate = errors.New("invalid header template")
ErrInvalidHeaderTemplate reports a header template that would corrupt the generated files. SetHeaderTemplate returns an error wrapping it and keeps the current template.
var Version = "1.4.0"
Version is the release version of the dynamic-ssz library.
Functions ¶
func ParseTags ¶ added in v1.3.0
func ParseTags(tag string) ([]ssztypes.SszTypeHint, []ssztypes.SszSizeHint, []ssztypes.SszMaxSizeHint, error)
ParseTags parses SSZ annotations from a string in struct tag format. This is a convenience re-export of ssztypes.ParseTags for backward compatibility with code that imports codegen.ParseTags.
Types ¶
type CodeGenerator ¶
type CodeGenerator struct {
// contains filtered or unexported fields
}
CodeGenerator manages batch generation of SSZ methods for multiple types across multiple files.
The CodeGenerator provides a high-level interface for generating SSZ encoding/decoding methods for Go types. It supports generating multiple files with different configurations, each containing optimized SSZ methods for specified types.
Key capabilities:
- Batch generation of multiple files with different type sets
- Per-file and per-type configuration options
- Automatic dependency analysis and import management
- Support for both reflection-based and compile-time type analysis
- Integration with dynamic-ssz specifications and size expressions
The generator uses a DynSsz instance for type analysis and descriptor creation, ensuring that generated code is compatible with the runtime library's type system.
Fields:
- files: Internal list of file generation requests
- dynSsz: DynSsz instance used for type analysis and descriptor generation
Typical workflow:
- Create generator with NewCodeGenerator()
- Add files with BuildFile()
- Generate code with Generate() or GenerateToMap()
func NewCodeGenerator ¶
func NewCodeGenerator(typeCache *ssztypes.TypeCache) *CodeGenerator
NewCodeGenerator creates a new code generator instance.
The generator analyzes types on caches of its own, with spec resolution disabled: spec expressions are emitted for the generated code to resolve at runtime, so the caller's spec values play no part in the output. The cache argument is read-only; only its extended-types setting is taken, so a cache from an instance built with WithExtendedTypes widens the reflect path like the instance itself. Passing a live instance's cache is safe.
Parameters:
- typeCache: Cache whose extended-types setting is inherited; nil for the default.
Returns:
- *CodeGenerator: A new code generator ready to accept file generation requests
Example:
// Inherit the extended-types setting of an instance cg := NewCodeGenerator(dynSsz.GetTypeCache()) // Create with default configuration cg := NewCodeGenerator(nil)
func (*CodeGenerator) BuildFile ¶
func (cg *CodeGenerator) BuildFile(fileName string, opts ...CodeGeneratorOption)
BuildFile adds a file generation request to the code generator.
This method configures a single output file with its associated types and generation options. The file will be generated when Generate() or GenerateToMap() is called. All types specified in the options must belong to the same Go package.
The method processes all provided options to build the final configuration for the file, including resolving type-specific options and validating type compatibility.
Parameters:
- fileName: The output file path for the generated code
- opts: Variable number of options controlling file generation behavior
Example:
cg.BuildFile("ethereum_types_generated.go",
WithReflectType(reflect.TypeOf((*BeaconBlock)(nil)).Elem()),
WithReflectType(reflect.TypeOf((*BeaconState)(nil)).Elem(),
WithNoHashTreeRoot(), // Skip hash tree root for this type only
),
WithCreateLegacyFn(), // Generate legacy fastssz methods
WithSizeHints(sizeHints), // Apply size constraints
)
func (*CodeGenerator) Generate ¶
func (cg *CodeGenerator) Generate() error
Generate processes all file generation requests and writes the results to disk.
This method is a convenience wrapper around GenerateToMap() that automatically writes all generated files to their specified paths. It handles directory creation as needed and ensures proper file permissions.
The method will create any necessary intermediate directories and write each generated file with standard Go source file permissions (0644).
Returns:
- error: An error if generation or file writing fails due to:
- Any errors from GenerateToMap()
- File system permission issues
- Directory creation failures
- File write failures
Example:
cg := NewCodeGenerator(dynSsz)
cg.BuildFile("./generated/types.go", WithReflectType(myType))
cg.BuildFile("./generated/helpers.go", WithReflectType(anotherType))
err := cg.Generate()
if err != nil {
log.Fatal("Failed to generate files:", err)
}
func (*CodeGenerator) GenerateToMap ¶
func (cg *CodeGenerator) GenerateToMap() (map[string]string, error)
GenerateToMap generates code for all requested files and returns the results as a map.
This method processes all file generation requests added via BuildFile() and produces the complete Go source code for each file. The returned map contains the file names as keys and the generated source code as values.
The generation process includes:
- Type analysis and descriptor creation for all specified types
- Dependency resolution and import management
- SSZ method generation (marshal, unmarshal, size, hash tree root)
- Go source code formatting and organization
- Cross-reference resolution for types that reference each other
Returns:
- map[string]string: Map of file names to their generated Go source code
- error: An error if generation fails due to:
- Type analysis errors
- Package path conflicts
- Invalid type configurations
- Code generation errors
Example:
cg := NewCodeGenerator(dynSsz)
cg.BuildFile("types.go", WithReflectType(myType))
cg.BuildFile("more_types.go", WithReflectType(anotherType))
files, err := cg.GenerateToMap()
if err != nil {
log.Fatal(err)
}
for fileName, code := range files {
fmt.Printf("Generated %s:\n%s\n", fileName, code)
}
func (*CodeGenerator) SetAnnotationResolver ¶ added in v1.3.2
func (cg *CodeGenerator) SetAnnotationResolver(resolver func(types.Type) string)
SetAnnotationResolver registers a resolver that returns the merged ssz annotation tag for a go/types type (or ""). The code generator passes it to the parser so referenced, fully-delegated types declaring ssz-static are shallow-built instead of traversed. Typically backed by the source scan that also feeds per-type Annotate options.
func (*CodeGenerator) SetHeaderTemplate ¶ added in v1.4.0
func (cg *CodeGenerator) SetHeaderTemplate(template string) error
SetHeaderTemplate sets a custom header comment template for generated files.
The template replaces the default file header (DefaultHeaderTemplate). The placeholders {hash} and {version} are substituted during generation with the combined SSZ layout hash of the file's types (see TypeDescriptor.GetTypeHash) and the dynamic-ssz library version.
Every non-empty line of the template must be a `//` line comment — anything else would make the generated files invalid Go. Such a template is rejected with an error wrapping ErrInvalidHeaderTemplate and the current template is kept; check for it with errors.Is.
Any other returned error is a non-fatal warning: it is returned when the template's first line does not match the Go convention for machine-generated files (`^// Code generated .* DO NOT EDIT\.$`), which tooling relies on to recognize and skip generated code. The template is applied in that case, so callers may log the warning and continue.
Example:
cg := NewCodeGenerator(nil)
if warn := cg.SetHeaderTemplate("// Code generated by mytool. DO NOT EDIT.\n// Hash: {hash}\n"); warn != nil {
log.Printf("Warning: %v", warn)
}
func (*CodeGenerator) SetPackageName ¶ added in v1.1.1
func (cg *CodeGenerator) SetPackageName(packageName string) error
SetPackageName sets the package name for the code generator.
This method sets the package name for the code generator.
Parameters:
- packageName: The package name to set
Returns:
- *CodeGenerator: The code generator instance
Example:
cg := NewCodeGenerator(dynSsz)
cg.SetPackageName("my_package")
cg.BuildFile("types.go", WithReflectType(reflect.TypeOf((*MyStruct)(nil)).Elem()))
cg.Generate()
func (*CodeGenerator) Warnings ¶ added in v1.4.0
func (cg *CodeGenerator) Warnings() []string
Warnings returns the non-fatal problems found while generating, sorted for a stable order. Generation succeeds regardless; callers are expected to surface them so the author can act on them.
type CodeGeneratorFileOptions ¶
type CodeGeneratorFileOptions struct {
Package string
PackageName string
Types []*CodeGeneratorTypeOptions
}
CodeGeneratorFileOptions contains the configuration for generating a complete Go source file.
This structure represents all the information needed to generate a single Go file containing SSZ methods for multiple types. It includes package information and the complete list of types to be included in the file with their individual configurations.
File Structure:
- Package: The Go package path for the generated file
- Types: All types to include in the file with their resolved configurations
The generator ensures all types belong to the same package and handles import management, method generation, and proper Go source code formatting for the entire file.
type CodeGeneratorOption ¶
type CodeGeneratorOption func(*CodeGeneratorOptions)
CodeGeneratorOption is a functional option for configuring code generation behavior.
This type follows the functional options pattern, allowing callers to customize various aspects of the code generation process through composable option functions. Options can control which methods are generated, performance optimizations, and compatibility settings.
Example usage:
cg := NewCodeGenerator(dynSsz)
cg.BuildFile("generated.go",
WithNoMarshalSSZ(), // Skip marshal method generation
WithCreateLegacyFn(), // Generate legacy fastssz methods
WithoutDynamicExpressions(), // Use static sizes only
)
func WithCreateDecoderFn ¶ added in v1.2.0
func WithCreateDecoderFn() CodeGeneratorOption
WithCreateDecoderFn creates an option to generate decoder functions.
When this option is enabled, the generator will generate decoder functions for the types.
Returns:
- CodeGeneratorOption: A functional option that enables decoder function generation
func WithCreateEncoderFn ¶ added in v1.2.0
func WithCreateEncoderFn() CodeGeneratorOption
WithCreateEncoderFn creates an option to generate encoder functions.
When this option is enabled, the generator will generate encoder functions for the types.
Returns:
- CodeGeneratorOption: A functional option that enables encoder function generation
func WithCreateLegacyFn ¶
func WithCreateLegacyFn() CodeGeneratorOption
WithCreateLegacyFn creates an option to generate legacy fastssz-compatible methods.
When this option is enabled, the generator creates additional methods that match the fastssz library interface, using a global DynSsz instance for compatibility. These methods include:
- MarshalSSZ() ([]byte, error)
- UnmarshalSSZ([]byte) error
- SizeSSZ() int
- HashTreeRoot() ([32]byte, error)
This option is essential for:
- Drop-in replacement for fastssz-generated code
- Gradual migration from fastssz to dynamic-ssz
- Interoperability with existing codebases expecting fastssz interfaces
- Maintaining backward compatibility in public APIs
The legacy methods delegate to the dynamic methods using the global DynSsz instance, so they inherit all dynamic sizing and expression capabilities.
Returns:
- CodeGeneratorOption: A functional option that enables legacy method generation
func WithExtendedTypes ¶ added in v1.2.2
func WithExtendedTypes() CodeGeneratorOption
WithExtendedTypes creates an option to generate code with extended types.
When this option is enabled, the generator will generate code with extended types.
Returns:
- CodeGeneratorOption: A functional option that enables extended type generation
func WithGoTypesType ¶
func WithGoTypesType(t types.Type, typeOpts ...CodeGeneratorOption) CodeGeneratorOption
WithGoTypesType creates an option to include a specific type using compile-time type analysis.
This function adds a type to the generation list using Go's types package for compile-time type analysis. This approach is more powerful than reflection as it can analyze types that may not be available at runtime and provides richer type information for complex scenarios.
This method is typically used in code analysis tools, compilers, or advanced code generation scenarios where you're working with the Go AST or type checker.
Parameters:
- t: The types.Type to include in code generation (from go/types package)
- typeOpts: Optional type-specific generation options that override base settings
Returns:
- CodeGeneratorOption: A functional option that adds the type to the generation list
Example:
// In a compiler or analysis tool context
var structType *types.Named = ... // obtained from type analysis
WithGoTypesType(structType,
WithCreateLegacyFn(),
WithoutDynamicExpressions(),
)
The type must be a declared named type; an alias cannot carry methods and is refused when go/types materialises it as one. Under Go 1.22, where go/types resolves an alias to its target before analysis, the caller has to make that distinction itself (dynssz-gen checks the declaration).
func WithGoTypesViewTypes ¶ added in v1.3.0
func WithGoTypesViewTypes(viewTypes ...types.Type) CodeGeneratorOption
WithGoTypesViewTypes creates an option to specify view types for data+views mode.
This option specifies view types that share the same SSZ schema as the data type. When code is generated, both regular data methods and view-compatible methods will be created, allowing the data type's methods to work with these view types.
Parameters:
- viewTypes: View types that share the same SSZ schema as the data type
Returns:
- CodeGeneratorOption: A functional option that sets view types
Example:
WithGoTypesType(dataType,
WithGoTypesViewTypes(viewType1, viewType2),
)
func WithMaxSizeHints ¶
func WithMaxSizeHints(hints []ssztypes.SszMaxSizeHint) CodeGeneratorOption
WithMaxSizeHints creates an option to provide maximum size constraints for variable-length types.
Maximum size hints define upper bounds for variable-length types like slices and lists. These constraints are crucial for:
- Memory allocation optimization
- Security bounds checking
- SSZ encoding validation
- Buffer pre-allocation in performance-critical code
The hints help generate efficient code that can pre-allocate appropriate buffer sizes and validate data doesn't exceed specified limits during encoding/decoding.
Parameters:
- hints: Array of maximum size hints, typically corresponding to nested type levels
Returns:
- CodeGeneratorOption: A functional option that applies the provided maximum size hints
Example:
WithMaxSizeHints([]dynssz.SszMaxSizeHint{
{Size: 1048576, Expr: "MAX_VALIDATORS_PER_COMMITTEE"},
})
func WithNoFastSsz ¶ added in v1.1.1
func WithNoFastSsz() CodeGeneratorOption
WithNoFastSsz creates an option to skip generating fast ssz generated methods.
When this option is enabled, the generator will not use any fast ssz generated methods for static types.
Returns:
- CodeGeneratorOption: A functional option that disables fast ssz generated method generation
func WithNoHashTreeRoot ¶
func WithNoHashTreeRoot() CodeGeneratorOption
WithNoHashTreeRoot creates an option to skip generating HashTreeRoot and HashTreeRootDyn methods.
When this option is applied, the code generator will not produce hash tree root calculation methods for the target types. This is useful when:
- Hash tree roots are not needed for the application
- Custom hashing logic is implemented elsewhere
- Optimizing for code size when cryptographic commitments aren't required
Note that hash tree roots are essential for many blockchain and cryptographic applications, particularly in Ethereum consensus where they're used for Merkle proofs and state roots.
Returns:
- CodeGeneratorOption: A functional option that disables hash tree root method generation
func WithNoMarshalSSZ ¶
func WithNoMarshalSSZ() CodeGeneratorOption
WithNoMarshalSSZ creates an option to skip generating MarshalSSZTo and MarshalSSZDyn methods.
When this option is applied, the code generator will not produce any marshaling methods for the target types. This is useful when:
- Types only need to be deserialized (read-only scenarios)
- Custom marshaling logic is implemented elsewhere
- Reducing generated code size for specific use cases
Note that skipping marshal methods may limit interoperability with some SSZ libraries that expect the full method interface to be present.
Returns:
- CodeGeneratorOption: A functional option that disables marshal method generation
func WithNoSizeSSZ ¶
func WithNoSizeSSZ() CodeGeneratorOption
WithNoSizeSSZ creates an option to skip generating SizeSSZ and SizeSSZDyn methods.
When this option is applied, the code generator will not produce size calculation methods for the target types. This is useful when:
- Size calculation is not needed for the application
- Custom size calculation logic is implemented elsewhere
- Optimizing for code size in constrained environments
Note that many SSZ operations benefit from accurate size pre-calculation for buffer allocation, so this option should be used carefully.
Returns:
- CodeGeneratorOption: A functional option that disables size method generation
func WithNoUnmarshalSSZ ¶
func WithNoUnmarshalSSZ() CodeGeneratorOption
WithNoUnmarshalSSZ creates an option to skip generating UnmarshalSSZ and UnmarshalSSZDyn methods.
When this option is applied, the code generator will not produce any unmarshaling methods for the target types. This is useful when:
- Types are only created programmatically (write-only scenarios)
- Custom unmarshaling logic is implemented elsewhere
- Reducing generated code size for specific use cases
Note that skipping unmarshal methods may limit interoperability with some SSZ libraries that expect the full method interface to be present.
Returns:
- CodeGeneratorOption: A functional option that disables unmarshal method generation
func WithRecursionDepth ¶ added in v1.4.0
func WithRecursionDepth(depth int) CodeGeneratorOption
WithRecursionDepth sets how deep a recursive type may nest before the generated methods fail with sszutils.ErrMaxDepthExceeded. A non-positive value selects defaultRecursionDepth.
The bound exists because stack exhaustion is fatal in Go: the runtime aborts the process and recover() cannot contain it, so a server could not isolate the failure to the request that caused it. Each level of a recursive type costs only a handful of wire bytes, so a small payload can otherwise declare nesting deep enough to exhaust the stack.
It applies to recursive cycles only: the count advances one level per cycle member entered — generated or inlined — so a trip around a cycle costs as many levels as the cycle has structural members, the same rule the reflection engine applies. A type that merely sits above a cycle threads the depth through unchanged; a type with no cycle beneath it is unaffected, as is the code emitted for it.
The value is baked into the generated code, so changing it requires regeneration. The reflection engine carries its own bound; see dynssz.WithMaxNestingDepth.
A recursive type reached through a view costs two stack frames per level rather than one: a view dispatcher returns a closure, which has nowhere to take a depth argument, so the closure supplies it and becomes a frame of its own. The bound still counts nesting levels, so the reachable depth is the same -- only the stack used getting there differs.
func WithReflectType ¶
func WithReflectType(t reflect.Type, typeOpts ...CodeGeneratorOption) CodeGeneratorOption
WithReflectType creates an option to include a specific type using runtime reflection.
This function adds a type to the generation list using Go's reflection system to analyze the type structure. It's the most common way to specify types for generation when you have access to the actual Go types at runtime.
The function accepts additional type-specific options that will be applied only to this type, allowing fine-grained control over generation behavior per type.
Parameters:
- t: The reflect.Type to include in code generation (typically obtained via reflect.TypeOf)
- typeOpts: Optional type-specific generation options that override base settings
Returns:
- CodeGeneratorOption: A functional option that adds the type to the generation list
Example:
// Add a type with default options
WithReflectType(reflect.TypeOf((*MyStruct)(nil)).Elem()),
// Add a type with specific options
WithReflectType(reflect.TypeOf((*AnotherStruct)(nil)).Elem(),
WithNoHashTreeRoot(), // Skip hash tree root for this type only
WithCreateLegacyFn(), // But include legacy methods
),
A referenced static type from another package that delegates to its own generated methods is sized with the type cache's specs at generation time; a width that depends on a spec value is baked for that preset. dynssz-gen reads such a width from the type's sizer at run time instead.
func WithReflectViewTypes ¶ added in v1.3.0
func WithReflectViewTypes(viewTypes ...reflect.Type) CodeGeneratorOption
WithReflectViewTypes creates an option to specify view types for data+views mode.
This option specifies view types that share the same SSZ schema as the data type. When code is generated, both regular data methods and view-compatible methods will be created, allowing the data type's methods to work with these view types.
Parameters:
- viewTypes: View types that share the same SSZ schema as the data type
Returns:
- CodeGeneratorOption: A functional option that sets view types
Example:
WithReflectType(dataType,
WithReflectViewTypes(viewType1, viewType2),
)
func WithSizeHints ¶
func WithSizeHints(hints []ssztypes.SszSizeHint) CodeGeneratorOption
WithSizeHints creates an option to provide size constraints for dynamic types.
Size hints guide the code generator in handling types with variable or dynamic sizes. They can specify exact sizes, dynamic sizing expressions, or size calculation formulas that reference runtime specification values.
Common use cases:
- Fixed-size arrays where size depends on configuration: []Item with size "SLOTS_PER_EPOCH"
- Variable-size containers with known constraints
- Performance optimization by pre-calculating buffer sizes
Parameters:
- hints: Array of size hints, typically corresponding to nested type levels
Returns:
- CodeGeneratorOption: A functional option that applies the provided size hints
Example:
WithSizeHints([]dynssz.SszSizeHint{
{Size: 8192, Expr: "SLOTS_PER_HISTORICAL_ROOT"},
})
func WithTypeHints ¶
func WithTypeHints(hints []ssztypes.SszTypeHint) CodeGeneratorOption
WithTypeHints creates an option to provide explicit SSZ type mappings for ambiguous Go types.
Type hints resolve ambiguity when Go types can be mapped to multiple SSZ types. This is particularly important for:
- Generic types that could be containers, lists, or vectors
- Interface types that need concrete SSZ representations
- Custom types that implement multiple SSZ-compatible interfaces
- Ensuring consistent type interpretation across different contexts
The hints allow precise control over how the generator interprets and encodes complex type hierarchies, ensuring compatibility with dynamic expressions and runtime specifications.
Parameters:
- hints: Array of type hints mapping Go types to specific SSZ type interpretations
Returns:
- CodeGeneratorOption: A functional option that applies the provided type hints
Example:
WithTypeHints([]dynssz.SszTypeHint{
{Type: dynssz.SszListType}, // Force slice to be treated as list not vector
{Type: dynssz.SszContainerType}, // Force struct to be treated as container
})
func WithViewOnly ¶ added in v1.3.0
func WithViewOnly() CodeGeneratorOption
WithViewOnly creates an option to generate only view methods, not data methods.
When this option is set, the generator will only produce view-compatible methods (like MarshalSSZToView, UnmarshalSSZView, etc.) and skip generating standard data methods (MarshalSSZTo, UnmarshalSSZ, etc.).
This is useful when you have a type that is only used as a view for another data type and doesn't need its own data serialization methods.
Returns:
- CodeGeneratorOption: A functional option that enables view-only mode
Example:
WithGoTypesType(viewType,
WithViewOnly(),
WithGoTypesViewTypes(otherViewType), // additional views
)
func WithoutDynamicExpressions ¶
func WithoutDynamicExpressions() CodeGeneratorOption
WithoutDynamicExpressions creates an option to generate static-only code that ignores dynamic expressions.
When this option is enabled, the generator produces highly optimized code that uses only static, compile-time known sizes and completely ignores any dynamic size expressions. This results in:
- Maximum performance characteristics for the default/known preset
- Smaller generated code size
- No runtime expression evaluation overhead
- Compile-time size validation
Trade-offs:
- Loss of flexibility for different presets/specifications
- Cannot handle runtime size variations
- Falls back to slower reflection-based methods for dynamic cases
- Not compatible with types that require dynamic expression evaluation
This option is ideal for production deployments where:
- The specification preset is known at compile time
- Maximum performance is prioritized over flexibility
- Code size optimization is important
Returns:
- CodeGeneratorOption: A functional option that enables static-only code generation
type CodeGeneratorOptions ¶
type CodeGeneratorOptions struct {
NoMarshalSSZ bool
NoUnmarshalSSZ bool
NoSizeSSZ bool
NoHashTreeRoot bool
CreateLegacyFn bool
CreateEncoderFn bool
CreateDecoderFn bool
WithoutDynamicExpressions bool
NoFastSsz bool
ExtendedTypes bool
RecursionDepth int
SizeHints []ssztypes.SszSizeHint
MaxSizeHints []ssztypes.SszMaxSizeHint
TypeHints []ssztypes.SszTypeHint
Types []CodeGeneratorTypeOption
// View support options (type-specific)
ViewGoTypesTypes []types.Type // View types for data+views mode (compile-time)
ViewReflectTypes []reflect.Type // View types for data+views mode (runtime)
ViewOnly bool // Only generate view methods, not data methods
// contains filtered or unexported fields
}
CodeGeneratorOptions contains all configuration settings for code generation.
This structure controls every aspect of the code generation process, from which methods to generate to performance optimizations and compatibility modes. It serves as the central configuration hub for customizing generated SSZ code to meet specific requirements and constraints.
Method Generation Controls:
- NoMarshalSSZ: Skip generating MarshalSSZTo and MarshalSSZDyn methods
- NoUnmarshalSSZ: Skip generating UnmarshalSSZ and UnmarshalSSZDyn methods
- NoSizeSSZ: Skip generating SizeSSZ and SizeSSZDyn methods
- NoHashTreeRoot: Skip generating HashTreeRoot and HashTreeRootDyn methods
Compatibility and Performance Options:
- CreateLegacyFn: Generate legacy fastssz-compatible methods (MarshalSSZ, etc.)
- WithoutDynamicExpressions: Generate static-only code, ignoring dynamic expressions
- NoFastSsz: Disable use of fastssz optimizations in generated code
Type Configuration:
- SizeHints: Static and dynamic size constraints for types
- MaxSizeHints: Maximum size limits for variable-length types
- TypeHints: Explicit SSZ type mappings for ambiguous Go types
- Types: Specific types to include in generation with per-type options
type CodeGeneratorTypeOption ¶
type CodeGeneratorTypeOption struct {
ReflectType reflect.Type
GoTypesType types.Type
Opts []CodeGeneratorOption
}
CodeGeneratorTypeOption specifies a type to include in code generation with its specific options.
This structure allows fine-grained control over individual types within a generation request. Each type can have its own set of generation options that override or extend the base configuration. This enables scenarios like generating different method sets for different types within the same output file.
Type Specification (exactly one must be provided):
- ReflectType: Go reflection-based type representation (runtime type)
- GoTypesType: Go types package representation (compile-time type analysis)
Configuration:
- Opts: Type-specific options that will be applied in addition to base options
View support is configured via options:
- WithGoTypesViewTypes() / WithReflectViewTypes(): Specify view types for data+views mode
- WithViewOnly(): Only generate view methods, not data methods
Example:
// Generate type with view support
WithReflectType(reflect.TypeOf((*MyStruct)(nil)).Elem(),
WithReflectViewTypes(reflect.TypeOf((*MyView)(nil)).Elem()),
),
// Generate view-only type
WithReflectType(reflect.TypeOf((*ViewType)(nil)).Elem(),
WithViewOnly(),
WithReflectViewTypes(reflect.TypeOf((*OtherView)(nil)).Elem()),
),
type CodeGeneratorTypeOptions ¶
type CodeGeneratorTypeOptions struct {
ReflectType reflect.Type
GoTypesType types.Type
TypeName string
Options CodeGeneratorOptions
Descriptor *ssztypes.TypeDescriptor
// View types for data+views mode
ViewGoTypesTypes []types.Type
ViewReflectTypes []reflect.Type
ViewDescriptors []*ssztypes.TypeDescriptor
// IsViewOnly marks this type as view-only (only generates view methods)
IsViewOnly bool
}
CodeGeneratorTypeOptions contains the resolved configuration for a specific type during generation.
This structure represents the final, processed configuration for a type after all options have been applied and type analysis has been completed. It serves as the authoritative source of information about how a type should be generated, including its resolved type descriptor and effective generation options.
Type Information:
- ReflectType: Runtime reflection type representation
- GoTypesType: Compile-time type analysis representation
- TypeName: Resolved type name for code generation
View Support:
- ViewGoTypesTypes: Resolved view types for data+views mode
- ViewReflectTypes: Resolved view types for data+views mode
- IsViewOnly: Whether this is a view-only type
- SchemaDescriptor: Schema type descriptor for view-only mode
Generation Configuration:
- Options: Final resolved options after applying base and type-specific settings
- Descriptor: Analyzed SSZ type descriptor containing encoding/decoding metadata
type CodegenInfo ¶
CodegenInfo contains type information specific to code generation from go/types analysis.
This structure bridges the gap between compile-time type analysis (using go/types) and runtime code generation. It stores type information that was obtained through static analysis rather than runtime reflection, enabling more sophisticated code generation scenarios.
Fields:
- Type: The types.Type from go/types package representing the analyzed type
- SchemaType: The types.Type representing the schema structure (may differ from Type for view descriptors)
This information is embedded in TypeDescriptor.CodegenInfo to provide access to compile-time type information during code generation.
type Parser ¶
type Parser struct {
CompatFlags map[string]ssztypes.SszCompatFlag
ExtendedTypes bool
// AnnotationResolver returns the merged ssz annotation tag for a type (or "").
// It lets the parser read a referenced, fully-delegated type's ssz-static
// declaration so its subtree need not be traversed or validated.
AnnotationResolver func(types.Type) string
// NoDelegation disables the shallow-build shortcut for fully-delegated
// ssz-static types, forcing their subtree to be traversed. Code generated
// without dynamic expressions must never call a delegated *Dyn method, so
// such a type is inlined from its structure instead — which requires the
// traversed descriptor.
NoDelegation bool
// contains filtered or unexported fields
}
Parser provides compile-time type analysis for SSZ code generation.
The Parser analyzes Go types using the go/types package to create TypeDescriptors suitable for code generation. Unlike runtime reflection, this approach can analyze types that may not be available at runtime and provides richer type information for complex code generation scenarios.
Key capabilities:
- Compile-time type analysis using go/types
- SSZ type inference and validation
- Struct tag parsing for SSZ annotations
- Interface compatibility checking
- Type descriptor caching for performance
The parser handles all SSZ-compatible types including basic types, containers, vectors, lists, and custom types like unions and type wrappers.
Fields:
- cache: Type descriptor cache to avoid recomputing analysis for the same types
func NewParser ¶
func NewParser() *Parser
NewParser creates a new compile-time type parser for code generation.
The parser is initialized with an empty cache and is ready to analyze types using the go/types package. The parser can be reused across multiple type analysis operations to benefit from caching.
Returns:
- *Parser: A new parser instance ready for type analysis
Example:
parser := NewParser()
desc, err := parser.GetTypeDescriptor(myGoType, nil, nil, nil)
if err != nil {
log.Fatal("Type analysis failed:", err)
}
func (*Parser) GetTypeDescriptor ¶
func (p *Parser) GetTypeDescriptor(typ types.Type, typeHints []ssztypes.SszTypeHint, sizeHints []ssztypes.SszSizeHint, maxSizeHints []ssztypes.SszMaxSizeHint) (*ssztypes.TypeDescriptor, error)
GetTypeDescriptor analyzes a Go type and creates an SSZ type descriptor for code generation.
This method is the main entry point for type analysis. It examines the provided go/types.Type and creates a comprehensive TypeDescriptor containing all information needed for SSZ code generation, including size calculations, encoding strategies, and interface compatibility.
The analysis process includes:
- Type structure examination and validation
- SSZ type inference and mapping
- Size and constraint analysis from hints
- Interface compatibility checking
- Nested type analysis for containers and collections
Parameters:
- typ: The go/types.Type to analyze
- typeHints: Optional hints for explicit SSZ type mapping
- sizeHints: Optional size constraints and expressions
- maxSizeHints: Optional maximum size limits for variable-length types
Returns:
- *ssztypes.TypeDescriptor: Complete type descriptor for code generation
- error: An error if the type is incompatible with SSZ or analysis fails
Example:
parser := NewParser()
typeHints := []ssztypes.SszTypeHint{{Type: ssztypes.SszListType}}
sizeHints := []ssztypes.SszSizeHint{{Size: 1024}}
desc, err := parser.GetTypeDescriptor(structType, typeHints, sizeHints, nil)
if err != nil {
return fmt.Errorf("failed to analyze type: %w", err)
}
func (*Parser) GetTypeDescriptorWithSchema ¶ added in v1.3.0
func (p *Parser) GetTypeDescriptorWithSchema(dataType, schemaType types.Type, typeHints []ssztypes.SszTypeHint, sizeHints []ssztypes.SszSizeHint, maxSizeHints []ssztypes.SszMaxSizeHint) (*ssztypes.TypeDescriptor, error)
GetTypeDescriptorWithSchema analyzes Go types and creates an SSZ type descriptor with separate schema and data types.
This method supports fork-dependent SSZ schemas (view descriptors) where the schema type defines the SSZ layout while the data type holds the actual data. This allows different SSZ serializations of the same data based on the schema provided.
When dataType == schemaType, this behaves identically to GetTypeDescriptor. When they differ, the descriptor is built using schema's field definitions (names, tags, order) but code generation targets the data type's fields.
Parameters:
- dataType: The types.Type where actual data lives (runtime type)
- schemaType: The types.Type that defines SSZ layout (field order, tags, limits)
- typeHints: Optional hints for explicit SSZ type mapping
- sizeHints: Optional size constraints and expressions
- maxSizeHints: Optional maximum size limits for variable-length types
Returns:
- *ssztypes.TypeDescriptor: Complete type descriptor for code generation
- error: An error if the type is incompatible with SSZ or analysis fails
type TypeImport ¶
TypeImport represents an import declaration for generated code files.
This structure is used during code generation to track and organize import statements that need to be included in the generated Go files. It pairs import paths with their corresponding aliases to avoid naming conflicts and provide clean, readable generated code.
Fields:
- Alias: The alias name for the import (empty string means no alias)
- Path: The full import path (e.g., "github.com/pkg/errors")
type TypePrinter ¶
type TypePrinter struct {
CurrentPkg string
UseRune bool
// contains filtered or unexported fields
}
TypePrinter manages type name formatting and import tracking for code generation.
The TypePrinter provides intelligent type name formatting that handles package qualification, import management, and alias generation. It ensures that generated code has clean, readable type names while avoiding import conflicts.
Key capabilities:
- Automatic package qualification for types from other packages
- Import path tracking and alias generation
- Conflict resolution for import aliases
- Support for both reflection and go/types type representations
- Generic type name formatting with proper package path handling
Fields:
- CurrentPkg: The package path of the code being generated (types from this package are unqualified)
- imports: Map of import paths to their assigned aliases
- aliases: Map of import paths to their preferred aliases
- UseRune: Whether to prefer "rune" over "int32" in type names
func NewTypePrinter ¶
func NewTypePrinter(currentPkg string) *TypePrinter
NewTypePrinter creates a new type printer for the specified package.
The type printer is configured to generate type names relative to the specified current package. Types from the current package will be unqualified, while types from other packages will be properly qualified with import aliases.
Parameters:
- currentPkg: The Go package path of the code being generated
Returns:
- *TypePrinter: A new type printer ready for type formatting and import tracking
Example:
printer := NewTypePrinter("github.com/example/mypackage")
typeName := printer.TypeString(myTypeDescriptor) // Will qualify external types
func (*TypePrinter) AddAlias ¶
func (p *TypePrinter) AddAlias(path, alias string)
AddAlias sets a preferred alias for an import path.
This method establishes a preferred alias for a specific import path. When generating import statements, these preferred aliases will be used instead of automatically generated ones, providing consistent and predictable import formatting.
Parameters:
- path: The import path to set an alias for
- alias: The preferred alias to use for this import path
Example:
printer.AddAlias("github.com/pk910/dynamic-ssz", "dynssz")
// All references to dynamic-ssz types will use "dynssz" as the package qualifier
func (*TypePrinter) AddImport ¶
func (p *TypePrinter) AddImport(path, alias string) string
AddImport registers an import path with a preferred alias and returns the assigned alias.
This method adds an import path to the printer's import tracking system. If the path is already registered, it returns the existing alias. If the preferred alias conflicts with an existing import, it generates a unique alternative by appending numbers.
Parameters:
- path: The import path to register (e.g., "github.com/pkg/errors")
- alias: The preferred alias for the import (e.g., "errors")
Returns:
- string: The actual alias assigned to the import (may differ from preferred if conflicts occur)
Example:
alias := printer.AddImport("github.com/pkg/errors", "errors")
// alias == "errors" if no conflict, or "errors1", "errors2", etc. if conflicts exist
func (*TypePrinter) Aliases ¶
func (p *TypePrinter) Aliases() map[string]string
Aliases returns the map of import paths to their preferred aliases.
This method provides access to the preferred alias mappings that were set via AddAlias(). These aliases take precedence over automatically generated aliases when formatting import statements.
Returns:
- map[string]string: Map of import paths to their preferred aliases
func (*TypePrinter) Imports ¶
func (p *TypePrinter) Imports() map[string]string
Imports returns the map of import paths to their assigned aliases.
This method provides access to all import paths that have been registered during type formatting operations. The returned map can be used to generate the import section of a Go source file.
Returns:
- map[string]string: Map of import paths to their assigned aliases
func (*TypePrinter) InnerTypeString ¶
func (p *TypePrinter) InnerTypeString(t *ssztypes.TypeDescriptor) string
InnerTypeString returns the qualified string representation of the inner (dereferenced) type.
This method is similar to TypeString but automatically dereferences pointer types to get the underlying type. It's particularly useful when generating code that needs to work with the actual value type rather than pointer types.
For pointer types, this returns the element type. For non-pointer types, this behaves identically to TypeString.
Parameters:
- t: The TypeDescriptor containing type information for formatting
Returns:
- string: The qualified Go type string of the inner/dereferenced type
Example:
// For *MyStruct innerType := printer.InnerTypeString(descriptor) // Result: "MyStruct" (without the pointer)
func (*TypePrinter) InnerViewTypeString ¶ added in v1.4.0
func (p *TypePrinter) InnerViewTypeString(t *ssztypes.TypeDescriptor) string
InnerViewTypeString returns the qualified string representation of the view (schema) type of t, dereferenced: the type the view is declared as, without the pointer a view is referenced through.
func (*TypePrinter) ReserveNames ¶ added in v1.4.0
func (p *TypePrinter) ReserveNames(names []string)
ReserveNames records identifiers already declared in the target package's top-level scope. Import aliases are kept clear of these so generated code cannot collide with a package-level name like "sszutils" or "hasher" (which would otherwise fail to compile).
func (*TypePrinter) TypeString ¶
func (p *TypePrinter) TypeString(t *ssztypes.TypeDescriptor) string
TypeString returns the qualified string representation of a type descriptor and tracks import usage.
This method generates the appropriate Go type string for a TypeDescriptor, handling package qualification and import tracking automatically. It works with both types analyzed via go/types (compile-time) and reflection (runtime).
The method automatically:
- Qualifies types from other packages with appropriate import aliases
- Tracks import usage for later import statement generation
- Handles generic types with complex package path references
- Prefers compile-time type information when available
Parameters:
- t: The TypeDescriptor containing type information for formatting
Returns:
- string: The qualified Go type string suitable for code generation
Example:
typeName := printer.TypeString(descriptor) // Result: "phase0.BeaconBlock" or "*MyStruct" depending on the type
func (*TypePrinter) TypeStringWithoutTracking ¶
func (p *TypePrinter) TypeStringWithoutTracking(t *ssztypes.TypeDescriptor, viewType bool) string
TypeStringWithoutTracking returns the type string representation without tracking import usage.
This method generates type strings without adding imports to the tracking system. It's useful for scenarios where you need type names for analysis or comparison but don't want to affect the import management (e.g., during validation or debugging).
The generated string will still be properly qualified but won't register any imports for later code generation.
Parameters:
- t: The TypeDescriptor containing type information for formatting
Returns:
- string: The qualified Go type string without import tracking side effects
func (*TypePrinter) ViewTypeString ¶ added in v1.3.0
func (p *TypePrinter) ViewTypeString(t *ssztypes.TypeDescriptor, ensurePointer bool) string
ViewTypeString returns the qualified string representation of a view type descriptor and tracks import usage.
This method generates the appropriate Go type string for a view TypeDescriptor, handling package qualification and import tracking automatically.
Parameters:
- t: The view TypeDescriptor containing type information for formatting
Returns:
- string: The qualified Go type string suitable for code generation
Example:
typeName := printer.TypeString(descriptor) // Result: "phase0.BeaconBlock" or "*MyStruct" depending on the type