| package builder | |
| import ( | |
| "reflect" | |
| "sync" | |
| ) | |
| var ( | |
| registry = make(map[reflect.Type]reflect.Type) | |
| registryMux sync.RWMutex | |
| ) | |
| // RegisterType maps the given builderType to a structType. | |
| // This mapping affects the type of slices returned by Get and is required for | |
| // GetStruct to work. | |
| // | |
| // Returns a Value containing an empty instance of the registered builderType. | |
| // | |
| // RegisterType will panic if builderType's underlying type is not Builder or | |
| // if structType's Kind is not Struct. | |
| func RegisterType(builderType reflect.Type, structType reflect.Type) *reflect.Value { | |
| registryMux.Lock() | |
| defer registryMux.Unlock() | |
| structType.NumField() // Panic if structType is not a struct | |
| registry[builderType] = structType | |
| emptyValue := emptyBuilderValue.Convert(builderType) | |
| return &emptyValue | |
| } | |
| // Register wraps RegisterType, taking instances instead of Types. | |
| // | |
| // Returns an empty instance of the registered builder type which can be used | |
| // as the initial value for builder expressions. See example. | |
| func Register(builderProto, structProto interface{}) interface{} { | |
| empty := RegisterType( | |
| reflect.TypeOf(builderProto), | |
| reflect.TypeOf(structProto), | |
| ).Interface() | |
| return empty | |
| } | |
| func getBuilderStructType(builderType reflect.Type) *reflect.Type { | |
| registryMux.RLock() | |
| defer registryMux.RUnlock() | |
| structType, ok := registry[builderType] | |
| if !ok { | |
| return nil | |
| } | |
| return &structType | |
| } | |
| func newBuilderStruct(builderType reflect.Type) *reflect.Value { | |
| structType := getBuilderStructType(builderType) | |
| if structType == nil { | |
| return nil | |
| } | |
| newStruct := reflect.New(*structType).Elem() | |
| return &newStruct | |
| } |