123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- 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")
- }
|