encode.go (5274B)
1 package msgpack 2 3 import ( 4 "bytes" 5 "io" 6 "reflect" 7 "sync" 8 "time" 9 10 "github.com/vmihailenco/msgpack/v5/msgpcode" 11 ) 12 13 const ( 14 sortMapKeysFlag uint32 = 1 << iota 15 arrayEncodedStructsFlag 16 useCompactIntsFlag 17 useCompactFloatsFlag 18 useInternedStringsFlag 19 omitEmptyFlag 20 ) 21 22 type writer interface { 23 io.Writer 24 WriteByte(byte) error 25 } 26 27 type byteWriter struct { 28 io.Writer 29 } 30 31 func newByteWriter(w io.Writer) byteWriter { 32 return byteWriter{ 33 Writer: w, 34 } 35 } 36 37 func (bw byteWriter) WriteByte(c byte) error { 38 _, err := bw.Write([]byte{c}) 39 return err 40 } 41 42 //------------------------------------------------------------------------------ 43 44 var encPool = sync.Pool{ 45 New: func() interface{} { 46 return NewEncoder(nil) 47 }, 48 } 49 50 func GetEncoder() *Encoder { 51 return encPool.Get().(*Encoder) 52 } 53 54 func PutEncoder(enc *Encoder) { 55 enc.w = nil 56 encPool.Put(enc) 57 } 58 59 // Marshal returns the MessagePack encoding of v. 60 func Marshal(v interface{}) ([]byte, error) { 61 enc := GetEncoder() 62 63 var buf bytes.Buffer 64 enc.Reset(&buf) 65 66 err := enc.Encode(v) 67 b := buf.Bytes() 68 69 PutEncoder(enc) 70 71 if err != nil { 72 return nil, err 73 } 74 return b, err 75 } 76 77 type Encoder struct { 78 w writer 79 80 buf []byte 81 timeBuf []byte 82 83 dict map[string]int 84 85 flags uint32 86 structTag string 87 } 88 89 // NewEncoder returns a new encoder that writes to w. 90 func NewEncoder(w io.Writer) *Encoder { 91 e := &Encoder{ 92 buf: make([]byte, 9), 93 } 94 e.Reset(w) 95 return e 96 } 97 98 // Writer returns the Encoder's writer. 99 func (e *Encoder) Writer() io.Writer { 100 return e.w 101 } 102 103 // Reset discards any buffered data, resets all state, and switches the writer to write to w. 104 func (e *Encoder) Reset(w io.Writer) { 105 e.ResetDict(w, nil) 106 } 107 108 // ResetDict is like Reset, but also resets the dict. 109 func (e *Encoder) ResetDict(w io.Writer, dict map[string]int) { 110 e.resetWriter(w) 111 e.flags = 0 112 e.structTag = "" 113 e.dict = dict 114 } 115 116 func (e *Encoder) WithDict(dict map[string]int, fn func(*Encoder) error) error { 117 oldDict := e.dict 118 e.dict = dict 119 err := fn(e) 120 e.dict = oldDict 121 return err 122 } 123 124 func (e *Encoder) resetWriter(w io.Writer) { 125 if bw, ok := w.(writer); ok { 126 e.w = bw 127 } else { 128 e.w = newByteWriter(w) 129 } 130 } 131 132 // SetSortMapKeys causes the Encoder to encode map keys in increasing order. 133 // Supported map types are: 134 // - map[string]string 135 // - map[string]interface{} 136 func (e *Encoder) SetSortMapKeys(on bool) *Encoder { 137 if on { 138 e.flags |= sortMapKeysFlag 139 } else { 140 e.flags &= ^sortMapKeysFlag 141 } 142 return e 143 } 144 145 // SetCustomStructTag causes the Encoder to use a custom struct tag as 146 // fallback option if there is no msgpack tag. 147 func (e *Encoder) SetCustomStructTag(tag string) { 148 e.structTag = tag 149 } 150 151 // SetOmitEmpty causes the Encoder to omit empty values by default. 152 func (e *Encoder) SetOmitEmpty(on bool) { 153 if on { 154 e.flags |= omitEmptyFlag 155 } else { 156 e.flags &= ^omitEmptyFlag 157 } 158 } 159 160 // UseArrayEncodedStructs causes the Encoder to encode Go structs as msgpack arrays. 161 func (e *Encoder) UseArrayEncodedStructs(on bool) { 162 if on { 163 e.flags |= arrayEncodedStructsFlag 164 } else { 165 e.flags &= ^arrayEncodedStructsFlag 166 } 167 } 168 169 // UseCompactEncoding causes the Encoder to chose the most compact encoding. 170 // For example, it allows to encode small Go int64 as msgpack int8 saving 7 bytes. 171 func (e *Encoder) UseCompactInts(on bool) { 172 if on { 173 e.flags |= useCompactIntsFlag 174 } else { 175 e.flags &= ^useCompactIntsFlag 176 } 177 } 178 179 // UseCompactFloats causes the Encoder to chose a compact integer encoding 180 // for floats that can be represented as integers. 181 func (e *Encoder) UseCompactFloats(on bool) { 182 if on { 183 e.flags |= useCompactFloatsFlag 184 } else { 185 e.flags &= ^useCompactFloatsFlag 186 } 187 } 188 189 // UseInternedStrings causes the Encoder to intern strings. 190 func (e *Encoder) UseInternedStrings(on bool) { 191 if on { 192 e.flags |= useInternedStringsFlag 193 } else { 194 e.flags &= ^useInternedStringsFlag 195 } 196 } 197 198 func (e *Encoder) Encode(v interface{}) error { 199 switch v := v.(type) { 200 case nil: 201 return e.EncodeNil() 202 case string: 203 return e.EncodeString(v) 204 case []byte: 205 return e.EncodeBytes(v) 206 case int: 207 return e.EncodeInt(int64(v)) 208 case int64: 209 return e.encodeInt64Cond(v) 210 case uint: 211 return e.EncodeUint(uint64(v)) 212 case uint64: 213 return e.encodeUint64Cond(v) 214 case bool: 215 return e.EncodeBool(v) 216 case float32: 217 return e.EncodeFloat32(v) 218 case float64: 219 return e.EncodeFloat64(v) 220 case time.Duration: 221 return e.encodeInt64Cond(int64(v)) 222 case time.Time: 223 return e.EncodeTime(v) 224 } 225 return e.EncodeValue(reflect.ValueOf(v)) 226 } 227 228 func (e *Encoder) EncodeMulti(v ...interface{}) error { 229 for _, vv := range v { 230 if err := e.Encode(vv); err != nil { 231 return err 232 } 233 } 234 return nil 235 } 236 237 func (e *Encoder) EncodeValue(v reflect.Value) error { 238 fn := getEncoder(v.Type()) 239 return fn(e, v) 240 } 241 242 func (e *Encoder) EncodeNil() error { 243 return e.writeCode(msgpcode.Nil) 244 } 245 246 func (e *Encoder) EncodeBool(value bool) error { 247 if value { 248 return e.writeCode(msgpcode.True) 249 } 250 return e.writeCode(msgpcode.False) 251 } 252 253 func (e *Encoder) EncodeDuration(d time.Duration) error { 254 return e.EncodeInt(int64(d)) 255 } 256 257 func (e *Encoder) writeCode(c byte) error { 258 return e.w.WriteByte(c) 259 } 260 261 func (e *Encoder) write(b []byte) error { 262 _, err := e.w.Write(b) 263 return err 264 } 265 266 func (e *Encoder) writeString(s string) error { 267 _, err := e.w.Write(stringToBytes(s)) 268 return err 269 }