package ini import ( "encoding" "fmt" "reflect" "strconv" ) var ( unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem() textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() ) type Unmarshaler interface { UnmarshalINI([]byte) error } type valueDecoder func([]byte) error type field struct { ns string t reflect.Type v reflect.Value p interface{} f valueDecoder } type decoder struct { scan *scanner ns map[string]*field nss string } func Unmarshal(d []byte, v interface{}) error { dec := &decoder{ scan: newScanner(d), ns: make(map[string]*field), } if err := dec.scan.valid(); err != nil { fmt.Println("ERROR, invalid", err) return err } return dec.unmarshal(v) } func (d *decoder) unmarshal(v interface{}) error { rv := reflect.ValueOf(v) d.imap("", rv, nil, 0) fmt.Println(d.ns) ns := d.nss for elem, err := d.scan.next(); err == EOL; elem, err = d.scan.next() { switch elem.t { case section: ns = d.nss + "." + string(elem.key) case variable: key := ns + "." + string(elem.key) if f, ok := d.ns[key]; ok { if err := f.f(elem.val); err != nil { fmt.Println(err) } } } } return nil } func (d *decoder) ns_append(ns string, f *field) string { if f.p == nil { f.ns = ns + "." + f.t.Name() return f.ns } if tag := f.p.(reflect.StructField).Tag.Get("ini"); len(tag) != 0 { f.ns = ns + "." + tag return f.ns } f.ns = ns + "." + f.p.(reflect.StructField).Name return f.ns } func (d *decoder) imap(ns string, v reflect.Value, p interface{}, i int) { f := &field{ t: v.Type(), v: v, p: nil, } if p != nil { f.p = p.(reflect.Type).Field(i) } if f.t.Implements(unmarshalerType) { f.f = f.unmDecoder d.ns[d.ns_append(ns, f)] = f return } switch f.v.Kind() { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: f.f = f.uintDecoder d.ns[d.ns_append(ns, f)] = f case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: f.f = f.intDecoder d.ns[d.ns_append(ns, f)] = f case reflect.String: f.f = f.strDecoder d.ns[d.ns_append(ns, f)] = f case reflect.Bool: f.f = f.boolDecoder d.ns[d.ns_append(ns, f)] = f case reflect.Struct: if len(d.nss) == 0 { d.nss = d.ns_append(ns, f) } for i := 0; i < f.v.NumField(); i++ { d.imap(d.ns_append(ns, f), f.v.Field(i), f.t, i) } case reflect.Ptr: if f.v.IsNil() { return } d.imap(ns, f.v.Elem(), nil, i) default: fmt.Printf("OTHER TYPE: %v", f.t.Name()) } } func (f *field) valid() error { if f.v.CanAddr() { return nil } return fmt.Errorf("Field '%s' not addressable", f.ns) } func (f *field) uintDecoder(b []byte) error { if err := f.valid(); err != nil { return err } i, err := strconv.ParseUint(string(b), 10, 64) if err != nil { return err } f.v.SetUint(i) return nil } func (f *field) intDecoder(b []byte) error { if err := f.valid(); err != nil { return err } i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return err } f.v.SetInt(i) return nil } func (f *field) strDecoder(b []byte) error { if err := f.valid(); err != nil { return err } f.v.SetString(string(b)) return nil } func (f *field) boolDecoder(b []byte) error { if err := f.valid(); err != nil { return err } f.v.SetBool(true) return nil } func (f *field) unmDecoder(b []byte) error { if err := f.valid(); err != nil { return err } v := f.v if v.Kind() != reflect.Ptr && v.Type().Name() != "" { v = v.Addr() } if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } if i, ok := v.Interface().(Unmarshaler); ok { err := i.UnmarshalINI(b) return err } return fmt.Errorf("Cannot load Unmarshaler") }