Documentation
¶
Overview ¶
Package spec provides tools to create serializable type specifications and encoding/decoding functionality for them.
Index ¶
- Constants
- Variables
- func GetSrcPointer(rv reflect.Value) uintptr
- func IsSpecError(err error) bool
- func NewError(msg string, args ...any) error
- func NewErrorf(format string, args ...any) error
- type Builder
- type Error
- type FieldErrors
- type Registry
- func (reg *Registry[T]) Build(spc *Spec) (T, error)
- func (reg *Registry[T]) BuilderFor(name string) Builder[T]
- func (reg *Registry[T]) DecodeAndBuild(data []byte) (T, error)
- func (reg *Registry[T]) DecodeSpec(data []byte, spc *Spec) error
- func (reg *Registry[T]) EncodeSpec(spc *Spec) ([]byte, error)
- func (reg *Registry[T]) RegisterBuilder(name string, bld Builder[T]) Builder[T]
- func (reg *Registry[T]) RegisterBuilders(bls map[string]Builder[T]) map[string]Builder[T]
- func (reg *Registry[T]) RegisterSource(src Source) Source
- func (reg *Registry[T]) SourceByName(name string) Source
- func (reg *Registry[T]) SourceByValue(value any) Source
- type Source
- type Spec
- type Specable
Constants ¶
const ( // ECInvSpec is the error code used when a [Spec] is invalid or incomplete. ECInvSpec = "ECInvSpec" // ECUnkSource is the error code used when a [Source] doesn't exist. ECUnkSource = "ECUnkSource" // ECUnkBuilder is the error code used when a [Builder] doesn't exist. ECUnkBuilder = "ECUnkBuilder" // ECInvSource is the error code used when a [Source] is invalid or // unsupported. ECInvSource = "ECInvSource" // ECNoGoSource is the error code used when a [Spec] lacks the required // [Source] definition for Go language. ECNoGoSource = "ECNoGoSource" // ECInvSpecArg is the error code used when a [Spec] argument is invalid. ECInvSpecArg = "ECInvSpecArg" // ECInvSpecArgType is the error code used when a [Spec] argument has an // invalid type. ECInvSpecArgType = "ECInvSpecArgType" // ECNotSpecable is the error code used when a type doesn't implement // [Specable] interface. ECNotSpecable = "ECNotSpecable" )
Package level error codes.
const ( // ArgValue is a reserved [Spec] argument name holding a value. // // The value must be representable by [jsontype.Value]. // // When encoding, this value should be replaced with [jsontype.Value]. When // decoding, this value must be replaced with the concrete value encoded by // [jsontype.Value]. ArgValue = "value" // ArgValues is a reserved [Spec] argument name holding a list of values. // // It is represented by `[]any` slice, and each value must be representable // as [jsontype.Value]. // // When encoding, this value should be replaced with a slice of // [jsontype.Value] representations. When decoding, this value must be // replaced with the `[]any` slice. ArgValues = "values" // ArgSrc is a reserved [Spec] argument name holding a value like functions // which cannot be serialized. // // When encoding, this value must be replaced with an instance of [Source] // representing the value. When decoding, this value must be replaced with // the concrete value. ArgSrc = "src_go" // ArgSpecs is a reserved [Spec] argument name holding a list of [Spec] // instances. ArgSpecs = "specs" // ArgTypes is a reserved [Spec] argument name holding a list of typed // values. The [Registry] encodes and decodes this argument especially: on // marshaling each element is turned into a [Spec]; on unmarshaling each // element spec is rebuilt via a registered [Builder]. ArgTypes = "types" )
Spec argument names.
Variables ¶
var ( // ErrInvSpec is returned when a [Spec] is either invalid or incomplete. ErrInvSpec = NewError("invalid spec", ECInvSpec) // ErrNoGoSource is returned when a [Spec] lacks the required Go definition. ErrNoGoSource = NewError("spec has no Go source defined", ECNoGoSource) // ErrUnkSource is returned when a [Source] does not exist. ErrUnkSource = NewError("unknown source", ECUnkSource) // ErrUnkBuilder is returned when a [Builder] does not exist. ErrUnkBuilder = NewError("unknown builder", ECUnkBuilder) // ErrInvSource is returned when a [Source] definition is invalid. ErrInvSource = NewError("invalid source", ECInvSource) // ErrInvArg is returned when a [Spec] argument is invalid. ErrInvArg = NewError("invalid spec argument", ECInvSpecArg) // ErrInvArgType is returned when a [Spec] argument is of an invalid type. ErrInvArgType = NewError("invalid spec argument type", ECInvSpecArgType) // ErrNotSpecable is returned when a type doesn't implement [Specable]. ErrNotSpecable = NewError("type not specable", ECNotSpecable) )
Package level sentinel errors.
Functions ¶
func GetSrcPointer ¶
GetSrcPointer returns a pointer to the value. Returns zero for not supported or invalid values. Currently only functions are supported.
func IsSpecError ¶ added in v0.5.0
IsSpecError reports whether the error is non-nil Error or FieldErrors.
func NewError ¶
NewError creates a new Error with the given message. The args may contain an optional string error code and any number of xrr.Option values in any order.
Examples:
NewError("message")
NewError("message", "ECode")
NewError("message", "ECode", xrr.Option())
When xrr.WithCause is provided:
- If msg is empty, Error() returns the cause's message directly.
- If msg is non-empty, Error() returns "msg: cause message".
- If no code is given and xrr.WithCode is not provided, the cause's code is inherited via xrr.GetCode. Pass a code string or xrr.WithCode to override it.
For wrapping without a new message, prefer xrr.Wrap, which makes the intent clearer.
func NewErrorf ¶ added in v0.7.0
NewErrorf creates a new Error using a format string. It is the format-style counterpart of NewError: non-xrr.Option args are passed to the format string, while xrr.Option values are applied to the error. Unlike NewError, a bare string argument is treated as a format argument, not an error code — pass xrr.WithCode to set the code.
When the format string contains %w, the error is created via fmt.Errorf and stored as the cause; xrr.GenericError.Error delegates to it. Without %w, the message is set to fmt.Sprintf(format, args...).
Examples:
NewErrorf("user %d not found", userID)
NewErrorf("user %d not found", userID, xrr.WithCode("ECode"))
NewErrorf("connect failed: %w", err)
NewErrorf("connect failed: %w", err, xrr.WithCode("ECode"))
Types ¶
type Error ¶
type Error = xrr.GenericError[edError]
Error represents an error in the package's error domain.
type FieldErrors ¶ added in v0.5.0
type FieldErrors = xrr.GenericFields[edError]
FieldErrors represents a field error in the package's error domain.
func NewFieldError ¶ added in v0.5.0
func NewFieldError(field string, err error) *FieldErrors
NewFieldError returns a new field error in the package's error domain.
func NewFieldErrors ¶ added in v0.5.0
func NewFieldErrors(fields map[string]error) *FieldErrors
NewFieldErrors creates a new FieldErrors from the given map. The map is stored directly without copying.
type Registry ¶
type Registry[T any] struct { // contains filtered or unexported fields }
Registry manages a collection of Source and Builder instances and provides methods to encode and decode Spec instances to generic type T. It is safe for concurrent use.
func NewRegistry ¶
NewRegistry returns a new instance of Registry.
func (*Registry[T]) Build ¶ added in v0.6.0
Build creates an instance of T from the given Spec using a registered Builder. Returns ErrInvSpec if spc is nil, or ErrUnkBuilder if no Builder is registered for Spec.Name.
func (*Registry[T]) BuilderFor ¶
BuilderFor returns the Builder registered for the given name, or nil if none exists.
func (*Registry[T]) DecodeAndBuild ¶ added in v0.6.0
DecodeAndBuild decodes the JSON representation of a Spec and builds an instance of T from it. It is a convenience wrapper around Registry.DecodeSpec followed by Registry.Build.
func (*Registry[T]) DecodeSpec ¶
DecodeSpec decodes JSON representation of Spec.
func (*Registry[T]) EncodeSpec ¶
EncodeSpec encodes the given Spec to JSON.
NOTE: The input spc is never mutated. EncodeSpec works on an internal copy so callers can safely reuse the same *Spec across multiple Encode / Build / roundtrip operations.
func (*Registry[T]) RegisterBuilder ¶
RegisterBuilder registers or replaces a Builder for the given spec name.
If a builder with the same name already exists, it is replaced and the previous builder is returned.
If bld is nil and a builder with the given name exists, it is removed and the removed builder is returned.
Returns the previous builder (or nil if none existed).
func (*Registry[T]) RegisterBuilders ¶
RegisterBuilders registers multiple Builder instances in a single call.
It invokes Registry.RegisterBuilder for each entry in bls and returns a map of name → previous builder (or nil if none existed) for each registration.
func (*Registry[T]) RegisterSource ¶
RegisterSource registers a source so it can be later used during decoding.
func (*Registry[T]) SourceByName ¶
SourceByName retrieves an instance of Source by its name.
type Source ¶
type Source struct {
Lang string `json:"lang"` // Source language: go, js, etc.
Name string `json:"name"` // Unique name of the source.
Src string `json:"src,omitempty"` // Optional source code location.
Desc string `json:"desc,omitempty"` // Optional description.
// contains filtered or unexported fields
}
Source represents values like functions which cannot be serialized.
Is used to associate a unique name for non-serializable values so we can find them later when they are unserialized.
func NewSource ¶
NewSource returns a new instance of named Source for the value. By default, the source language is set to "go".
type Spec ¶
type Spec struct {
// The unique name of the specification. Use application-wide unique names.
Name string `json:"name"`
// The map of additional arguments for the specification.
Args map[string]any `json:"args,omitempty"`
}
Spec represents information about a type or process that can be serialized.
func NewSpec ¶
NewSpec creates a new Spec instance with the given name.
Use application-wide unique names.
type Specable ¶
type Specable interface {
// Spec returns the [Spec] describing the given structure. The returned
// spec must include all information needed to instantiate the structure at
// a later time.
Spec() (*Spec, error)
}
Specable is implemented by types that can describe themselves as a Spec.