intern.go (5029B)
1 package msgpack 2 3 import ( 4 "fmt" 5 "math" 6 "reflect" 7 8 "github.com/vmihailenco/msgpack/v5/msgpcode" 9 ) 10 11 const ( 12 minInternedStringLen = 3 13 maxDictLen = math.MaxUint16 14 ) 15 16 var internedStringExtID = int8(math.MinInt8) 17 18 func init() { 19 extTypes[internedStringExtID] = &extInfo{ 20 Type: stringType, 21 Decoder: decodeInternedStringExt, 22 } 23 } 24 25 func decodeInternedStringExt(d *Decoder, v reflect.Value, extLen int) error { 26 idx, err := d.decodeInternedStringIndex(extLen) 27 if err != nil { 28 return err 29 } 30 31 s, err := d.internedStringAtIndex(idx) 32 if err != nil { 33 return err 34 } 35 36 v.SetString(s) 37 return nil 38 } 39 40 //------------------------------------------------------------------------------ 41 42 func encodeInternedInterfaceValue(e *Encoder, v reflect.Value) error { 43 if v.IsNil() { 44 return e.EncodeNil() 45 } 46 47 v = v.Elem() 48 if v.Kind() == reflect.String { 49 return e.encodeInternedString(v.String(), true) 50 } 51 return e.EncodeValue(v) 52 } 53 54 func encodeInternedStringValue(e *Encoder, v reflect.Value) error { 55 return e.encodeInternedString(v.String(), true) 56 } 57 58 func (e *Encoder) encodeInternedString(s string, intern bool) error { 59 // Interned string takes at least 3 bytes. Plain string 1 byte + string len. 60 if len(s) >= minInternedStringLen { 61 if idx, ok := e.dict[s]; ok { 62 return e.encodeInternedStringIndex(idx) 63 } 64 65 if intern && len(e.dict) < maxDictLen { 66 if e.dict == nil { 67 e.dict = make(map[string]int) 68 } 69 idx := len(e.dict) 70 e.dict[s] = idx 71 } 72 } 73 74 return e.encodeNormalString(s) 75 } 76 77 func (e *Encoder) encodeInternedStringIndex(idx int) error { 78 if idx <= math.MaxUint8 { 79 if err := e.writeCode(msgpcode.FixExt1); err != nil { 80 return err 81 } 82 return e.write1(byte(internedStringExtID), uint8(idx)) 83 } 84 85 if idx <= math.MaxUint16 { 86 if err := e.writeCode(msgpcode.FixExt2); err != nil { 87 return err 88 } 89 return e.write2(byte(internedStringExtID), uint16(idx)) 90 } 91 92 if uint64(idx) <= math.MaxUint32 { 93 if err := e.writeCode(msgpcode.FixExt4); err != nil { 94 return err 95 } 96 return e.write4(byte(internedStringExtID), uint32(idx)) 97 } 98 99 return fmt.Errorf("msgpack: interned string index=%d is too large", idx) 100 } 101 102 //------------------------------------------------------------------------------ 103 104 func decodeInternedInterfaceValue(d *Decoder, v reflect.Value) error { 105 s, err := d.decodeInternedString(true) 106 if err == nil { 107 v.Set(reflect.ValueOf(s)) 108 return nil 109 } 110 if err != nil { 111 if _, ok := err.(unexpectedCodeError); !ok { 112 return err 113 } 114 } 115 116 if err := d.s.UnreadByte(); err != nil { 117 return err 118 } 119 return decodeInterfaceValue(d, v) 120 } 121 122 func decodeInternedStringValue(d *Decoder, v reflect.Value) error { 123 s, err := d.decodeInternedString(true) 124 if err != nil { 125 return err 126 } 127 128 v.SetString(s) 129 return nil 130 } 131 132 func (d *Decoder) decodeInternedString(intern bool) (string, error) { 133 c, err := d.readCode() 134 if err != nil { 135 return "", err 136 } 137 138 if msgpcode.IsFixedString(c) { 139 n := int(c & msgpcode.FixedStrMask) 140 return d.decodeInternedStringWithLen(n, intern) 141 } 142 143 switch c { 144 case msgpcode.Nil: 145 return "", nil 146 case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4: 147 typeID, extLen, err := d.extHeader(c) 148 if err != nil { 149 return "", err 150 } 151 if typeID != internedStringExtID { 152 err := fmt.Errorf("msgpack: got ext type=%d, wanted %d", 153 typeID, internedStringExtID) 154 return "", err 155 } 156 157 idx, err := d.decodeInternedStringIndex(extLen) 158 if err != nil { 159 return "", err 160 } 161 162 return d.internedStringAtIndex(idx) 163 case msgpcode.Str8, msgpcode.Bin8: 164 n, err := d.uint8() 165 if err != nil { 166 return "", err 167 } 168 return d.decodeInternedStringWithLen(int(n), intern) 169 case msgpcode.Str16, msgpcode.Bin16: 170 n, err := d.uint16() 171 if err != nil { 172 return "", err 173 } 174 return d.decodeInternedStringWithLen(int(n), intern) 175 case msgpcode.Str32, msgpcode.Bin32: 176 n, err := d.uint32() 177 if err != nil { 178 return "", err 179 } 180 return d.decodeInternedStringWithLen(int(n), intern) 181 } 182 183 return "", unexpectedCodeError{ 184 code: c, 185 hint: "interned string", 186 } 187 } 188 189 func (d *Decoder) decodeInternedStringIndex(extLen int) (int, error) { 190 switch extLen { 191 case 1: 192 n, err := d.uint8() 193 if err != nil { 194 return 0, err 195 } 196 return int(n), nil 197 case 2: 198 n, err := d.uint16() 199 if err != nil { 200 return 0, err 201 } 202 return int(n), nil 203 case 4: 204 n, err := d.uint32() 205 if err != nil { 206 return 0, err 207 } 208 return int(n), nil 209 } 210 211 err := fmt.Errorf("msgpack: unsupported ext len=%d decoding interned string", extLen) 212 return 0, err 213 } 214 215 func (d *Decoder) internedStringAtIndex(idx int) (string, error) { 216 if idx >= len(d.dict) { 217 err := fmt.Errorf("msgpack: interned string at index=%d does not exist", idx) 218 return "", err 219 } 220 return d.dict[idx], nil 221 } 222 223 func (d *Decoder) decodeInternedStringWithLen(n int, intern bool) (string, error) { 224 if n <= 0 { 225 return "", nil 226 } 227 228 s, err := d.stringWithLen(n) 229 if err != nil { 230 return "", err 231 } 232 233 if intern && len(s) >= minInternedStringLen && len(d.dict) < maxDictLen { 234 d.dict = append(d.dict, s) 235 } 236 237 return s, nil 238 }