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  }