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 ArgDecoder
- type ArgEncoder
- 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]) RegisterCodec(name string, enc ArgEncoder[T], dec ArgDecoder[T]) (ArgEncoder[T], ArgDecoder[T], error)
- 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 = "ECECInvSpecArg" // 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 ( // ArgSpecs is a reserved [Spec] argument name that holds a list of // [Spec] instances. It is the only argument for which neither an // encoder nor a decoder can be registered. ArgSpecs = "specs" // 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" // 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 ArgDecoder ¶ added in v0.8.0
ArgDecoder is a function that decodes a JSON-encoded Spec argument and stores the result in spc. It receives the registry, the raw JSON bytes, and the target Spec.
type ArgEncoder ¶ added in v0.8.0
ArgEncoder is a function that encodes a Spec argument value into a form suitable for JSON marshaling. It receives the registry and the raw argument value, and returns the encoded representation or an error.
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.
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]) RegisterCodec ¶ added in v0.8.0
func (reg *Registry[T]) RegisterCodec( name string, enc ArgEncoder[T], dec ArgDecoder[T], ) (ArgEncoder[T], ArgDecoder[T], error)
RegisterCodec registers custom encoder and decoder functions for the given Spec argument name. When enc and dec are both nil, any existing codec for the name is removed. Returns the previously registered encoder and decoder (both nil if none existed). Returns an error if exactly one of enc or dec is nil.
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.