spec

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package spec provides tools to create serializable type specifications and encoding/decoding functionality for them.

Index

Constants

View Source
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.

View Source
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

View Source
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

func GetSrcPointer(rv reflect.Value) uintptr

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

func IsSpecError(err error) bool

IsSpecError reports whether the error is non-nil Error or FieldErrors.

func NewError

func NewError(msg string, args ...any) error

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

func NewErrorf(format string, args ...any) error

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 Builder

type Builder[T any] func(*Spec) (T, error)

Builder creates a type instance from the given Spec.

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

func NewRegistry[T any]() *Registry[T]

NewRegistry returns a new instance of Registry.

func (*Registry[T]) Build added in v0.6.0

func (reg *Registry[T]) Build(spc *Spec) (T, error)

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

func (reg *Registry[T]) BuilderFor(name string) Builder[T]

BuilderFor returns the Builder registered for the given name, or nil if none exists.

func (*Registry[T]) DecodeAndBuild added in v0.6.0

func (reg *Registry[T]) DecodeAndBuild(data []byte) (T, error)

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

func (reg *Registry[T]) DecodeSpec(data []byte, spc *Spec) error

DecodeSpec decodes JSON representation of Spec.

func (*Registry[T]) EncodeSpec

func (reg *Registry[T]) EncodeSpec(spc *Spec) ([]byte, error)

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

func (reg *Registry[T]) RegisterBuilder(
	name string,
	bld Builder[T],
) Builder[T]

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

func (reg *Registry[T]) RegisterBuilders(
	bls map[string]Builder[T],
) map[string]Builder[T]

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

func (reg *Registry[T]) RegisterSource(src Source) Source

RegisterSource registers a source so it can be later used during decoding.

func (*Registry[T]) SourceByName

func (reg *Registry[T]) SourceByName(name string) Source

SourceByName retrieves an instance of Source by its name.

func (*Registry[T]) SourceByValue

func (reg *Registry[T]) SourceByValue(value any) Source

SourceByValue retrieves an instance of Source representing a given value.

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

func NewSource(name string, val any) (Source, error)

NewSource returns a new instance of named Source for the value. By default, the source language is set to "go".

func (Source) IsZero

func (src Source) IsZero() bool

func (Source) Ptr

func (src Source) Ptr() uintptr

Ptr retrieves the pointer to the value described by the source.

func (Source) SetDesc

func (src Source) SetDesc(desc string) Source

SetDesc sets the source description.

func (Source) SetLang

func (src Source) SetLang(lang string) Source

SetLang sets the source language.

func (Source) Val

func (src Source) Val() any

Val retrieves the value described by the source.

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

func NewSpec(name string) *Spec

NewSpec creates a new Spec instance with the given name.

Use application-wide unique names.

func (*Spec) ArgExist

func (spc *Spec) ArgExist(name string) bool

ArgExist checks if the argument with the given name exists in the spec.

func (*Spec) SetArg

func (spc *Spec) SetArg(name string, val any) *Spec

SetArg sets Source argument; when the argument with the same name exists, it will be overwritten.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL