Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package structmap
- import (
- "fmt"
- "reflect"
- "strings"
- )
- type Options struct {
- Strict bool
- NameMapper func(name string) string
- }
- func applyDefaults(o *Options) *Options {
- if o == nil {
- o = &Options{}
- }
- if o.NameMapper == nil {
- o.NameMapper = normalizeName
- }
- return o
- }
- func MapToStruct(m map[string]interface{}, s interface{}, o *Options) error {
- o = applyDefaults(o)
- val := reflect.ValueOf(s).Elem()
- fields := make(map[string]reflect.Value)
- fieldMap(val, fields, o)
- for name, value := range m {
- field, ok := fields[o.NameMapper(name)]
- if !ok {
- if o.Strict {
- return fmt.Errorf("missing field %s", name)
- }
- continue
- }
- if !field.CanSet() {
- return fmt.Errorf("cannot set %s field value", name)
- }
- val := reflect.ValueOf(value)
- if field.Type() != val.Type() {
- return fmt.Errorf("invalid type for field %s", name)
- }
- field.Set(val)
- }
- return nil
- }
- func normalizeName(name string) string {
- name = strings.Replace(name, "_", "", -1)
- name = strings.Replace(name, "-", "", -1)
- return strings.ToLower(name)
- }
- func fieldMap(s reflect.Value, m map[string]reflect.Value, o *Options) {
- var embedded []reflect.Value
- for i := 0; i < s.NumField(); i++ {
- typ := s.Type().Field(i)
- val := s.Field(i)
- if typ.Anonymous {
- embedded = append(embedded, val)
- }
- name := o.NameMapper(typ.Name)
- if _, ok := m[name]; !ok {
- m[name] = val
- }
- }
- for _, val := range embedded {
- fieldMap(val, m, o)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement