Documentation
¶
Overview ¶
Package xtypes implements Dynamic Data for go-DDS (Milestone 9).
XTypes provides a runtime type system that allows distributed systems to evolve their data schemas without lock-step software updates. It is loosely aligned with the OMG DDS-XTypes 1.3 specification but simplified for idiomatic Go use.
Type System ¶
A TypeDescriptor describes the structure of a named type: its fields, their primitive kinds, and optional/required status. A TypeIdentifier is a compact, content-addressed fingerprint of a descriptor derived from its stable canonical hash.
Dynamic Data ¶
DynamicData is a schema-validated property map: values may only be set on fields declared in the associated TypeDescriptor. It serialises transparently to/from JSON.
Type Registry ¶
TypeRegistry is a thread-safe store of TypeObject values (descriptor + identifier pairs). Participants use the registry to announce their types and to resolve types received from peers.
Compatibility Checking ¶
CheckCompatibility implements the standard forward/backward type evolution rules:
- New optional fields added to the writer are invisible but harmless to an older reader (forward compatibility).
- New required fields expected by the reader but absent from the writer are incompatible (the reader would receive data it cannot interpret).
- Renamed or type-changed fields are always incompatible.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrTypeMismatch = errors.New("xtypes: type name already registered with different structure")
ErrTypeMismatch is returned by TypeRegistry.Register when a type with the same name but a different hash is already registered.
var GlobalTopicRegistry = NewTopicTypeRegistry()
GlobalTopicRegistry is the process-wide default TopicTypeRegistry. RegisterTopicCodec and LookupTopicType use this registry by default.
Functions ¶
func RegisterTopicCodec ¶ added in v0.10.0
func RegisterTopicCodec[T any](r *TopicTypeRegistry, topic string, _ dds.Codec[T])
RegisterTopicCodec records that topic is encoded with codec[T]. The association between topic and the Go type T is stored in r (pass GlobalTopicRegistry for the process-wide default). The codec parameter is used only for type inference; it is not stored.
Types ¶
type CompatibilityResult ¶
type CompatibilityResult struct {
Compatible bool // true if reader and writer are compatible
Reason string // human-readable explanation when Compatible is false
}
CompatibilityResult describes whether a reader using one type descriptor can safely consume data produced by a writer using another.
func CheckCompatibility ¶
func CheckCompatibility(writerTD, readerTD *TypeDescriptor) CompatibilityResult
CheckCompatibility reports whether a reader using readerTD can safely consume data written by a writer using writerTD.
The rules follow standard schema-evolution conventions:
- Fields present in writer but absent in reader: always OK (forward compat).
- Fields present in reader but absent in writer: OK only if Optional in reader.
- Fields present in both: compatible only if they have the same Kind.
type DynamicData ¶
type DynamicData struct {
// contains filtered or unexported fields
}
DynamicData is a schema-validated property map. Values can only be set on fields declared in the associated TypeDescriptor.
DynamicData is NOT safe for concurrent use from multiple goroutines.
func NewDynamicData ¶
func NewDynamicData(td *TypeDescriptor) *DynamicData
NewDynamicData creates a DynamicData backed by td.
func (*DynamicData) FromJSON ¶
func (d *DynamicData) FromJSON(data []byte) error
FromJSON populates set fields from JSON. Only keys that match declared fields in the descriptor are stored; unknown keys are silently ignored (forward compatibility: old code reads new data).
func (*DynamicData) Get ¶
func (d *DynamicData) Get(name string) (any, bool)
Get returns the value for name. The second return is false if the field has not been set (even if it is declared in the descriptor).
func (*DynamicData) Set ¶
func (d *DynamicData) Set(name string, value any) error
Set sets the named field to value. Returns an error if name does not exist in the descriptor.
func (*DynamicData) ToJSON ¶
func (d *DynamicData) ToJSON() ([]byte, error)
ToJSON serialises the set fields to JSON.
func (*DynamicData) TypeDescriptor ¶
func (d *DynamicData) TypeDescriptor() *TypeDescriptor
TypeDescriptor returns the schema backing this DynamicData.
type FieldDescriptor ¶
type FieldDescriptor struct {
Name string // field name; must be unique within its parent
Kind TypeKind // primitive kind
Optional bool // if false, the field is required
Fields []FieldDescriptor // for KindStruct: nested field descriptors
Element *FieldDescriptor // for KindSeq: element type descriptor
}
FieldDescriptor describes one field within a TypeDescriptor.
type TopicCodecInfo ¶ added in v0.10.0
type TopicCodecInfo struct {
// Topic is the DDS topic name.
Topic string
// TypeName is the Go reflect type name of the value type (e.g. "main.Reading").
TypeName string
}
TopicCodecInfo describes the codec registration for a topic.
type TopicTypeRegistry ¶ added in v0.10.0
type TopicTypeRegistry struct {
// contains filtered or unexported fields
}
TopicTypeRegistry maps topic names to Go value types for codec autodiscovery. It enables runtime inspection of which Go type is associated with each topic, without requiring a concrete Codec[T] value at lookup time.
Use RegisterTopicCodec to register a topic at startup, then LookupTopicType to retrieve the association anywhere in the program.
func NewTopicTypeRegistry ¶ added in v0.10.0
func NewTopicTypeRegistry() *TopicTypeRegistry
NewTopicTypeRegistry returns an empty TopicTypeRegistry.
func (*TopicTypeRegistry) All ¶ added in v0.10.0
func (r *TopicTypeRegistry) All() []TopicCodecInfo
All returns all registered topic→type associations, sorted by topic name.
func (*TopicTypeRegistry) Deregister ¶ added in v0.10.0
func (r *TopicTypeRegistry) Deregister(topic string)
Deregister removes the registration for topic. It is a no-op if topic is not registered.
func (*TopicTypeRegistry) LookupTopicType ¶ added in v0.10.0
func (r *TopicTypeRegistry) LookupTopicType(topic string) (string, bool)
LookupTopicType returns the Go type name registered for topic, or ("", false) if the topic has not been registered.
type TypeDescriptor ¶
type TypeDescriptor struct {
Name string // type name; must be unique within a [TypeRegistry]
Version uint32 // schema version; 0 = unversioned
Fields []FieldDescriptor // top-level fields
}
TypeDescriptor describes a complete named schema.
type TypeIdentifier ¶
type TypeIdentifier struct {
Name string // type name
Hash [8]byte // first 8 bytes of SHA-256(canonical JSON representation)
}
TypeIdentifier is a compact, content-addressed reference to a TypeDescriptor. Two descriptors with identical structure produce the same TypeIdentifier regardless of the order in which they were created.
func Identify ¶
func Identify(td *TypeDescriptor) TypeIdentifier
Identify computes the TypeIdentifier for td. The hash is derived from a sorted, canonical JSON encoding of the descriptor so that structurally identical types hash identically.
type TypeObject ¶
type TypeObject struct {
ID TypeIdentifier
Descriptor TypeDescriptor
}
TypeObject pairs a TypeDescriptor with its content-addressed TypeIdentifier.
func NewTypeObject ¶
func NewTypeObject(td TypeDescriptor) *TypeObject
NewTypeObject builds a TypeObject from td, computing the identifier automatically.
type TypeRegistry ¶
type TypeRegistry struct {
// contains filtered or unexported fields
}
TypeRegistry is a thread-safe store for TypeObject values.
func NewTypeRegistry ¶
func NewTypeRegistry() *TypeRegistry
NewTypeRegistry creates an empty TypeRegistry.
func (*TypeRegistry) All ¶
func (r *TypeRegistry) All() []*TypeObject
All returns a snapshot of all registered TypeObjects in name-sorted order.
func (*TypeRegistry) Lookup ¶
func (r *TypeRegistry) Lookup(name string) (*TypeObject, bool)
Lookup returns the TypeObject registered under name, if any.
func (*TypeRegistry) Register ¶
func (r *TypeRegistry) Register(to *TypeObject) error
Register stores to. Returns ErrTypeMismatch if a type with the same Name but a different hash is already registered. Registering the same TypeObject twice (same name and hash) is a no-op.