github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/labix.org/v2/mgo/bson/encode.go (about) 1 // BSON library for Go 2 // 3 // Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net> 4 // 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // 1. Redistributions of source code must retain the above copyright notice, this 11 // list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright notice, 13 // this list of conditions and the following disclaimer in the documentation 14 // and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // gobson - BSON library for Go. 27 28 package bson 29 30 import ( 31 "fmt" 32 "math" 33 "net/url" 34 "reflect" 35 "strconv" 36 "time" 37 ) 38 39 // -------------------------------------------------------------------------- 40 // Some internal infrastructure. 41 42 var ( 43 typeBinary = reflect.TypeOf(Binary{}) 44 typeObjectId = reflect.TypeOf(ObjectId("")) 45 typeSymbol = reflect.TypeOf(Symbol("")) 46 typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0)) 47 typeOrderKey = reflect.TypeOf(MinKey) 48 typeDocElem = reflect.TypeOf(DocElem{}) 49 typeRawDocElem = reflect.TypeOf(RawDocElem{}) 50 typeRaw = reflect.TypeOf(Raw{}) 51 typeURL = reflect.TypeOf(url.URL{}) 52 typeTime = reflect.TypeOf(time.Time{}) 53 typeString = reflect.TypeOf("") 54 ) 55 56 const itoaCacheSize = 32 57 58 var itoaCache []string 59 60 func init() { 61 itoaCache = make([]string, itoaCacheSize) 62 for i := 0; i != itoaCacheSize; i++ { 63 itoaCache[i] = strconv.Itoa(i) 64 } 65 } 66 67 func itoa(i int) string { 68 if i < itoaCacheSize { 69 return itoaCache[i] 70 } 71 return strconv.Itoa(i) 72 } 73 74 // -------------------------------------------------------------------------- 75 // Marshaling of the document value itself. 76 77 type encoder struct { 78 out []byte 79 } 80 81 func (e *encoder) addDoc(v reflect.Value) { 82 for { 83 if vi, ok := v.Interface().(Getter); ok { 84 getv, err := vi.GetBSON() 85 if err != nil { 86 panic(err) 87 } 88 v = reflect.ValueOf(getv) 89 continue 90 } 91 if v.Kind() == reflect.Ptr { 92 v = v.Elem() 93 continue 94 } 95 break 96 } 97 98 if v.Type() == typeRaw { 99 raw := v.Interface().(Raw) 100 if raw.Kind != 0x03 && raw.Kind != 0x00 { 101 panic("Attempted to unmarshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document") 102 } 103 e.addBytes(raw.Data...) 104 return 105 } 106 107 start := e.reserveInt32() 108 109 switch v.Kind() { 110 case reflect.Map: 111 e.addMap(v) 112 case reflect.Struct: 113 e.addStruct(v) 114 case reflect.Array, reflect.Slice: 115 e.addSlice(v) 116 default: 117 panic("Can't marshal " + v.Type().String() + " as a BSON document") 118 } 119 120 e.addBytes(0) 121 e.setInt32(start, int32(len(e.out)-start)) 122 } 123 124 func (e *encoder) addMap(v reflect.Value) { 125 for _, k := range v.MapKeys() { 126 e.addElem(k.String(), v.MapIndex(k), false) 127 } 128 } 129 130 func (e *encoder) addStruct(v reflect.Value) { 131 sinfo, err := getStructInfo(v.Type()) 132 if err != nil { 133 panic(err) 134 } 135 var value reflect.Value 136 if sinfo.InlineMap >= 0 { 137 m := v.Field(sinfo.InlineMap) 138 if m.Len() > 0 { 139 for _, k := range m.MapKeys() { 140 ks := k.String() 141 if _, found := sinfo.FieldsMap[ks]; found { 142 panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks)) 143 } 144 e.addElem(ks, m.MapIndex(k), false) 145 } 146 } 147 } 148 for _, info := range sinfo.FieldsList { 149 if info.Inline == nil { 150 value = v.Field(info.Num) 151 } else { 152 value = v.FieldByIndex(info.Inline) 153 } 154 if info.OmitEmpty && isZero(value) { 155 continue 156 } 157 e.addElem(info.Key, value, info.MinSize) 158 } 159 } 160 161 func isZero(v reflect.Value) bool { 162 switch v.Kind() { 163 case reflect.String: 164 return len(v.String()) == 0 165 case reflect.Ptr, reflect.Interface: 166 return v.IsNil() 167 case reflect.Slice: 168 return v.Len() == 0 169 case reflect.Map: 170 return v.Len() == 0 171 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 172 return v.Int() == 0 173 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 174 return v.Uint() == 0 175 case reflect.Float32, reflect.Float64: 176 return v.Float() == 0 177 case reflect.Bool: 178 return !v.Bool() 179 case reflect.Struct: 180 if v.Type() == typeTime { 181 return v.Interface().(time.Time).IsZero() 182 } 183 for i := v.NumField() - 1; i >= 0; i-- { 184 if !isZero(v.Field(i)) { 185 return false 186 } 187 } 188 return true 189 } 190 return false 191 } 192 193 func (e *encoder) addSlice(v reflect.Value) { 194 vi := v.Interface() 195 if d, ok := vi.(D); ok { 196 for _, elem := range d { 197 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) 198 } 199 return 200 } 201 if d, ok := vi.(RawD); ok { 202 for _, elem := range d { 203 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) 204 } 205 return 206 } 207 l := v.Len() 208 et := v.Type().Elem() 209 if et == typeDocElem { 210 for i := 0; i < l; i++ { 211 elem := v.Index(i).Interface().(DocElem) 212 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) 213 } 214 return 215 } 216 if et == typeRawDocElem { 217 for i := 0; i < l; i++ { 218 elem := v.Index(i).Interface().(RawDocElem) 219 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false) 220 } 221 return 222 } 223 for i := 0; i < l; i++ { 224 e.addElem(itoa(i), v.Index(i), false) 225 } 226 } 227 228 // -------------------------------------------------------------------------- 229 // Marshaling of elements in a document. 230 231 func (e *encoder) addElemName(kind byte, name string) { 232 e.addBytes(kind) 233 e.addBytes([]byte(name)...) 234 e.addBytes(0) 235 } 236 237 func (e *encoder) addElem(name string, v reflect.Value, minSize bool) { 238 239 if !v.IsValid() { 240 e.addElemName('\x0A', name) 241 return 242 } 243 244 if getter, ok := v.Interface().(Getter); ok { 245 getv, err := getter.GetBSON() 246 if err != nil { 247 panic(err) 248 } 249 e.addElem(name, reflect.ValueOf(getv), minSize) 250 return 251 } 252 253 switch v.Kind() { 254 255 case reflect.Interface: 256 e.addElem(name, v.Elem(), minSize) 257 258 case reflect.Ptr: 259 e.addElem(name, v.Elem(), minSize) 260 261 case reflect.String: 262 s := v.String() 263 switch v.Type() { 264 case typeObjectId: 265 if len(s) != 12 { 266 panic("ObjectIDs must be exactly 12 bytes long (got " + 267 strconv.Itoa(len(s)) + ")") 268 } 269 e.addElemName('\x07', name) 270 e.addBytes([]byte(s)...) 271 case typeSymbol: 272 e.addElemName('\x0E', name) 273 e.addStr(s) 274 default: 275 e.addElemName('\x02', name) 276 e.addStr(s) 277 } 278 279 case reflect.Float32, reflect.Float64: 280 e.addElemName('\x01', name) 281 e.addInt64(int64(math.Float64bits(v.Float()))) 282 283 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 284 u := v.Uint() 285 if int64(u) < 0 { 286 panic("BSON has no uint64 type, and value is too large to fit correctly in an int64") 287 } else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) { 288 e.addElemName('\x10', name) 289 e.addInt32(int32(u)) 290 } else { 291 e.addElemName('\x12', name) 292 e.addInt64(int64(u)) 293 } 294 295 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 296 switch v.Type() { 297 case typeMongoTimestamp: 298 e.addElemName('\x11', name) 299 e.addInt64(v.Int()) 300 301 case typeOrderKey: 302 if v.Int() == int64(MaxKey) { 303 e.addElemName('\x7F', name) 304 } else { 305 e.addElemName('\xFF', name) 306 } 307 308 default: 309 i := v.Int() 310 if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 { 311 // It fits into an int32, encode as such. 312 e.addElemName('\x10', name) 313 e.addInt32(int32(i)) 314 } else { 315 e.addElemName('\x12', name) 316 e.addInt64(i) 317 } 318 } 319 320 case reflect.Bool: 321 e.addElemName('\x08', name) 322 if v.Bool() { 323 e.addBytes(1) 324 } else { 325 e.addBytes(0) 326 } 327 328 case reflect.Map: 329 e.addElemName('\x03', name) 330 e.addDoc(v) 331 332 case reflect.Slice: 333 vt := v.Type() 334 et := vt.Elem() 335 if et.Kind() == reflect.Uint8 { 336 e.addElemName('\x05', name) 337 e.addBinary('\x00', v.Bytes()) 338 } else if et == typeDocElem || et == typeRawDocElem { 339 e.addElemName('\x03', name) 340 e.addDoc(v) 341 } else { 342 e.addElemName('\x04', name) 343 e.addDoc(v) 344 } 345 346 case reflect.Array: 347 et := v.Type().Elem() 348 if et.Kind() == reflect.Uint8 { 349 e.addElemName('\x05', name) 350 e.addBinary('\x00', v.Slice(0, v.Len()).Interface().([]byte)) 351 } else { 352 e.addElemName('\x04', name) 353 e.addDoc(v) 354 } 355 356 case reflect.Struct: 357 switch s := v.Interface().(type) { 358 359 case Raw: 360 kind := s.Kind 361 if kind == 0x00 { 362 kind = 0x03 363 } 364 e.addElemName(kind, name) 365 e.addBytes(s.Data...) 366 367 case Binary: 368 e.addElemName('\x05', name) 369 e.addBinary(s.Kind, s.Data) 370 371 case RegEx: 372 e.addElemName('\x0B', name) 373 e.addCStr(s.Pattern) 374 e.addCStr(s.Options) 375 376 case JavaScript: 377 if s.Scope == nil { 378 e.addElemName('\x0D', name) 379 e.addStr(s.Code) 380 } else { 381 e.addElemName('\x0F', name) 382 start := e.reserveInt32() 383 e.addStr(s.Code) 384 e.addDoc(reflect.ValueOf(s.Scope)) 385 e.setInt32(start, int32(len(e.out)-start)) 386 } 387 388 case time.Time: 389 // MongoDB handles timestamps as milliseconds. 390 e.addElemName('\x09', name) 391 e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6)) 392 393 case url.URL: 394 e.addElemName('\x02', name) 395 e.addStr(s.String()) 396 397 case undefined: 398 e.addElemName('\x06', name) 399 400 default: 401 e.addElemName('\x03', name) 402 e.addDoc(v) 403 } 404 405 default: 406 panic("Can't marshal " + v.Type().String() + " in a BSON document") 407 } 408 } 409 410 // -------------------------------------------------------------------------- 411 // Marshaling of base types. 412 413 func (e *encoder) addBinary(subtype byte, v []byte) { 414 if subtype == 0x02 { 415 // Wonder how that brilliant idea came to life. Obsolete, luckily. 416 e.addInt32(int32(len(v) + 4)) 417 e.addBytes(subtype) 418 e.addInt32(int32(len(v))) 419 } else { 420 e.addInt32(int32(len(v))) 421 e.addBytes(subtype) 422 } 423 e.addBytes(v...) 424 } 425 426 func (e *encoder) addStr(v string) { 427 e.addInt32(int32(len(v) + 1)) 428 e.addCStr(v) 429 } 430 431 func (e *encoder) addCStr(v string) { 432 e.addBytes([]byte(v)...) 433 e.addBytes(0) 434 } 435 436 func (e *encoder) reserveInt32() (pos int) { 437 pos = len(e.out) 438 e.addBytes(0, 0, 0, 0) 439 return pos 440 } 441 442 func (e *encoder) setInt32(pos int, v int32) { 443 e.out[pos+0] = byte(v) 444 e.out[pos+1] = byte(v >> 8) 445 e.out[pos+2] = byte(v >> 16) 446 e.out[pos+3] = byte(v >> 24) 447 } 448 449 func (e *encoder) addInt32(v int32) { 450 u := uint32(v) 451 e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24)) 452 } 453 454 func (e *encoder) addInt64(v int64) { 455 u := uint64(v) 456 e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24), 457 byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56)) 458 } 459 460 func (e *encoder) addBytes(v ...byte) { 461 e.out = append(e.out, v...) 462 }