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
- Variables
- func DeRefPointer(t reflect.Type) reflect.Type
- func DecodeHex(s string) ([]byte, error)
- func DecodeUint256(s string) (*big.Int, error)
- func DecodeUint64(s string) (uint64, error)
- func EncodeHex(b []byte) string
- func EncodeUint256(n *big.Int) string
- func EncodeUint64(n uint64) string
- func FieldKeyString(str string) string
- func LengthPrefixTypeSize(t LengthPrefixType) (int, error)
- type API
- func (api *API) Decode(ctx context.Context, b []byte, obj interface{}, opts ...Option) (int, error)
- func (api *API) Encode(ctx context.Context, obj interface{}, opts ...Option) ([]byte, error)
- func (api *API) ForEachRegisteredInterfaceObjects(consumer func(objType reflect.Type, interfaceObjects *InterfaceObjects) bool)
- func (api *API) ForEachRegisteredTypeSetting(consumer func(objType reflect.Type, ts TypeSettings) bool)
- func (api *API) JSONDecode(ctx context.Context, data []byte, obj interface{}, opts ...Option) error
- func (api *API) JSONEncode(ctx context.Context, obj any, opts ...Option) ([]byte, error)
- func (api *API) MapDecode(ctx context.Context, m map[string]any, obj interface{}, opts ...Option) error
- func (api *API) MapEncode(ctx context.Context, obj interface{}, opts ...Option) (*orderedmap.OrderedMap, error)
- func (api *API) RegisterInterfaceObjects(iType interface{}, objs ...interface{}) error
- func (api *API) RegisterTypeSettings(obj interface{}, ts TypeSettings) error
- func (api *API) RegisterValidator(obj any, syntacticValidatorFn interface{}) error
- type ArrayRules
- type ContextAwareDeserializable
- type Deserializable
- type DeserializableJSON
- type InterfaceObjects
- func (i *InterfaceObjects) AddObject(objCode uint32, objType reflect.Type)
- func (i *InterfaceObjects) ForEachObjectCode(f func(objCode uint32, objType reflect.Type) bool)
- func (i *InterfaceObjects) ForEachObjectType(f func(objType reflect.Type, objCode uint32) bool)
- func (i *InterfaceObjects) GetObjectCodeByType(objType reflect.Type) (uint32, bool)
- func (i *InterfaceObjects) GetObjectTypeByCode(objCode uint32) (reflect.Type, bool)
- func (i *InterfaceObjects) HasObjectType(objType reflect.Type) bool
- func (i *InterfaceObjects) TypeDenotation() serializer.TypeDenotationType
- type InterfacesRegistry
- func (r *InterfacesRegistry) ForEach(consumer func(objType reflect.Type, interfaceObjects *InterfaceObjects) bool)
- func (r *InterfacesRegistry) Get(objType reflect.Type) (*InterfaceObjects, bool)
- func (r *InterfacesRegistry) Has(objType reflect.Type) bool
- func (r *InterfacesRegistry) RegisterInterfaceObjects(typeSettingsRegistry *TypeSettingsRegistry, iType interface{}, ...) error
- type LengthPrefixType
- type ObjectMetadata
- type Option
- type Serializable
- type SerializableJSON
- type TagSettings
- type TypeSettings
- func (ts TypeSettings) ArrayRules() *ArrayRules
- func (ts TypeSettings) Description() string
- func (ts TypeSettings) FieldKey() (string, bool)
- func (ts TypeSettings) LengthPrefixType() (LengthPrefixType, bool)
- func (ts TypeSettings) LexicalOrdering() (val bool, set bool)
- func (ts TypeSettings) MaxLen() (uint, bool)
- func (ts TypeSettings) MinLen() (uint, bool)
- func (ts TypeSettings) MinMaxLen() (int, int)
- func (ts TypeSettings) MustFieldKey() string
- func (ts TypeSettings) ObjectType() interface{}
- func (ts TypeSettings) WithArrayRules(rules *ArrayRules) TypeSettings
- func (ts TypeSettings) WithDescription(description string) TypeSettings
- func (ts TypeSettings) WithFieldKey(fieldKey string) TypeSettings
- func (ts TypeSettings) WithLengthPrefixType(lpt LengthPrefixType) TypeSettings
- func (ts TypeSettings) WithLexicalOrdering(val bool) TypeSettings
- func (ts TypeSettings) WithMaxLen(l uint) TypeSettings
- func (ts TypeSettings) WithMinLen(l uint) TypeSettings
- func (ts TypeSettings) WithObjectType(t interface{}) TypeSettings
- type TypeSettingsRegistry
- func (r *TypeSettingsRegistry) ForEach(consumer func(objType reflect.Type, ts TypeSettings) bool)
- func (r *TypeSettingsRegistry) GetByType(objType reflect.Type) (TypeSettings, bool)
- func (r *TypeSettingsRegistry) GetByValue(objValue reflect.Value, optTS ...TypeSettings) TypeSettings
- func (r *TypeSettingsRegistry) GetObjectMetadata(obj any) (*ObjectMetadata, error)
- func (r *TypeSettingsRegistry) Has(objType reflect.Type) bool
- func (r *TypeSettingsRegistry) RegisterTypeSettings(obj interface{}, ts TypeSettings) error
Constants ¶
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 ¶
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") )
var DefaultAPI = NewAPI()
DefaultAPI is the default instance of the API type.
var (
ErrInterfaceUnderlyingTypeNotRegistered = ierrors.New("underlying type hasn't been registered for interface type")
)
var ( // ErrUnknownLengthPrefixType gets returned when an unknown LengthPrefixType is used. ErrUnknownLengthPrefixType = ierrors.New("unknown length prefix type") )
Functions ¶
func DeRefPointer ¶
DeRefPointer dereferences the given type if it's a pointer.
func DecodeUint256 ¶
DecodeUint256 decodes the little-endian hex encoded string to an uint256.
func DecodeUint64 ¶
DecodeUint64 decodes the base 10 string to an uint64.
func EncodeHex ¶
EncodeHex encodes the bytes string to a hex string. It always adds the 0x prefix if bytes are not empty.
func EncodeUint256 ¶
EncodeUint256 encodes the uint256 to a little-endian encoded hex string.
func EncodeUint64 ¶
EncodeUint64 encodes the uint64 to a base 10 string.
func FieldKeyString ¶
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 (*API) Decode ¶
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 ¶
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 ¶
JSONDecode deserializes json data into the provided object obj.
func (*API) JSONEncode ¶
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 ¶
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 ¶
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 ¶
ContextAwareDeserializable is a type that is able to receive the serialization context.
type Deserializable ¶
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 ¶
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) 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 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 ¶
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 ¶
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) RegisterTypeSettings ¶
func (r *TypeSettingsRegistry) RegisterTypeSettings(obj interface{}, ts TypeSettings) error
RegisterTypeSettings registers settings for a particular type obj.