Documentation ¶
Overview ¶
Package typeregistry is a generic system to instantiate types by name. Since go cannot instantiate a type directly, we must first register any type that we would later like to instantiate. The registry handles these mechanics for you.
In addition, the registry supports marshal, unmarshal, and custom setup injection for getting objects in and out of storage.
Marshaling an object results in the registered name of the type, plus byte data if the type implements Marshaler.
Unmarshaling performs the reverse operation, first instantiating the type by name, then using Unmarshaler (if implemented) to populate the object (note that the type should probably be a pointer reciever for this to be useful). If the object requires collaborators, or data from the outside world then a function can be passed to Unmarshal that receives the object after it's instantiated and before it's unmarshaled.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var NoSetup = func(i interface{}) {}
NoSetup is a SetupFunc that does nothing. It is functionally equivalent to passing nil, but it's more descriptive so please do.
Functions ¶
This section is empty.
Types ¶
type Marshaler ¶
Marshaler is implemented by any type that can encode a copy of itself. The style of encoding doesn't matter, it will only be seen by Unmarshaler.
type SetupFunc ¶
type SetupFunc func(interface{})
SetupFunc is passed to Unmarshal to manually manipulate the object after it's instantiated, but before it's unmarshaled. This can be used to set dependencies that are needed during unmarshal. For example, to covert a user's ID to a user object.
type TypeRegistry ¶
TypeRegistry can instantiate, marshal, and unmarshal types from string names and type-defined encodings.
func (TypeRegistry) Add ¶
func (r TypeRegistry) Add(o interface{}) string
Add puts a new type in the registry. If the type cannot be registered, it panics. It returns the name that it was registered as.
func (TypeRegistry) Marshal ¶
func (r TypeRegistry) Marshal(o interface{}) (string, []byte, error)
Marshal encodes a type. If the type implements Marshaler or its bytes are returned.
func (TypeRegistry) New ¶
func (r TypeRegistry) New(name string) interface{}
New instantiates a type by name. If the name is unknown, it panics.
Example ¶
package main import ( "fmt" "github.com/rcarver/typeregistry" ) type simpleThing struct { Name string } func main() { registry := typeregistry.New() name := registry.Add(simpleThing{}) thing := registry.New(name) fmt.Printf("%#v", thing) }
Output: typeregistry_test.simpleThing{Name:""}
func (TypeRegistry) Unmarshal ¶
func (r TypeRegistry) Unmarshal(name string, data []byte, setup SetupFunc) (interface{}, error)
Unmarshal decodes a type by name. If the type implements Unmarshaler, the data is used to unmarshal. SetupFunc can be passed to inject any other data into the type before it is unmarshaled.
Example ¶
package main import ( "encoding/json" "fmt" "github.com/rcarver/typeregistry" ) // User is your typical user struct. type User struct { ID string Name string } // UserService is your typical service backend to retrieve users. type UserService struct { users []*User } // FindUser returns a user by id. func (s *UserService) FindUser(id string) *User { for _, u := range s.users { if u.ID == id { return u } } return nil } // userThing is a sample struct that can marshal/unmarshal itself and requires // a service collaborator when doing so. type userThing struct { UserID string user *User svc *UserService } func (t *userThing) Marshal() ([]byte, error) { // We store the ID when marshaling so we can look it up fresh when // unmarshaled. t.UserID = t.user.ID return json.Marshal(t) } func (t *userThing) Unmarshal(data []byte) error { // Unmarshal, getting the UserID. if err := json.Unmarshal(data, t); err != nil { return err } // Use the UserID and injected service to restore the user. t.user = t.svc.FindUser(t.UserID) return nil } func main() { registry := typeregistry.New() registry.Add(&userThing{}) // The service world. var ( ryan = &User{"1", "Ryan"} svc = &UserService{[]*User{ryan}} sample = &userThing{user: ryan} ) // Pass between marshal and unmarshal. var ( name string data []byte ) // Marshal it. func() { var err error name, data, err = registry.Marshal(sample) if err != nil { panic(err) } fmt.Printf("Sample marshaled name:%s data:%s\n", name, data) }() // Unmarshal it with custom setup. func() { si, err := registry.Unmarshal(name, data, func(o interface{}) { if s, ok := o.(*userThing); ok { s.svc = svc } }) if err != nil { panic(err) } sample := si.(*userThing) fmt.Printf("Sample unmarshaled with ID:%s, Name:%s\n", sample.UserID, sample.user.Name) }() }
Output: Sample marshaled name:*typeregistry_test.userThing data:{"UserID":"1"} Sample unmarshaled with ID:1, Name:Ryan
type Unmarshaler ¶
Unmarshaler is implemented by any type that can decode of a copy of itself, as returned by its Marshal method.