|
@@ -1,21 +1,45 @@
|
|
package ini
|
|
package ini
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
+ "encoding"
|
|
"fmt"
|
|
"fmt"
|
|
|
|
+ "reflect"
|
|
|
|
+ "strconv"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+var (
|
|
|
|
+ unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem()
|
|
|
|
+ textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
|
|
)
|
|
)
|
|
|
|
|
|
type Unmarshaler interface {
|
|
type Unmarshaler interface {
|
|
UnmarshalINI([]byte) error
|
|
UnmarshalINI([]byte) error
|
|
}
|
|
}
|
|
|
|
|
|
-type decode struct {
|
|
|
|
|
|
+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
|
|
scan *scanner
|
|
|
|
+ ns map[string]*field
|
|
|
|
+ nss string
|
|
}
|
|
}
|
|
|
|
|
|
func Unmarshal(d []byte, v interface{}) error {
|
|
func Unmarshal(d []byte, v interface{}) error {
|
|
|
|
|
|
- dec := &decode{
|
|
|
|
- newScanner(d),
|
|
|
|
|
|
+ dec := &decoder{
|
|
|
|
+ scan: newScanner(d),
|
|
|
|
+ ns: make(map[string]*field),
|
|
}
|
|
}
|
|
|
|
|
|
if err := dec.scan.valid(); err != nil {
|
|
if err := dec.scan.valid(); err != nil {
|
|
@@ -23,5 +47,177 @@ func Unmarshal(d []byte, v interface{}) error {
|
|
return 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
|
|
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")
|
|
|
|
+}
|