NewStructEncoder compiles a set of instructions for marhsaling a struct shape to a JSON document.
(t interface{})
| 77 | |
| 78 | // NewStructEncoder compiles a set of instructions for marhsaling a struct shape to a JSON document. |
| 79 | func NewStructEncoder(t interface{}) *StructEncoder { |
| 80 | e := &StructEncoder{} |
| 81 | e.t = t |
| 82 | tt := reflect.TypeOf(t) |
| 83 | |
| 84 | e.chunk("{") |
| 85 | |
| 86 | emit := 0 // track number of fields we emit |
| 87 | // pass over each field in the struct to build up our instruction set for each |
| 88 | for e.i = 0; e.i < tt.NumField(); e.i++ { |
| 89 | e.f = tt.Field(e.i) |
| 90 | |
| 91 | tag, opts := parseTag(e.f.Tag.Get("json")) // we're using tags to nominate inclusion |
| 92 | if tag == "" { |
| 93 | continue |
| 94 | } |
| 95 | emit++ |
| 96 | |
| 97 | // write the key |
| 98 | if emit > 1 { |
| 99 | e.chunk(",") |
| 100 | } |
| 101 | e.chunk(`"` + tag + `":`) |
| 102 | |
| 103 | switch { |
| 104 | /// support calling .String() when the 'stringer' option is passed |
| 105 | case opts.Contains("stringer") && reflect.ValueOf(e.t).Field(e.i).MethodByName("String").Kind() != reflect.Invalid: |
| 106 | e.optInstrStringer() |
| 107 | |
| 108 | /// support calling .JSONEncode(*Buffer) when the 'encoder' option is passed |
| 109 | case opts.Contains("encoder"): |
| 110 | |
| 111 | // requrie explicit opt-in for JSONMarshaler implementation |
| 112 | t := reflect.ValueOf(e.t).Field(e.i).Type() |
| 113 | if t.Kind() != reflect.Ptr { |
| 114 | t = reflect.PtrTo(t) |
| 115 | } |
| 116 | |
| 117 | if _, ok := t.MethodByName("EncodeJSON"); ok { |
| 118 | e.optInstrEncoderWriter() |
| 119 | break |
| 120 | } |
| 121 | |
| 122 | // default to JSONEncoder implementation for any other encoder fields |
| 123 | e.optInstrEncoder() |
| 124 | |
| 125 | /// support writing byteslice-like items using 'raw' option. |
| 126 | case opts.Contains("raw"): |
| 127 | e.optInstrRaw() |
| 128 | |
| 129 | /// suport escaping reserved json characters from byteslice-like items and slices |
| 130 | case opts.Contains("escape"): |
| 131 | e.optInstrEscape() |
| 132 | |
| 133 | /// time is a type of struct, not a kind, so somewhat of a special case here. |
| 134 | case e.f.Type == timeType: |
| 135 | e.chunk(`"`) |
| 136 | e.val(ptrTimeToBuf) |