Documentation ¶
Overview ¶
Atlas types are used to define how to map Go values into refmt token streams.
Atlas information may be autogenerated based on struct tags automatically, but you can also specify custom AtlasEntry info to use advanced features and define custom transformations.
An Atlas is a collection of AtlasEntry (plus some internal indexing). Typical usage is to declare an AtlasEntry for your structs (often near by the struct definition), then
Building an AtlasEntry for some type called `Formula` looks like this:
atlas.BuildEntry(Formula{}).StructMap().Autogenerate().Complete()
Building an AtlasEntry always starts with `atlas.BuildEntry(x)` where `x` is a dummy object used to convey type information. The next function in the chain declares what kind of behavior we're going to use to turn that type of object into its serial form. (In the above example, we're declaring that we want refmt to see the `Formula` type as a struct and traverse its fields. There are many other options!) Subsequent functions are specific to what kind of walking and mapping we've chosen. For struct walking, this may involve declaring fields and custom serial names to map them to; for a "Transform" we'd instead have to provide callbacks to do the transformation from the `Formula` type to some other type; etcetera. The final function in the chain is always called `Complete`, and returns a ready-to-use AtlasEntry.
Building a complete Atlas for a whole suite of serializable types is as easy as putting a bunch of them together:
atlas.Build( atlas.BuildEntry(Foo{}).StructMap().Autogenerate().Complete(), atlas.BuildEntry(Bar{}).StructMap().Autogenerate().Complete(), atlas.BuildEntry(Baz{}).StructMap().Autogenerate().Complete(), )
You can put your entire protocol into one Atlas. It's also possible to build several different Atlases each with different sets of AtlasEntry. This may be useful if you have a protocol where some messages are not valid during some phases of communication, and you would like to use the Atlas as a form of whitelisting for what can be marshalled/unmarshalled.
Index ¶
- Constants
- type Atlas
- type AtlasEntry
- type BuilderCore
- type BuilderMapMorphism
- type BuilderStructMap
- func (x *BuilderStructMap) AddField(fieldName string, mapping StructMapEntry) *BuilderStructMap
- func (x *BuilderStructMap) Autogenerate() *BuilderStructMap
- func (x *BuilderStructMap) AutogenerateWithSortingScheme(sorting KeySortMode) *BuilderStructMap
- func (x *BuilderStructMap) Complete() *AtlasEntry
- func (x *BuilderStructMap) IgnoreKey(serialKeyName string) *BuilderStructMap
- type BuilderTransform
- type BuilderUnionKeyedMorphism
- type ErrStructureMismatch
- type KeySortMode
- type MapMorphism
- type MarshalTransformFunc
- type ReflectRoute
- type StructMap
- type StructMapEntry
- type StructMapEntry_RFC7049
- type StructMapEntry_byFieldRoute
- type StructMapEntry_byName
- type UnionKeyedMorphism
- type UnmarshalTransformFunc
Constants ¶
const ( KeySortMode_Default = KeySortMode("default") // the default mode -- for structs, this is the source-order of the fields; for maps, it's identify to "strings" sort mode. KeySortMode_Strings = KeySortMode("strings") // lexical sort by strings. this *is* the default for maps; it overrides source-order sorting for structs. KeySortMode_RFC7049 = KeySortMode("rfc7049") // "Canonical" as proposed by rfc7049 § 3.9 (shorter byte sequences sort to top). )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Atlas ¶
type Atlas struct {
// contains filtered or unexported fields
}
func Build ¶
func Build(entries ...*AtlasEntry) (Atlas, error)
func MustBuild ¶
func MustBuild(entries ...*AtlasEntry) Atlas
func (Atlas) Get ¶
func (atl Atlas) Get(rtid uintptr) (*AtlasEntry, bool)
Gets the AtlasEntry for a typeID. Used by obj package, not meant for user facing.
func (Atlas) GetDefaultMapMorphism ¶
func (atl Atlas) GetDefaultMapMorphism() *MapMorphism
Gets the default map morphism config. Used by obj package, not meant for user facing.
func (Atlas) GetEntryByTag ¶
func (atl Atlas) GetEntryByTag(tag int) (*AtlasEntry, bool)
Gets the AtlasEntry for a tag int. Used by obj package, not meant for user facing.
func (Atlas) WithMapMorphism ¶
func (atl Atlas) WithMapMorphism(m MapMorphism) Atlas
type AtlasEntry ¶
type AtlasEntry struct { // The reflect info of the type this morphism is regarding. Type reflect.Type // Transforms the value we reached by walking (the 'live' value -- which // must be of `this.Type`) into another value (the 'serialable' value -- // which will be of `this.MarshalTransformTargetType`). // // The target type may be anything, even of a completely different Kind! // // This transform func runs first, then the resulting value is // serialized (by running through the path through Atlas again, so // chaining of transform funcs is supported, though not recommended). MarshalTransformFunc MarshalTransformFunc // The type of value we expect after using the MarshalTransformFunc. // // The match between transform func and target type should be checked // during construction of this AtlasEntry. MarshalTransformTargetType reflect.Type // Expects a different type (the 'serialable' value -- which will be of // 'this.UnmarshalTransformTargetType') than the value we reached by // walking (the 'live' value -- which must be of `this.Type`). // // The target type may be anything, even of a completely different Kind! // // The unmarshal of that target type will be run first, then the // resulting value is fed through this function to produce the real value, // which is then placed correctly into bigger mid-unmarshal object tree. // // For non-primitives, unmarshal of the target type will always target // an empty pointer or empty slice, roughly as per if it was // operating on a value produced by `TargetType.New()`. UnmarshalTransformFunc UnmarshalTransformFunc // The type of value we will manufacture an instance of and unmarshal // into, then when done provide to the UnmarshalTransformFunc. // // The match between transform func and target type should be checked // during construction of this AtlasEntry. UnmarshalTransformTargetType reflect.Type // A "tag" to emit when marshalling this type of value; // and when unmarshalling, this tag will cause unmarshal to pick // this atlas (and if there's conflicting type info, error). Tag int // Flag for whether the Tag feature should be used (zero is a valid tag). Tagged bool // A mapping of fields in a struct to serial keys. // Only valid if `this.Type.Kind() == Struct`. StructMap *StructMap // Configuration for how to traverse a map kind. // Only valid if `this.Type.Kind() == Map`. MapMorphism *MapMorphism // Configuration for how to pick concrete types to fill a union interface. // Only valid if `this.Type.Kind() == Interface`. UnionKeyedMorphism *UnionKeyedMorphism // A validation function which will be called for the whole value // after unmarshalling reached the end of the object. // If it returns an error, the entire unmarshal will error. // // Not used in marshalling. // Not reachable if an UnmarshalTransform is set. ValidateFn func(v interface{}) error }
The AtlasEntry is a declarative roadmap of what we should do for marshal and unmarshal of a single object, keyed by type.
There are a lot of paths your mappings might want to take:
- For a struct type, you may simply want to specify some alternate keys, or some to leave out, etc.
- For an interface type, you probably want to specify one of our interface muxing strategies with a mapping between enumstr:typeinfo (and, what to do if we get a struct we don't recognize).
- For a string, int, or other primitive, you don't need to say anything: defaults will DTRT.
- For a typedef'd string, int, or other primitive, you *still* don't need to say anything: but, if you want custom behavior (say, transform the string to an int at the last second, and back again), you can specify transformer functions for that.
- For a struct type that you want to turn into a whole different kind (like a string): use those same transform functions. (You'll no longer need a FieldMap.)
- For the most esoteric needs, you can fall all the way back to providing a custom MarshalMachine (but avoid that; it's a lot of work, and one of these other transform methods should suffice).
func AutogenerateStructMapEntry ¶
func AutogenerateStructMapEntry(rt reflect.Type) *AtlasEntry
func AutogenerateStructMapEntryUsingTags ¶
func AutogenerateStructMapEntryUsingTags(rt reflect.Type, tagName string, sorter KeySortMode) *AtlasEntry
type BuilderCore ¶
type BuilderCore struct {
// contains filtered or unexported fields
}
Intermediate step in building an AtlasEntry: use `BuildEntry` to get one of these to start with, then call one of the methods on this type to get a specialized builder which has the methods relevant for setting up that specific kind of mapping.
One full example of using this builder may look like the following:
atlas.BuildEntry(Formula{}).StructMap().Autogenerate().Complete()
Some intermediate manipulations may be performed on this object, for example setting the "tag" (if you want to use cbor tagging), before calling the specializer method. In this case, just keep chaining the configuration calls like so:
atlas.BuildEntry(Formula{}).UseTag(4000) .StructMap().Autogenerate().Complete()
func BuildEntry ¶
func BuildEntry(typeHintObj interface{}) *BuilderCore
func (*BuilderCore) KeyedUnion ¶
func (x *BuilderCore) KeyedUnion() *BuilderUnionKeyedMorphism
func (*BuilderCore) MapMorphism ¶
func (x *BuilderCore) MapMorphism() *BuilderMapMorphism
func (*BuilderCore) StructMap ¶
func (x *BuilderCore) StructMap() *BuilderStructMap
func (*BuilderCore) Transform ¶
func (x *BuilderCore) Transform() *BuilderTransform
func (*BuilderCore) UseTag ¶
func (x *BuilderCore) UseTag(tag int) *BuilderCore
type BuilderMapMorphism ¶
type BuilderMapMorphism struct {
// contains filtered or unexported fields
}
func (*BuilderMapMorphism) Complete ¶
func (x *BuilderMapMorphism) Complete() *AtlasEntry
func (*BuilderMapMorphism) SetKeySortMode ¶
func (x *BuilderMapMorphism) SetKeySortMode(km KeySortMode) *BuilderMapMorphism
type BuilderStructMap ¶
type BuilderStructMap struct {
// contains filtered or unexported fields
}
func (*BuilderStructMap) AddField ¶
func (x *BuilderStructMap) AddField(fieldName string, mapping StructMapEntry) *BuilderStructMap
Add a field to the mapping based on its name.
Given a struct:
struct{ X int Y struct{ Z int } }
`AddField("X", {"x", ...}) will cause that field to be serialized as key "x"; `AddField("Y.Z", {"z", ...})` will cause that *nested* field to be serialized as key "z" in the same object (e.g. "x" and "z" will be siblings).
Returns the mutated builder for convenient call chaining.
If the fieldName string doesn't map onto the structure type info, a panic will be raised.
func (*BuilderStructMap) Autogenerate ¶
func (x *BuilderStructMap) Autogenerate() *BuilderStructMap
Automatically generate mappings by looking at the struct type info, taking any hints from tags, and appending that to the builder.
You may use autogeneration in concert with manually adding field mappings, though if doing so be mindful not to map the same fields twice.
func (*BuilderStructMap) AutogenerateWithSortingScheme ¶
func (x *BuilderStructMap) AutogenerateWithSortingScheme(sorting KeySortMode) *BuilderStructMap
Automatically generate mappings using a given struct field sorting scheme
func (*BuilderStructMap) Complete ¶
func (x *BuilderStructMap) Complete() *AtlasEntry
func (*BuilderStructMap) IgnoreKey ¶
func (x *BuilderStructMap) IgnoreKey(serialKeyName string) *BuilderStructMap
type BuilderTransform ¶
type BuilderTransform struct {
// contains filtered or unexported fields
}
func (*BuilderTransform) Complete ¶
func (x *BuilderTransform) Complete() *AtlasEntry
func (*BuilderTransform) TransformMarshal ¶
func (x *BuilderTransform) TransformMarshal(trFunc MarshalTransformFunc, toType reflect.Type) *BuilderTransform
func (*BuilderTransform) TransformUnmarshal ¶
func (x *BuilderTransform) TransformUnmarshal(trFunc UnmarshalTransformFunc, toType reflect.Type) *BuilderTransform
type BuilderUnionKeyedMorphism ¶
type BuilderUnionKeyedMorphism struct {
// contains filtered or unexported fields
}
func (*BuilderUnionKeyedMorphism) Of ¶
func (x *BuilderUnionKeyedMorphism) Of(elements map[string]*AtlasEntry) *AtlasEntry
type ErrStructureMismatch ¶
Error type raised when initializing an Atlas, and field entries do not resolve against the type. (If you recently refactored names of fields in your types, check to make sure you updated any references to those fields by name to match!)
func (ErrStructureMismatch) Error ¶
func (e ErrStructureMismatch) Error() string
type MapMorphism ¶
type MapMorphism struct {
KeySortMode KeySortMode
}
type MarshalTransformFunc ¶
func MakeMarshalTransformFunc ¶
func MakeMarshalTransformFunc(fn interface{}) (MarshalTransformFunc, reflect.Type)
Takes a wildcard object which must be `func (live T1) (serialable T2, error)` and returns a MarshalTransformFunc and the typeinfo of T2.
type ReflectRoute ¶
type ReflectRoute []int
func (ReflectRoute) TraverseToValue ¶
func (rr ReflectRoute) TraverseToValue(v reflect.Value) reflect.Value
type StructMap ¶
type StructMap struct { // A slice of descriptions of each field in the type. // Each entry specifies the name by which each field should be referenced // when serialized, and defines a way to get an address to the field. Fields []StructMapEntry }
type StructMapEntry ¶
type StructMapEntry struct { // The field name; will be emitted as token during marshal, and used for // lookup during unmarshal. Required. SerialName string // If true, a key token with this SerialName will be ignored during unmarshal. // (By default, if there's no StructMapEntry for a key token, it's an error.) // If true, the ReflectRoute, Type, etc fields are irrelevant and may be nil. Ignore bool ReflectRoute ReflectRoute // reflection generates these. Type reflect.Type // type to expect on the far side of the ReflectRoute. // If true, marshalling will skip this field if it's the zero value. OmitEmpty bool // contains filtered or unexported fields }
type StructMapEntry_RFC7049 ¶
type StructMapEntry_RFC7049 []StructMapEntry
StructMapEntry_RFC7049 sorts fields as specified in RFC7049,
func (StructMapEntry_RFC7049) Len ¶
func (x StructMapEntry_RFC7049) Len() int
func (StructMapEntry_RFC7049) Less ¶
func (x StructMapEntry_RFC7049) Less(i, j int) bool
func (StructMapEntry_RFC7049) Swap ¶
func (x StructMapEntry_RFC7049) Swap(i, j int)
type StructMapEntry_byFieldRoute ¶
type StructMapEntry_byFieldRoute []StructMapEntry
StructMapEntry_byFieldRoute sorts field by FieldRoute sequence (e.g., roughly source declaration order within each type).
func (StructMapEntry_byFieldRoute) Len ¶
func (x StructMapEntry_byFieldRoute) Len() int
func (StructMapEntry_byFieldRoute) Less ¶
func (x StructMapEntry_byFieldRoute) Less(i, j int) bool
func (StructMapEntry_byFieldRoute) Swap ¶
func (x StructMapEntry_byFieldRoute) Swap(i, j int)
type StructMapEntry_byName ¶
type StructMapEntry_byName []StructMapEntry
StructMapEntry_byName sorts field by name, breaking ties with depth, then breaking ties with "name came from tag", then breaking ties with FieldRoute sequence.
func (StructMapEntry_byName) Len ¶
func (x StructMapEntry_byName) Len() int
func (StructMapEntry_byName) Less ¶
func (x StructMapEntry_byName) Less(i, j int) bool
func (StructMapEntry_byName) Swap ¶
func (x StructMapEntry_byName) Swap(i, j int)
type UnionKeyedMorphism ¶
type UnionKeyedMorphism struct { // Mapping of typehint key strings to atlasEntry that should be delegated to. Elements map[string]*AtlasEntry // Mapping of rtid to string (roughly the dual of the Elements map). Mappings map[uintptr]string // Purely to have in readiness for error messaging. KnownMembers []string }
type UnmarshalTransformFunc ¶
func MakeUnmarshalTransformFunc ¶
func MakeUnmarshalTransformFunc(fn interface{}) (UnmarshalTransformFunc, reflect.Type)
Takes a wildcard object which must be `func (serialable T1) (live T2, error)` and returns a UnmarshalTransformFunc and the typeinfo of T1.