serix

package
v2.0.0-rc.1.0...-ecd835d Latest Latest
Warning

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

Go to latest
Published: May 17, 2024 License: Apache-2.0, BSD-2-Clause Imports: 18 Imported by: 0

Documentation

Overview

Package serix serializes and deserializes complex Go objects into/from bytes using reflection.

Structs serialization/deserialization

In order for a field to be detected by serix it must have `serix:""` struct tag. The first part in the tag is the key used for json serialization. If the name is empty, serix uses the field name in camel case.

Exceptions:
	- "ID" => "Id"
	- "NFT" => "Nft"
	- "URL" => "Url"
	- "HRP" => "Hrp"

Examples:

  • `serix:""
  • `serix:"example"
  • `serix:","`

serix traverses all fields and handles them in the order specified in the struct. You can provide the following settings to serix via struct tags:

  • "optional": means the field might be nil. Only valid for pointers or interfaces. It will be prepended with the serialized size of the field. `serix:"example,optional"`

  • "inlined": handle embedded/anonymous field as a nested field `serix:"example,inlined"`

  • "omitempty": omit the field in json serialization if it's empty `serix:"example,omitempty"`

  • "maxByteSize": maximum serialized byte size for that field `serix:"example,maxByteSize=100"`

  • "lenPrefix": provide serializer.SeriLengthPrefixType for that field (string, slice, map) `serix:"example,lenPrefix=uint32"`

  • "minLen": minimum length for that field (string, slice, map) `serix:"example,minLen=2"`

  • "maxLen": maximum length for that field (string, slice, map) `serix:"example,maxLen=5"`

See serix_text.go for more detail.

Index

Constants

View Source
const (
	// LengthPrefixTypeAsByte defines a collection length to be denoted by a byte.
	LengthPrefixTypeAsByte = LengthPrefixType(serializer.SeriLengthPrefixTypeAsByte)
	// LengthPrefixTypeAsUint16 defines a collection length to be denoted by a uint16.
	LengthPrefixTypeAsUint16 = LengthPrefixType(serializer.SeriLengthPrefixTypeAsUint16)
	// LengthPrefixTypeAsUint32 defines a collection length to be denoted by a uint32.
	LengthPrefixTypeAsUint32 = LengthPrefixType(serializer.SeriLengthPrefixTypeAsUint32)
	// LengthPrefixTypeAsUint64 defines a collection length to be denoted by a uint64.
	LengthPrefixTypeAsUint64 = LengthPrefixType(serializer.SeriLengthPrefixTypeAsUint64)
)

Variables

View Source
var (
	// ErrMapValidationViolatesUniqueness gets returned if the map elements are not unique.
	ErrMapValidationViolatesUniqueness = ierrors.New("map elements must be unique")
	// ErrNonUTF8String gets returned when a non UTF-8 string is being encoded/decoded.
	ErrNonUTF8String = ierrors.New("non UTF-8 string value")
)
View Source
var DefaultAPI = NewAPI()

DefaultAPI is the default instance of the API type.

View Source
var (
	ErrInterfaceUnderlyingTypeNotRegistered = ierrors.New("underlying type hasn't been registered for interface type")
)
View Source
var (
	// ErrUnknownLengthPrefixType gets returned when an unknown LengthPrefixType is used.
	ErrUnknownLengthPrefixType = ierrors.New("unknown length prefix type")
)

Functions

func DeRefPointer

func DeRefPointer(t reflect.Type) reflect.Type

DeRefPointer dereferences the given type if it's a pointer.

func DecodeHex

func DecodeHex(s string) ([]byte, error)

DecodeHex decodes the given hex string to bytes. It expects the 0x prefix.

func DecodeUint256

func DecodeUint256(s string) (*big.Int, error)

DecodeUint256 decodes the little-endian hex encoded string to an uint256.

func DecodeUint64

func DecodeUint64(s string) (uint64, error)

DecodeUint64 decodes the base 10 string to an uint64.

func EncodeHex

func EncodeHex(b []byte) string

EncodeHex encodes the bytes string to a hex string. It always adds the 0x prefix if bytes are not empty.

func EncodeUint256

func EncodeUint256(n *big.Int) string

EncodeUint256 encodes the uint256 to a little-endian encoded hex string.

func EncodeUint64

func EncodeUint64(n uint64) string

EncodeUint64 encodes the uint64 to a base 10 string.

func FieldKeyString

func FieldKeyString(str string) string

FieldKeyString converts the given string to camelCase. Special keywords like ID or URL are converted to only first letter upper case.

func LengthPrefixTypeSize

func LengthPrefixTypeSize(t LengthPrefixType) (int, error)

Types

type API

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

API is the main object of the package that provides the methods for client to use. It holds all the settings and configuration. It also stores the cache. Most often you will need a single object of API for the whole program. You register all type settings and interfaces on the program start or in init() function. Instead of creating a new API object you can also use the default singleton API object: DefaultAPI.

func NewAPI

func NewAPI() *API

NewAPI creates a new instance of the API type.

func (*API) Decode

func (api *API) Decode(ctx context.Context, b []byte, obj interface{}, opts ...Option) (int, error)

Decode deserializes bytes b into the provided object obj. obj must be a non-nil pointer for serix to deserialize into it. serix traverses the object recursively and deserializes everything based on its type. If a type implements the custom Deserializable interface serix delegates the deserialization to that type. During the decoding process serix also performs the validation if such option was provided. Use the options list opts to customize the deserialization behavior.

func (*API) Encode

func (api *API) Encode(ctx context.Context, obj interface{}, opts ...Option) ([]byte, error)

Encode serializes the provided object obj into bytes. serix traverses the object recursively and serializes everything based on the type. If a type implements the custom Serializable interface serix delegates the serialization to that type. During the encoding process serix also performs the validation if such option was provided. Use the options list opts to customize the serialization behavior. To ensure deterministic serialization serix automatically applies lexical ordering for maps.

func (*API) ForEachRegisteredInterfaceObjects

func (api *API) ForEachRegisteredInterfaceObjects(consumer func(objType reflect.Type, interfaceObjects *InterfaceObjects) bool)

func (*API) ForEachRegisteredTypeSetting

func (api *API) ForEachRegisteredTypeSetting(consumer func(objType reflect.Type, ts TypeSettings) bool)

func (*API) JSONDecode

func (api *API) JSONDecode(ctx context.Context, data []byte, obj interface{}, opts ...Option) error

JSONDecode deserializes json data into the provided object obj.

func (*API) JSONEncode

func (api *API) JSONEncode(ctx context.Context, obj any, opts ...Option) ([]byte, error)

JSONEncode serializes the provided object obj into its JSON representation.

func (*API) MapDecode

func (api *API) MapDecode(ctx context.Context, m map[string]any, obj interface{}, opts ...Option) error

MapDecode deserializes generic map m into the provided object obj. obj must be a non-nil pointer for serix to deserialize into it. serix traverses the object recursively and deserializes everything based on its type. Use the options list opts to customize the deserialization behavior.

func (*API) MapEncode

func (api *API) MapEncode(ctx context.Context, obj interface{}, opts ...Option) (*orderedmap.OrderedMap, error)

MapEncode serializes the provided object obj into an ordered map. serix traverses the object recursively and serializes everything based on the type. Use the options list opts to customize the serialization behavior.

func (*API) RegisterInterfaceObjects

func (api *API) RegisterInterfaceObjects(iType interface{}, objs ...interface{}) error

RegisterInterfaceObjects tells serix that when it encounters iType during serialization/deserialization it actually might be one of the objs types. Those objs type must provide their ObjectTypes beforehand via API.RegisterTypeSettings(). serix needs object types to be able to figure out what concrete object to instantiate during the deserialization based on its object type code. In order for reflection to grasp the actual interface type, iType must be provided as a pointer to an interface: api.RegisterInterfaceObjects((*Interface)(nil), (*InterfaceImpl)(nil)) See TestMain() in serix_test.go for more detail.

func (*API) RegisterTypeSettings

func (api *API) RegisterTypeSettings(obj interface{}, ts TypeSettings) error

RegisterTypeSettings registers settings for a particular type obj. It's better to provide obj as a value, not a pointer, that way serix will be able to get the type settings for both values and pointers during Encode/Decode via de-referencing The settings provided via registration are considered global and default ones, they can be overridden by type settings parsed from struct tags or by type settings provided via option to the Encode/Decode methods. See TypeSettings for more detail.

func (*API) RegisterValidator

func (api *API) RegisterValidator(obj any, syntacticValidatorFn interface{}) error

RegisterValidator registers a syntactic validator function that serix will call during the Encode and Decode processes.

A syntactic validator validates the Go object and its data.

For Encode, it is called for the original Go object before serix serializes the object into bytes. For Decode, it is called after serix builds the Go object from bytes.

The validation is called for every registered type during the recursive traversal. It's an early stop process, if some validator returns an error serix stops the Encode/Decode and pops up the error.

obj is an instance of the type you want to provide the validator for. Note that it's better to pass the obj as a value, not as a pointer because that way serix would be able to dereference pointers during Encode/Decode and detect the validators for both pointers and values

syntacticValidatorFn is a function that accepts context.Context, and an object with the same type as obj.

Example:

syntacticValidator := func (ctx context.Context, t time.Time) error { ... }

api.RegisterValidator(time.Time{}, syntacticValidator).

type ArrayRules

type ArrayRules serializer.ArrayRules

ArrayRules defines rules around a to be deserialized array. Min and Max at 0 define an unbounded array.

type ContextAwareDeserializable

type ContextAwareDeserializable interface {
	SetDeserializationContext(ctx context.Context)
}

ContextAwareDeserializable is a type that is able to receive the serialization context.

type Deserializable

type Deserializable interface {
	Decode(b []byte) (int, error)
}

Deserializable is a type that can deserialize itself. Serix will call its .Decode() method instead of trying to deserialize it in the default way. The behavior is totally the same as in the standard "encoding/json" package and json.Unmarshaler interface.

type DeserializableJSON

type DeserializableJSON interface {
	DecodeJSON(b any) error
}

DeserializableJSON is a type that can deserialize itself from JSON format. Serix will call its .Decode() method instead of trying to deserialize it in the default way. The behavior is totally the same as in the standard "encoding/json" package and json.Unmarshaler interface.

type InterfaceObjects

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

InterfaceObjects holds all the information about the objects that are registered to the same interface.

func NewInterfaceObjects

func NewInterfaceObjects(typeDenotation serializer.TypeDenotationType) *InterfaceObjects

func (*InterfaceObjects) AddObject

func (i *InterfaceObjects) AddObject(objCode uint32, objType reflect.Type)

func (*InterfaceObjects) ForEachObjectCode

func (i *InterfaceObjects) ForEachObjectCode(f func(objCode uint32, objType reflect.Type) bool)

func (*InterfaceObjects) ForEachObjectType

func (i *InterfaceObjects) ForEachObjectType(f func(objType reflect.Type, objCode uint32) bool)

func (*InterfaceObjects) GetObjectCodeByType

func (i *InterfaceObjects) GetObjectCodeByType(objType reflect.Type) (uint32, bool)

func (*InterfaceObjects) GetObjectTypeByCode

func (i *InterfaceObjects) GetObjectTypeByCode(objCode uint32) (reflect.Type, bool)

func (*InterfaceObjects) HasObjectType

func (i *InterfaceObjects) HasObjectType(objType reflect.Type) bool

func (*InterfaceObjects) TypeDenotation

func (i *InterfaceObjects) TypeDenotation() serializer.TypeDenotationType

type InterfacesRegistry

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

func NewInterfacesRegistry

func NewInterfacesRegistry() *InterfacesRegistry

func (*InterfacesRegistry) ForEach

func (r *InterfacesRegistry) ForEach(consumer func(objType reflect.Type, interfaceObjects *InterfaceObjects) bool)

func (*InterfacesRegistry) Get

func (r *InterfacesRegistry) Get(objType reflect.Type) (*InterfaceObjects, bool)

func (*InterfacesRegistry) Has

func (r *InterfacesRegistry) Has(objType reflect.Type) bool

func (*InterfacesRegistry) RegisterInterfaceObjects

func (r *InterfacesRegistry) RegisterInterfaceObjects(typeSettingsRegistry *TypeSettingsRegistry, iType interface{}, objs ...interface{}) error

type LengthPrefixType

type LengthPrefixType serializer.SeriLengthPrefixType

LengthPrefixType defines the type of the value denoting the length of a collection.

type ObjectMetadata

type ObjectMetadata struct {
	Type           reflect.Type
	TypeDenotation serializer.TypeDenotationType
	Code           uint32
}

type Option

type Option func(o *options)

Option is an option for Encode/Decode methods.

func WithTypeSettings

func WithTypeSettings(ts TypeSettings) Option

WithTypeSettings returns an option that sets TypeSettings. TypeSettings provided via option override global TypeSettings from the registry. See TypeSettings for details.

func WithValidation

func WithValidation() Option

WithValidation returns an Option that tells serix to perform validation.

type Serializable

type Serializable interface {
	Encode() ([]byte, error)
}

Serializable is a type that can serialize itself. Serix will call its .Encode() method instead of trying to serialize it in the default way. The behavior is totally the same as in the standard "encoding/json" package and json.Marshaler interface.

type SerializableJSON

type SerializableJSON interface {
	EncodeJSON() (any, error)
}

SerializableJSON is a type that can serialize itself to JSON format. Serix will call its .EncodeJSON() method instead of trying to serialize it in the default way. The behavior is totally the same as in the standard "encoding/json" package and json.Marshaler interface.

type TagSettings

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

func ParseSerixSettings

func ParseSerixSettings(tag string, serixPosition int) (TagSettings, error)

ParseSerixSettings parses the given struct tag and returns the settings.

func (TagSettings) Inlined

func (ts TagSettings) Inlined() bool

func (TagSettings) IsOptional

func (ts TagSettings) IsOptional() bool

func (TagSettings) OmitEmpty

func (ts TagSettings) OmitEmpty() bool

func (TagSettings) Position

func (ts TagSettings) Position() int

func (TagSettings) TypeSettings

func (ts TagSettings) TypeSettings() TypeSettings

type TypeSettings

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

TypeSettings holds various settings for a particular type. Those settings determine how the object should be serialized/deserialized. There are three ways to provide TypeSettings 1. Via global registry: API.RegisterTypeSettings(). 2. Parse from struct tags. 3. Pass as an option to API.Encode/API.Decode methods. The type settings provided via struct tags or an option override the type settings from the registry. So the precedence is the following 1<2<3. See API.RegisterTypeSettings() and WithTypeSettings() for more detail.

func NewTypeSettings

func NewTypeSettings() TypeSettings

func (TypeSettings) ArrayRules

func (ts TypeSettings) ArrayRules() *ArrayRules

ArrayRules returns serializer.ArrayRules.

func (TypeSettings) Description

func (ts TypeSettings) Description() string

Description returns the description of the object.

func (TypeSettings) FieldKey

func (ts TypeSettings) FieldKey() (string, bool)

FieldKey returns the key for the field.

func (TypeSettings) LengthPrefixType

func (ts TypeSettings) LengthPrefixType() (LengthPrefixType, bool)

LengthPrefixType returns LengthPrefixType.

func (TypeSettings) LexicalOrdering

func (ts TypeSettings) LexicalOrdering() (val bool, set bool)

LexicalOrdering returns lexical ordering flag.

func (TypeSettings) MaxLen

func (ts TypeSettings) MaxLen() (uint, bool)

MaxLen returns max length for the object.

func (TypeSettings) MinLen

func (ts TypeSettings) MinLen() (uint, bool)

MinLen returns min length for the object.

func (TypeSettings) MinMaxLen

func (ts TypeSettings) MinMaxLen() (int, int)

MinMaxLen returns min/max lengths for the object. Returns 0 for either value if they are not set.

func (TypeSettings) MustFieldKey

func (ts TypeSettings) MustFieldKey() string

MustFieldKey must return a key for the field.

func (TypeSettings) ObjectType

func (ts TypeSettings) ObjectType() interface{}

ObjectType returns the object type as an uint8 or uint32 number.

func (TypeSettings) WithArrayRules

func (ts TypeSettings) WithArrayRules(rules *ArrayRules) TypeSettings

WithArrayRules specifies serializer.ArrayRules.

func (TypeSettings) WithDescription

func (ts TypeSettings) WithDescription(description string) TypeSettings

WithDescription specifies the description of the object.

func (TypeSettings) WithFieldKey

func (ts TypeSettings) WithFieldKey(fieldKey string) TypeSettings

WithFieldKey specifies the key for the field.

func (TypeSettings) WithLengthPrefixType

func (ts TypeSettings) WithLengthPrefixType(lpt LengthPrefixType) TypeSettings

WithLengthPrefixType specifies LengthPrefixType.

func (TypeSettings) WithLexicalOrdering

func (ts TypeSettings) WithLexicalOrdering(val bool) TypeSettings

WithLexicalOrdering specifies whether the type must be lexically ordered during serialization.

func (TypeSettings) WithMaxLen

func (ts TypeSettings) WithMaxLen(l uint) TypeSettings

WithMaxLen specifies the max length for the object.

func (TypeSettings) WithMinLen

func (ts TypeSettings) WithMinLen(l uint) TypeSettings

WithMinLen specifies the min length for the object.

func (TypeSettings) WithObjectType

func (ts TypeSettings) WithObjectType(t interface{}) TypeSettings

WithObjectType specifies the object type. It can be either uint8 or uint32 number. The object type holds two meanings: the actual code (number) and the serializer.TypeDenotationType like uint8 or uint32. serix uses object type to actually encode the number and to know its serializer.TypeDenotationType to be able to decode it.

type TypeSettingsRegistry

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

func NewTypeSettingsRegistry

func NewTypeSettingsRegistry() *TypeSettingsRegistry

func (*TypeSettingsRegistry) ForEach

func (r *TypeSettingsRegistry) ForEach(consumer func(objType reflect.Type, ts TypeSettings) bool)

func (*TypeSettingsRegistry) GetByType

func (r *TypeSettingsRegistry) GetByType(objType reflect.Type) (TypeSettings, bool)

func (*TypeSettingsRegistry) GetByValue

func (r *TypeSettingsRegistry) GetByValue(objValue reflect.Value, optTS ...TypeSettings) TypeSettings

func (*TypeSettingsRegistry) GetObjectMetadata

func (r *TypeSettingsRegistry) GetObjectMetadata(obj any) (*ObjectMetadata, error)

func (*TypeSettingsRegistry) Has

func (r *TypeSettingsRegistry) Has(objType reflect.Type) bool

func (*TypeSettingsRegistry) RegisterTypeSettings

func (r *TypeSettingsRegistry) RegisterTypeSettings(obj interface{}, ts TypeSettings) error

RegisterTypeSettings registers settings for a particular type obj.

Jump to

Keyboard shortcuts

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