decode.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. package ini
  2. // Decode INI-fomatted data into an interface (typically a struct)
  3. // Known types:
  4. // - Any kind of ints
  5. // - Any kind of unsigned ints
  6. // - Structs + pointers
  7. // - Boolean
  8. // - Strings
  9. // - Types with the method `UnmarshalText`
  10. //
  11. // Unknown types (also known types!) can impement the method UnmarshalINI
  12. // to be to override standard unmarshaling method, or make marshalable if it's not.
  13. //
  14. // e.g: see types.go and the Time example. Time does implement MarshalText, but it doesnt
  15. // store the time-value in a very readable/editable manner, so the ini.Time is just a
  16. // wrapper-struct with the Marshaler-interface to read/write the time-value differently.
  17. import (
  18. "reflect"
  19. )
  20. // Unmarshaler is an interface to implement for unknown types
  21. type Unmarshaler interface {
  22. UnmarshalINI([]byte) error
  23. }
  24. type decoder struct {
  25. scan *scanner
  26. ns map[string]*field
  27. nss string
  28. }
  29. // Unmarshal decodes byte-array/slice containing INI into interface v
  30. func Unmarshal(d []byte, v interface{}) error {
  31. dec := &decoder{
  32. scan: newScanner(d),
  33. ns: make(map[string]*field),
  34. }
  35. // Ensure data is valid before reflecting
  36. if err := dec.scan.valid(); err != nil {
  37. return err
  38. }
  39. // Map struct -> INI
  40. return dec.unmarshal(v)
  41. }
  42. // umarshal does the actual mapping by first collecting struct data
  43. // then scanning ini-file and mapping data to the struct.
  44. func (d *decoder) unmarshal(v interface{}) error {
  45. rv := reflect.ValueOf(v)
  46. d.imap("", rv, nil, 0)
  47. ns := d.nss
  48. for elem, err := d.scan.next(); err == EOL || err == EOF; elem, err = d.scan.next() {
  49. switch elem.t {
  50. case section:
  51. ns = d.nss + "." + string(elem.key)
  52. case variable:
  53. key := ns + "." + string(elem.key)
  54. if f, ok := d.ns[key]; ok {
  55. if err := f.decode(elem.val); err != nil {
  56. return err
  57. }
  58. }
  59. }
  60. if err == EOF {
  61. break
  62. }
  63. }
  64. return nil
  65. }
  66. // nsmap is a mapper function, storing each entry on a given namespace
  67. func (d *decoder) nsmap(ns string, f *field, fn decodeFn) {
  68. f.setFn(fn)
  69. d.ns[f.setNS(ns)] = f
  70. }
  71. // imap maps interface data into namespaces
  72. func (d *decoder) imap(ns string, v reflect.Value, p interface{}, i int) {
  73. f := newField(v, p, i)
  74. if f.implements(unmarshalerType) || f.implements(textUnmarshalerType) {
  75. d.nsmap(ns, f, f.unmarshalerDecoder)
  76. return
  77. }
  78. switch f.v.Kind() {
  79. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  80. d.nsmap(ns, f, f.uintDecoder)
  81. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  82. d.nsmap(ns, f, f.intDecoder)
  83. case reflect.String:
  84. d.nsmap(ns, f, f.strDecoder)
  85. case reflect.Bool:
  86. d.nsmap(ns, f, f.boolDecoder)
  87. case reflect.Float32:
  88. d.nsmap(ns, f, f.float32Decoder)
  89. case reflect.Float64:
  90. d.nsmap(ns, f, f.float64Decoder)
  91. case reflect.Struct:
  92. if len(d.nss) == 0 {
  93. d.nss = f.setNS(ns)
  94. }
  95. for i := 0; i < f.v.NumField(); i++ {
  96. d.imap(f.setNS(ns), f.v.Field(i), f.t, i)
  97. }
  98. case reflect.Ptr:
  99. if f.v.IsNil() {
  100. return
  101. }
  102. d.imap(ns, f.v.Elem(), nil, i)
  103. default:
  104. }
  105. }