1
0

added vendor

This commit is contained in:
kolaente
2018-10-28 17:24:10 +01:00
parent 738c22b5f9
commit 2556ef7624
484 changed files with 140231 additions and 0 deletions

25
vendor/github.com/globalsign/mgo/bson/LICENSE generated vendored Normal file
View File

@ -0,0 +1,25 @@
BSON library for Go
Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

12
vendor/github.com/globalsign/mgo/bson/README.md generated vendored Normal file
View File

@ -0,0 +1,12 @@
[![GoDoc](https://godoc.org/github.com/globalsign/mgo/bson?status.svg)](https://godoc.org/github.com/globalsign/mgo/bson)
An Implementation of BSON for Go
--------------------------------
Package bson is an implementation of the [BSON specification](http://bsonspec.org) for Go.
While the BSON package implements the BSON spec as faithfully as possible, there
is some MongoDB specific behaviour (such as map keys `$in`, `$all`, etc) in the
`bson` package. The priority is for backwards compatibility for the `mgo`
driver, though fixes for obviously buggy behaviour is welcome (and features, etc
behind feature flags).

836
vendor/github.com/globalsign/mgo/bson/bson.go generated vendored Normal file
View File

@ -0,0 +1,836 @@
// BSON library for Go
//
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Package bson is an implementation of the BSON specification for Go:
//
// http://bsonspec.org
//
// It was created as part of the mgo MongoDB driver for Go, but is standalone
// and may be used on its own without the driver.
package bson
import (
"bytes"
"crypto/md5"
"crypto/rand"
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math"
"os"
"reflect"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"
)
//go:generate go run bson_corpus_spec_test_generator.go
// --------------------------------------------------------------------------
// The public API.
// Element types constants from BSON specification.
const (
ElementFloat64 byte = 0x01
ElementString byte = 0x02
ElementDocument byte = 0x03
ElementArray byte = 0x04
ElementBinary byte = 0x05
Element06 byte = 0x06
ElementObjectId byte = 0x07
ElementBool byte = 0x08
ElementDatetime byte = 0x09
ElementNil byte = 0x0A
ElementRegEx byte = 0x0B
ElementDBPointer byte = 0x0C
ElementJavaScriptWithoutScope byte = 0x0D
ElementSymbol byte = 0x0E
ElementJavaScriptWithScope byte = 0x0F
ElementInt32 byte = 0x10
ElementTimestamp byte = 0x11
ElementInt64 byte = 0x12
ElementDecimal128 byte = 0x13
ElementMinKey byte = 0xFF
ElementMaxKey byte = 0x7F
BinaryGeneric byte = 0x00
BinaryFunction byte = 0x01
BinaryBinaryOld byte = 0x02
BinaryUUIDOld byte = 0x03
BinaryUUID byte = 0x04
BinaryMD5 byte = 0x05
BinaryUserDefined byte = 0x80
)
// Getter interface: a value implementing the bson.Getter interface will have its GetBSON
// method called when the given value has to be marshalled, and the result
// of this method will be marshaled in place of the actual object.
//
// If GetBSON returns return a non-nil error, the marshalling procedure
// will stop and error out with the provided value.
type Getter interface {
GetBSON() (interface{}, error)
}
// Setter interface: a value implementing the bson.Setter interface will receive the BSON
// value via the SetBSON method during unmarshaling, and the object
// itself will not be changed as usual.
//
// If setting the value works, the method should return nil or alternatively
// bson.ErrSetZero to set the respective field to its zero value (nil for
// pointer types). If SetBSON returns a value of type bson.TypeError, the
// BSON value will be omitted from a map or slice being decoded and the
// unmarshalling will continue. If it returns any other non-nil error, the
// unmarshalling procedure will stop and error out with the provided value.
//
// This interface is generally useful in pointer receivers, since the method
// will want to change the receiver. A type field that implements the Setter
// interface doesn't have to be a pointer, though.
//
// Unlike the usual behavior, unmarshalling onto a value that implements a
// Setter interface will NOT reset the value to its zero state. This allows
// the value to decide by itself how to be unmarshalled.
//
// For example:
//
// type MyString string
//
// func (s *MyString) SetBSON(raw bson.Raw) error {
// return raw.Unmarshal(s)
// }
//
type Setter interface {
SetBSON(raw Raw) error
}
// ErrSetZero may be returned from a SetBSON method to have the value set to
// its respective zero value. When used in pointer values, this will set the
// field to nil rather than to the pre-allocated value.
var ErrSetZero = errors.New("set to zero")
// M is a convenient alias for a map[string]interface{} map, useful for
// dealing with BSON in a native way. For instance:
//
// bson.M{"a": 1, "b": true}
//
// There's no special handling for this type in addition to what's done anyway
// for an equivalent map type. Elements in the map will be dumped in an
// undefined ordered. See also the bson.D type for an ordered alternative.
type M map[string]interface{}
// D represents a BSON document containing ordered elements. For example:
//
// bson.D{{"a", 1}, {"b", true}}
//
// In some situations, such as when creating indexes for MongoDB, the order in
// which the elements are defined is important. If the order is not important,
// using a map is generally more comfortable. See bson.M and bson.RawD.
type D []DocElem
// DocElem is an element of the bson.D document representation.
type DocElem struct {
Name string
Value interface{}
}
// Map returns a map out of the ordered element name/value pairs in d.
func (d D) Map() (m M) {
m = make(M, len(d))
for _, item := range d {
m[item.Name] = item.Value
}
return m
}
// The Raw type represents raw unprocessed BSON documents and elements.
// Kind is the kind of element as defined per the BSON specification, and
// Data is the raw unprocessed data for the respective element.
// Using this type it is possible to unmarshal or marshal values partially.
//
// Relevant documentation:
//
// http://bsonspec.org/#/specification
//
type Raw struct {
Kind byte
Data []byte
}
// RawD represents a BSON document containing raw unprocessed elements.
// This low-level representation may be useful when lazily processing
// documents of uncertain content, or when manipulating the raw content
// documents in general.
type RawD []RawDocElem
// RawDocElem elements of RawD type.
type RawDocElem struct {
Name string
Value Raw
}
// ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes
// long. MongoDB objects by default have such a property set in their "_id"
// property.
//
// http://www.mongodb.org/display/DOCS/Object+Ids
type ObjectId string
// ObjectIdHex returns an ObjectId from the provided hex representation.
// Calling this function with an invalid hex representation will
// cause a runtime panic. See the IsObjectIdHex function.
func ObjectIdHex(s string) ObjectId {
d, err := hex.DecodeString(s)
if err != nil || len(d) != 12 {
panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s))
}
return ObjectId(d)
}
// IsObjectIdHex returns whether s is a valid hex representation of
// an ObjectId. See the ObjectIdHex function.
func IsObjectIdHex(s string) bool {
if len(s) != 24 {
return false
}
_, err := hex.DecodeString(s)
return err == nil
}
// objectIdCounter is atomically incremented when generating a new ObjectId
// using NewObjectId() function. It's used as a counter part of an id.
var objectIdCounter = readRandomUint32()
// readRandomUint32 returns a random objectIdCounter.
func readRandomUint32() uint32 {
var b [4]byte
_, err := io.ReadFull(rand.Reader, b[:])
if err != nil {
panic(fmt.Errorf("cannot read random object id: %v", err))
}
return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24))
}
// machineId stores machine id generated once and used in subsequent calls
// to NewObjectId function.
var machineId = readMachineId()
var processId = os.Getpid()
// readMachineId generates and returns a machine id.
// If this function fails to get the hostname it will cause a runtime error.
func readMachineId() []byte {
var sum [3]byte
id := sum[:]
hostname, err1 := os.Hostname()
if err1 != nil {
_, err2 := io.ReadFull(rand.Reader, id)
if err2 != nil {
panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2))
}
return id
}
hw := md5.New()
hw.Write([]byte(hostname))
copy(id, hw.Sum(nil))
return id
}
// NewObjectId returns a new unique ObjectId.
func NewObjectId() ObjectId {
var b [12]byte
// Timestamp, 4 bytes, big endian
binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix()))
// Machine, first 3 bytes of md5(hostname)
b[4] = machineId[0]
b[5] = machineId[1]
b[6] = machineId[2]
// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
b[7] = byte(processId >> 8)
b[8] = byte(processId)
// Increment, 3 bytes, big endian
i := atomic.AddUint32(&objectIdCounter, 1)
b[9] = byte(i >> 16)
b[10] = byte(i >> 8)
b[11] = byte(i)
return ObjectId(b[:])
}
// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled
// with the provided number of seconds from epoch UTC, and all other parts
// filled with zeroes. It's not safe to insert a document with an id generated
// by this method, it is useful only for queries to find documents with ids
// generated before or after the specified timestamp.
func NewObjectIdWithTime(t time.Time) ObjectId {
var b [12]byte
binary.BigEndian.PutUint32(b[:4], uint32(t.Unix()))
return ObjectId(string(b[:]))
}
// String returns a hex string representation of the id.
// Example: ObjectIdHex("4d88e15b60f486e428412dc9").
func (id ObjectId) String() string {
return fmt.Sprintf(`ObjectIdHex("%x")`, string(id))
}
// Hex returns a hex representation of the ObjectId.
func (id ObjectId) Hex() string {
return hex.EncodeToString([]byte(id))
}
// MarshalJSON turns a bson.ObjectId into a json.Marshaller.
func (id ObjectId) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%x"`, string(id))), nil
}
var nullBytes = []byte("null")
// UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller.
func (id *ObjectId) UnmarshalJSON(data []byte) error {
if len(data) > 0 && (data[0] == '{' || data[0] == 'O') {
var v struct {
Id json.RawMessage `json:"$oid"`
Func struct {
Id json.RawMessage
} `json:"$oidFunc"`
}
err := jdec(data, &v)
if err == nil {
if len(v.Id) > 0 {
data = []byte(v.Id)
} else {
data = []byte(v.Func.Id)
}
}
}
if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) {
*id = ""
return nil
}
if len(data) != 26 || data[0] != '"' || data[25] != '"' {
return fmt.Errorf("invalid ObjectId in JSON: %s", string(data))
}
var buf [12]byte
_, err := hex.Decode(buf[:], data[1:25])
if err != nil {
return fmt.Errorf("invalid ObjectId in JSON: %s (%s)", string(data), err)
}
*id = ObjectId(string(buf[:]))
return nil
}
// MarshalText turns bson.ObjectId into an encoding.TextMarshaler.
func (id ObjectId) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%x", string(id))), nil
}
// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler.
func (id *ObjectId) UnmarshalText(data []byte) error {
if len(data) == 1 && data[0] == ' ' || len(data) == 0 {
*id = ""
return nil
}
if len(data) != 24 {
return fmt.Errorf("invalid ObjectId: %s", data)
}
var buf [12]byte
_, err := hex.Decode(buf[:], data[:])
if err != nil {
return fmt.Errorf("invalid ObjectId: %s (%s)", data, err)
}
*id = ObjectId(string(buf[:]))
return nil
}
// Valid returns true if id is valid. A valid id must contain exactly 12 bytes.
func (id ObjectId) Valid() bool {
return len(id) == 12
}
// byteSlice returns byte slice of id from start to end.
// Calling this function with an invalid id will cause a runtime panic.
func (id ObjectId) byteSlice(start, end int) []byte {
if len(id) != 12 {
panic(fmt.Sprintf("invalid ObjectId: %q", string(id)))
}
return []byte(string(id)[start:end])
}
// Time returns the timestamp part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ObjectId) Time() time.Time {
// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4)))
return time.Unix(secs, 0)
}
// Machine returns the 3-byte machine id part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ObjectId) Machine() []byte {
return id.byteSlice(4, 7)
}
// Pid returns the process id part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ObjectId) Pid() uint16 {
return binary.BigEndian.Uint16(id.byteSlice(7, 9))
}
// Counter returns the incrementing value part of the id.
// It's a runtime error to call this method with an invalid id.
func (id ObjectId) Counter() int32 {
b := id.byteSlice(9, 12)
// Counter is stored as big-endian 3-byte value
return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
}
// The Symbol type is similar to a string and is used in languages with a
// distinct symbol type.
type Symbol string
// Now returns the current time with millisecond precision. MongoDB stores
// timestamps with the same precision, so a Time returned from this method
// will not change after a roundtrip to the database. That's the only reason
// why this function exists. Using the time.Now function also works fine
// otherwise.
func Now() time.Time {
return time.Unix(0, time.Now().UnixNano()/1e6*1e6)
}
// MongoTimestamp is a special internal type used by MongoDB that for some
// strange reason has its own datatype defined in BSON.
type MongoTimestamp int64
// Time returns the time part of ts which is stored with second precision.
func (ts MongoTimestamp) Time() time.Time {
return time.Unix(int64(uint64(ts)>>32), 0)
}
// Counter returns the counter part of ts.
func (ts MongoTimestamp) Counter() uint32 {
return uint32(ts)
}
// NewMongoTimestamp creates a timestamp using the given
// date `t` (with second precision) and counter `c` (unique for `t`).
//
// Returns an error if time `t` is not between 1970-01-01T00:00:00Z
// and 2106-02-07T06:28:15Z (inclusive).
//
// Note that two MongoTimestamps should never have the same (time, counter) combination:
// the caller must ensure the counter `c` is increased if creating multiple MongoTimestamp
// values for the same time `t` (ignoring fractions of seconds).
func NewMongoTimestamp(t time.Time, c uint32) (MongoTimestamp, error) {
u := t.Unix()
if u < 0 || u > math.MaxUint32 {
return -1, errors.New("invalid value for time")
}
i := int64(u<<32 | int64(c))
return MongoTimestamp(i), nil
}
type orderKey int64
// MaxKey is a special value that compares higher than all other possible BSON
// values in a MongoDB database.
var MaxKey = orderKey(1<<63 - 1)
// MinKey is a special value that compares lower than all other possible BSON
// values in a MongoDB database.
var MinKey = orderKey(-1 << 63)
type undefined struct{}
// Undefined represents the undefined BSON value.
var Undefined undefined
// Binary is a representation for non-standard binary values. Any kind should
// work, but the following are known as of this writing:
//
// 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}.
// 0x01 - Function (!?)
// 0x02 - Obsolete generic.
// 0x03 - UUID
// 0x05 - MD5
// 0x80 - User defined.
//
type Binary struct {
Kind byte
Data []byte
}
// RegEx represents a regular expression. The Options field may contain
// individual characters defining the way in which the pattern should be
// applied, and must be sorted. Valid options as of this writing are 'i' for
// case insensitive matching, 'm' for multi-line matching, 'x' for verbose
// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all
// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match
// unicode. The value of the Options parameter is not verified before being
// marshaled into the BSON format.
type RegEx struct {
Pattern string
Options string
}
// JavaScript is a type that holds JavaScript code. If Scope is non-nil, it
// will be marshaled as a mapping from identifiers to values that may be
// used when evaluating the provided Code.
type JavaScript struct {
Code string
Scope interface{}
}
// DBPointer refers to a document id in a namespace.
//
// This type is deprecated in the BSON specification and should not be used
// except for backwards compatibility with ancient applications.
type DBPointer struct {
Namespace string
Id ObjectId
}
const initialBufferSize = 64
func handleErr(err *error) {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
} else if _, ok := r.(externalPanic); ok {
panic(r)
} else if s, ok := r.(string); ok {
*err = errors.New(s)
} else if e, ok := r.(error); ok {
*err = e
} else {
panic(r)
}
}
}
// Marshal serializes the in value, which may be a map or a struct value.
// In the case of struct values, only exported fields will be serialized,
// and the order of serialized fields will match that of the struct itself.
// The lowercased field name is used as the key for each exported field,
// but this behavior may be changed using the respective field tag.
// The tag may also contain flags to tweak the marshalling behavior for
// the field. The tag formats accepted are:
//
// "[<key>][,<flag1>[,<flag2>]]"
//
// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
//
// The following flags are currently supported:
//
// omitempty Only include the field if it's not set to the zero
// value for the type or to empty slices or maps.
//
// minsize Marshal an int64 value as an int32, if that's feasible
// while preserving the numeric value.
//
// inline Inline the field, which must be a struct or a map,
// causing all of its fields or keys to be processed as if
// they were part of the outer struct. For maps, keys must
// not conflict with the bson keys of other struct fields.
//
// Some examples:
//
// type T struct {
// A bool
// B int "myb"
// C string "myc,omitempty"
// D string `bson:",omitempty" json:"jsonkey"`
// E int64 ",minsize"
// F int64 "myf,omitempty,minsize"
// }
//
func Marshal(in interface{}) (out []byte, err error) {
return MarshalBuffer(in, make([]byte, 0, initialBufferSize))
}
// MarshalBuffer behaves the same way as Marshal, except that instead of
// allocating a new byte slice it tries to use the received byte slice and
// only allocates more memory if necessary to fit the marshaled value.
func MarshalBuffer(in interface{}, buf []byte) (out []byte, err error) {
defer handleErr(&err)
e := &encoder{buf}
e.addDoc(reflect.ValueOf(in))
return e.out, nil
}
// Unmarshal deserializes data from in into the out value. The out value
// must be a map, a pointer to a struct, or a pointer to a bson.D value.
// In the case of struct values, only exported fields will be deserialized.
// The lowercased field name is used as the key for each exported field,
// but this behavior may be changed using the respective field tag.
// The tag may also contain flags to tweak the marshalling behavior for
// the field. The tag formats accepted are:
//
// "[<key>][,<flag1>[,<flag2>]]"
//
// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
//
// The following flags are currently supported during unmarshal (see the
// Marshal method for other flags):
//
// inline Inline the field, which must be a struct or a map.
// Inlined structs are handled as if its fields were part
// of the outer struct. An inlined map causes keys that do
// not match any other struct field to be inserted in the
// map rather than being discarded as usual.
//
// The target field or element types of out may not necessarily match
// the BSON values of the provided data. The following conversions are
// made automatically:
//
// - Numeric types are converted if at least the integer part of the
// value would be preserved correctly
// - Bools are converted to numeric types as 1 or 0
// - Numeric types are converted to bools as true if not 0 or false otherwise
// - Binary and string BSON data is converted to a string, array or byte slice
//
// If the value would not fit the type and cannot be converted, it's
// silently skipped.
//
// Pointer values are initialized when necessary.
func Unmarshal(in []byte, out interface{}) (err error) {
if raw, ok := out.(*Raw); ok {
raw.Kind = 3
raw.Data = in
return nil
}
defer handleErr(&err)
v := reflect.ValueOf(out)
switch v.Kind() {
case reflect.Ptr:
fallthrough
case reflect.Map:
d := newDecoder(in)
d.readDocTo(v)
if d.i < len(d.in) {
return errors.New("document is corrupted")
}
case reflect.Struct:
return errors.New("unmarshal can't deal with struct values. Use a pointer")
default:
return errors.New("unmarshal needs a map or a pointer to a struct")
}
return nil
}
// Unmarshal deserializes raw into the out value. If the out value type
// is not compatible with raw, a *bson.TypeError is returned.
//
// See the Unmarshal function documentation for more details on the
// unmarshalling process.
func (raw Raw) Unmarshal(out interface{}) (err error) {
defer handleErr(&err)
v := reflect.ValueOf(out)
switch v.Kind() {
case reflect.Ptr:
v = v.Elem()
fallthrough
case reflect.Map:
d := newDecoder(raw.Data)
good := d.readElemTo(v, raw.Kind)
if !good {
return &TypeError{v.Type(), raw.Kind}
}
case reflect.Struct:
return errors.New("raw Unmarshal can't deal with struct values. Use a pointer")
default:
return errors.New("raw Unmarshal needs a map or a valid pointer")
}
return nil
}
// TypeError store details for type error occuring
// during unmarshaling
type TypeError struct {
Type reflect.Type
Kind byte
}
func (e *TypeError) Error() string {
return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String())
}
// --------------------------------------------------------------------------
// Maintain a mapping of keys to structure field indexes
type structInfo struct {
FieldsMap map[string]fieldInfo
FieldsList []fieldInfo
InlineMap int
Zero reflect.Value
}
type fieldInfo struct {
Key string
Num int
OmitEmpty bool
MinSize bool
Inline []int
}
var structMap = make(map[reflect.Type]*structInfo)
var structMapMutex sync.RWMutex
type externalPanic string
func (e externalPanic) String() string {
return string(e)
}
func getStructInfo(st reflect.Type) (*structInfo, error) {
structMapMutex.RLock()
sinfo, found := structMap[st]
structMapMutex.RUnlock()
if found {
return sinfo, nil
}
n := st.NumField()
fieldsMap := make(map[string]fieldInfo)
fieldsList := make([]fieldInfo, 0, n)
inlineMap := -1
for i := 0; i != n; i++ {
field := st.Field(i)
if field.PkgPath != "" && !field.Anonymous {
continue // Private field
}
info := fieldInfo{Num: i}
tag := field.Tag.Get("bson")
// Fall-back to JSON struct tag, if feature flag is set.
if tag == "" && useJSONTagFallback {
tag = field.Tag.Get("json")
}
// If there's no bson/json tag available.
if tag == "" {
// If there's no tag, and also no tag: value splits (i.e. no colon)
// then assume the entire tag is the value
if strings.Index(string(field.Tag), ":") < 0 {
tag = string(field.Tag)
}
}
if tag == "-" {
continue
}
inline := false
fields := strings.Split(tag, ",")
if len(fields) > 1 {
for _, flag := range fields[1:] {
switch flag {
case "omitempty":
info.OmitEmpty = true
case "minsize":
info.MinSize = true
case "inline":
inline = true
default:
msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
panic(externalPanic(msg))
}
}
tag = fields[0]
}
if inline {
switch field.Type.Kind() {
case reflect.Map:
if inlineMap >= 0 {
return nil, errors.New("Multiple ,inline maps in struct " + st.String())
}
if field.Type.Key() != reflect.TypeOf("") {
return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
}
inlineMap = info.Num
case reflect.Ptr:
// allow only pointer to struct
if kind := field.Type.Elem().Kind(); kind != reflect.Struct {
return nil, errors.New("Option ,inline allows a pointer only to a struct, was given pointer to " + kind.String())
}
field.Type = field.Type.Elem()
fallthrough
case reflect.Struct:
sinfo, err := getStructInfo(field.Type)
if err != nil {
return nil, err
}
for _, finfo := range sinfo.FieldsList {
if _, found := fieldsMap[finfo.Key]; found {
msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
return nil, errors.New(msg)
}
if finfo.Inline == nil {
finfo.Inline = []int{i, finfo.Num}
} else {
finfo.Inline = append([]int{i}, finfo.Inline...)
}
fieldsMap[finfo.Key] = finfo
fieldsList = append(fieldsList, finfo)
}
default:
panic("Option ,inline needs a struct value or a pointer to a struct or map field")
}
continue
}
if tag != "" {
info.Key = tag
} else {
info.Key = strings.ToLower(field.Name)
}
if _, found = fieldsMap[info.Key]; found {
msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
return nil, errors.New(msg)
}
fieldsList = append(fieldsList, info)
fieldsMap[info.Key] = info
}
sinfo = &structInfo{
fieldsMap,
fieldsList,
inlineMap,
reflect.New(st).Elem(),
}
structMapMutex.Lock()
structMap[st] = sinfo
structMapMutex.Unlock()
return sinfo, nil
}

View File

@ -0,0 +1,294 @@
// +build ignore
package main
import (
"bytes"
"fmt"
"go/format"
"html/template"
"io/ioutil"
"log"
"path/filepath"
"strings"
"github.com/globalsign/mgo/internal/json"
)
func main() {
log.SetFlags(0)
log.SetPrefix(name + ": ")
var g Generator
fmt.Fprintf(&g, "// Code generated by \"%s.go\"; DO NOT EDIT\n\n", name)
src := g.generate()
err := ioutil.WriteFile(fmt.Sprintf("%s.go", strings.TrimSuffix(name, "_generator")), src, 0644)
if err != nil {
log.Fatalf("writing output: %s", err)
}
}
// Generator holds the state of the analysis. Primarily used to buffer
// the output for format.Source.
type Generator struct {
bytes.Buffer // Accumulated output.
}
// format returns the gofmt-ed contents of the Generator's buffer.
func (g *Generator) format() []byte {
src, err := format.Source(g.Bytes())
if err != nil {
// Should never happen, but can arise when developing this code.
// The user can compile the output to see the error.
log.Printf("warning: internal error: invalid Go generated: %s", err)
log.Printf("warning: compile the package to analyze the error")
return g.Bytes()
}
return src
}
// EVERYTHING ABOVE IS CONSTANT BETWEEN THE GENERATORS
const name = "bson_corpus_spec_test_generator"
func (g *Generator) generate() []byte {
testFiles, err := filepath.Glob("./specdata/specifications/source/bson-corpus/tests/*.json")
if err != nil {
log.Fatalf("error reading bson-corpus files: %s", err)
}
tests, err := g.loadTests(testFiles)
if err != nil {
log.Fatalf("error loading tests: %s", err)
}
tmpl, err := g.getTemplate()
if err != nil {
log.Fatalf("error loading template: %s", err)
}
tmpl.Execute(&g.Buffer, tests)
return g.format()
}
func (g *Generator) loadTests(filenames []string) ([]*testDef, error) {
var tests []*testDef
for _, filename := range filenames {
test, err := g.loadTest(filename)
if err != nil {
return nil, err
}
tests = append(tests, test)
}
return tests, nil
}
func (g *Generator) loadTest(filename string) (*testDef, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var testDef testDef
err = json.Unmarshal(content, &testDef)
if err != nil {
return nil, err
}
names := make(map[string]struct{})
for i := len(testDef.Valid) - 1; i >= 0; i-- {
if testDef.BsonType == "0x05" && testDef.Valid[i].Description == "subtype 0x02" {
testDef.Valid = append(testDef.Valid[:i], testDef.Valid[i+1:]...)
continue
}
name := cleanupFuncName(testDef.Description + "_" + testDef.Valid[i].Description)
nameIdx := name
j := 1
for {
if _, ok := names[nameIdx]; !ok {
break
}
nameIdx = fmt.Sprintf("%s_%d", name, j)
}
names[nameIdx] = struct{}{}
testDef.Valid[i].TestDef = &testDef
testDef.Valid[i].Name = nameIdx
testDef.Valid[i].StructTest = testDef.TestKey != "" &&
(testDef.BsonType != "0x05" || strings.Contains(testDef.Valid[i].Description, "0x00")) &&
!testDef.Deprecated
}
for i := len(testDef.DecodeErrors) - 1; i >= 0; i-- {
if strings.Contains(testDef.DecodeErrors[i].Description, "UTF-8") {
testDef.DecodeErrors = append(testDef.DecodeErrors[:i], testDef.DecodeErrors[i+1:]...)
continue
}
name := cleanupFuncName(testDef.Description + "_" + testDef.DecodeErrors[i].Description)
nameIdx := name
j := 1
for {
if _, ok := names[nameIdx]; !ok {
break
}
nameIdx = fmt.Sprintf("%s_%d", name, j)
}
names[nameIdx] = struct{}{}
testDef.DecodeErrors[i].Name = nameIdx
}
return &testDef, nil
}
func (g *Generator) getTemplate() (*template.Template, error) {
content := `package bson_test
import (
"encoding/hex"
"time"
. "gopkg.in/check.v1"
"github.com/globalsign/mgo/bson"
)
func testValid(c *C, in []byte, expected []byte, result interface{}) {
err := bson.Unmarshal(in, result)
c.Assert(err, IsNil)
out, err := bson.Marshal(result)
c.Assert(err, IsNil)
c.Assert(string(expected), Equals, string(out), Commentf("roundtrip failed for %T, expected '%x' but got '%x'", result, expected, out))
}
func testDecodeSkip(c *C, in []byte) {
err := bson.Unmarshal(in, &struct{}{})
c.Assert(err, IsNil)
}
func testDecodeError(c *C, in []byte, result interface{}) {
err := bson.Unmarshal(in, result)
c.Assert(err, Not(IsNil))
}
{{range .}}
{{range .Valid}}
func (s *S) Test{{.Name}}(c *C) {
b, err := hex.DecodeString("{{.Bson}}")
c.Assert(err, IsNil)
{{if .CanonicalBson}}
cb, err := hex.DecodeString("{{.CanonicalBson}}")
c.Assert(err, IsNil)
{{else}}
cb := b
{{end}}
var resultD bson.D
testValid(c, b, cb, &resultD)
{{if .StructTest}}var resultS struct {
Element {{.TestDef.GoType}} ` + "`bson:\"{{.TestDef.TestKey}}\"`" + `
}
testValid(c, b, cb, &resultS){{end}}
testDecodeSkip(c, b)
}
{{end}}
{{range .DecodeErrors}}
func (s *S) Test{{.Name}}(c *C) {
b, err := hex.DecodeString("{{.Bson}}")
c.Assert(err, IsNil)
var resultD bson.D
testDecodeError(c, b, &resultD)
}
{{end}}
{{end}}
`
tmpl, err := template.New("").Parse(content)
if err != nil {
return nil, err
}
return tmpl, nil
}
func cleanupFuncName(name string) string {
return strings.Map(func(r rune) rune {
if (r >= 48 && r <= 57) || (r >= 65 && r <= 90) || (r >= 97 && r <= 122) {
return r
}
return '_'
}, name)
}
type testDef struct {
Description string `json:"description"`
BsonType string `json:"bson_type"`
TestKey string `json:"test_key"`
Valid []*valid `json:"valid"`
DecodeErrors []*decodeError `json:"decodeErrors"`
Deprecated bool `json:"deprecated"`
}
func (t *testDef) GoType() string {
switch t.BsonType {
case "0x01":
return "float64"
case "0x02":
return "string"
case "0x03":
return "bson.D"
case "0x04":
return "[]interface{}"
case "0x05":
return "[]byte"
case "0x07":
return "bson.ObjectId"
case "0x08":
return "bool"
case "0x09":
return "time.Time"
case "0x0E":
return "string"
case "0x10":
return "int32"
case "0x12":
return "int64"
case "0x13":
return "bson.Decimal"
default:
return "interface{}"
}
}
type valid struct {
Description string `json:"description"`
Bson string `json:"bson"`
CanonicalBson string `json:"canonical_bson"`
Name string
StructTest bool
TestDef *testDef
}
type decodeError struct {
Description string `json:"description"`
Bson string `json:"bson"`
Name string
}

29
vendor/github.com/globalsign/mgo/bson/compatibility.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
package bson
// Current state of the JSON tag fallback option.
var useJSONTagFallback = false
var useRespectNilValues = false
// SetJSONTagFallback enables or disables the JSON-tag fallback for structure tagging. When this is enabled, structures
// without BSON tags on a field will fall-back to using the JSON tag (if present).
func SetJSONTagFallback(state bool) {
useJSONTagFallback = state
}
// JSONTagFallbackState returns the current status of the JSON tag fallback compatability option. See SetJSONTagFallback
// for more information.
func JSONTagFallbackState() bool {
return useJSONTagFallback
}
// SetRespectNilValues enables or disables serializing nil slices or maps to `null` values.
// In other words it enables `encoding/json` compatible behaviour.
func SetRespectNilValues(state bool) {
useRespectNilValues = state
}
// RespectNilValuesState returns the current status of the JSON nil slices and maps fallback compatibility option.
// See SetRespectNilValues for more information.
func RespectNilValuesState() bool {
return useRespectNilValues
}

312
vendor/github.com/globalsign/mgo/bson/decimal.go generated vendored Normal file
View File

@ -0,0 +1,312 @@
// BSON library for Go
//
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package bson
import (
"fmt"
"strconv"
"strings"
)
// Decimal128 holds decimal128 BSON values.
type Decimal128 struct {
h, l uint64
}
func (d Decimal128) String() string {
var pos int // positive sign
var e int // exponent
var h, l uint64 // significand high/low
if d.h>>63&1 == 0 {
pos = 1
}
switch d.h >> 58 & (1<<5 - 1) {
case 0x1F:
return "NaN"
case 0x1E:
return "-Inf"[pos:]
}
l = d.l
if d.h>>61&3 == 3 {
// Bits: 1*sign 2*ignored 14*exponent 111*significand.
// Implicit 0b100 prefix in significand.
e = int(d.h>>47&(1<<14-1)) - 6176
//h = 4<<47 | d.h&(1<<47-1)
// Spec says all of these values are out of range.
h, l = 0, 0
} else {
// Bits: 1*sign 14*exponent 113*significand
e = int(d.h>>49&(1<<14-1)) - 6176
h = d.h & (1<<49 - 1)
}
// Would be handled by the logic below, but that's trivial and common.
if h == 0 && l == 0 && e == 0 {
return "-0"[pos:]
}
var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero.
var last = len(repr)
var i = len(repr)
var dot = len(repr) + e
var rem uint32
Loop:
for d9 := 0; d9 < 5; d9++ {
h, l, rem = divmod(h, l, 1e9)
for d1 := 0; d1 < 9; d1++ {
// Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc.
if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) {
e += len(repr) - i
i--
repr[i] = '.'
last = i - 1
dot = len(repr) // Unmark.
}
c := '0' + byte(rem%10)
rem /= 10
i--
repr[i] = c
// Handle "0E+3", "1E+3", etc.
if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) {
last = i
break Loop
}
if c != '0' {
last = i
}
// Break early. Works without it, but why.
if dot > i && l == 0 && h == 0 && rem == 0 {
break Loop
}
}
}
repr[last-1] = '-'
last--
if e > 0 {
return string(repr[last+pos:]) + "E+" + strconv.Itoa(e)
}
if e < 0 {
return string(repr[last+pos:]) + "E" + strconv.Itoa(e)
}
return string(repr[last+pos:])
}
func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) {
div64 := uint64(div)
a := h >> 32
aq := a / div64
ar := a % div64
b := ar<<32 + h&(1<<32-1)
bq := b / div64
br := b % div64
c := br<<32 + l>>32
cq := c / div64
cr := c % div64
d := cr<<32 + l&(1<<32-1)
dq := d / div64
dr := d % div64
return (aq<<32 | bq), (cq<<32 | dq), uint32(dr)
}
var dNaN = Decimal128{0x1F << 58, 0}
var dPosInf = Decimal128{0x1E << 58, 0}
var dNegInf = Decimal128{0x3E << 58, 0}
func dErr(s string) (Decimal128, error) {
return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s)
}
// ParseDecimal128 parse a string and return the corresponding value as
// a decimal128
func ParseDecimal128(s string) (Decimal128, error) {
orig := s
if s == "" {
return dErr(orig)
}
neg := s[0] == '-'
if neg || s[0] == '+' {
s = s[1:]
}
if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') {
if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") {
return dNaN, nil
}
if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") {
if neg {
return dNegInf, nil
}
return dPosInf, nil
}
return dErr(orig)
}
var h, l uint64
var e int
var add, ovr uint32
var mul uint32 = 1
var dot = -1
var digits = 0
var i = 0
for i < len(s) {
c := s[i]
if mul == 1e9 {
h, l, ovr = muladd(h, l, mul, add)
mul, add = 1, 0
if ovr > 0 || h&((1<<15-1)<<49) > 0 {
return dErr(orig)
}
}
if c >= '0' && c <= '9' {
i++
if c > '0' || digits > 0 {
digits++
}
if digits > 34 {
if c == '0' {
// Exact rounding.
e++
continue
}
return dErr(orig)
}
mul *= 10
add *= 10
add += uint32(c - '0')
continue
}
if c == '.' {
i++
if dot >= 0 || i == 1 && len(s) == 1 {
return dErr(orig)
}
if i == len(s) {
break
}
if s[i] < '0' || s[i] > '9' || e > 0 {
return dErr(orig)
}
dot = i
continue
}
break
}
if i == 0 {
return dErr(orig)
}
if mul > 1 {
h, l, ovr = muladd(h, l, mul, add)
if ovr > 0 || h&((1<<15-1)<<49) > 0 {
return dErr(orig)
}
}
if dot >= 0 {
e += dot - i
}
if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') {
i++
eneg := s[i] == '-'
if eneg || s[i] == '+' {
i++
if i == len(s) {
return dErr(orig)
}
}
n := 0
for i < len(s) && n < 1e4 {
c := s[i]
i++
if c < '0' || c > '9' {
return dErr(orig)
}
n *= 10
n += int(c - '0')
}
if eneg {
n = -n
}
e += n
for e < -6176 {
// Subnormal.
var div uint32 = 1
for div < 1e9 && e < -6176 {
div *= 10
e++
}
var rem uint32
h, l, rem = divmod(h, l, div)
if rem > 0 {
return dErr(orig)
}
}
for e > 6111 {
// Clamped.
var mul uint32 = 1
for mul < 1e9 && e > 6111 {
mul *= 10
e--
}
h, l, ovr = muladd(h, l, mul, 0)
if ovr > 0 || h&((1<<15-1)<<49) > 0 {
return dErr(orig)
}
}
if e < -6176 || e > 6111 {
return dErr(orig)
}
}
if i < len(s) {
return dErr(orig)
}
h |= uint64(e+6176) & uint64(1<<14-1) << 49
if neg {
h |= 1 << 63
}
return Decimal128{h, l}, nil
}
func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) {
mul64 := uint64(mul)
a := mul64 * (l & (1<<32 - 1))
b := a>>32 + mul64*(l>>32)
c := b>>32 + mul64*(h&(1<<32-1))
d := c>>32 + mul64*(h>>32)
a = a&(1<<32-1) + uint64(add)
b = b&(1<<32-1) + a>>32
c = c&(1<<32-1) + b>>32
d = d&(1<<32-1) + c>>32
return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32)
}

1055
vendor/github.com/globalsign/mgo/bson/decode.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

645
vendor/github.com/globalsign/mgo/bson/encode.go generated vendored Normal file
View File

@ -0,0 +1,645 @@
// BSON library for Go
//
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// gobson - BSON library for Go.
package bson
import (
"encoding/json"
"fmt"
"math"
"net/url"
"reflect"
"sort"
"strconv"
"sync"
"time"
)
// --------------------------------------------------------------------------
// Some internal infrastructure.
var (
typeBinary = reflect.TypeOf(Binary{})
typeObjectId = reflect.TypeOf(ObjectId(""))
typeDBPointer = reflect.TypeOf(DBPointer{"", ObjectId("")})
typeSymbol = reflect.TypeOf(Symbol(""))
typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
typeOrderKey = reflect.TypeOf(MinKey)
typeDocElem = reflect.TypeOf(DocElem{})
typeRawDocElem = reflect.TypeOf(RawDocElem{})
typeRaw = reflect.TypeOf(Raw{})
typeRawPtr = reflect.PtrTo(reflect.TypeOf(Raw{}))
typeURL = reflect.TypeOf(url.URL{})
typeTime = reflect.TypeOf(time.Time{})
typeString = reflect.TypeOf("")
typeJSONNumber = reflect.TypeOf(json.Number(""))
typeTimeDuration = reflect.TypeOf(time.Duration(0))
)
var (
// spec for []uint8 or []byte encoding
arrayOps = map[string]bool{
"$in": true,
"$nin": true,
"$all": true,
}
)
const itoaCacheSize = 32
const (
getterUnknown = iota
getterNone
getterTypeVal
getterTypePtr
getterAddr
)
var itoaCache []string
var getterStyles map[reflect.Type]int
var getterIface reflect.Type
var getterMutex sync.RWMutex
func init() {
itoaCache = make([]string, itoaCacheSize)
for i := 0; i != itoaCacheSize; i++ {
itoaCache[i] = strconv.Itoa(i)
}
var iface Getter
getterIface = reflect.TypeOf(&iface).Elem()
getterStyles = make(map[reflect.Type]int)
}
func itoa(i int) string {
if i < itoaCacheSize {
return itoaCache[i]
}
return strconv.Itoa(i)
}
func getterStyle(outt reflect.Type) int {
getterMutex.RLock()
style := getterStyles[outt]
getterMutex.RUnlock()
if style != getterUnknown {
return style
}
getterMutex.Lock()
defer getterMutex.Unlock()
if outt.Implements(getterIface) {
vt := outt
for vt.Kind() == reflect.Ptr {
vt = vt.Elem()
}
if vt.Implements(getterIface) {
style = getterTypeVal
} else {
style = getterTypePtr
}
} else if reflect.PtrTo(outt).Implements(getterIface) {
style = getterAddr
} else {
style = getterNone
}
getterStyles[outt] = style
return style
}
func getGetter(outt reflect.Type, out reflect.Value) Getter {
style := getterStyle(outt)
if style == getterNone {
return nil
}
if style == getterAddr {
if !out.CanAddr() {
return nil
}
return out.Addr().Interface().(Getter)
}
if style == getterTypeVal && out.Kind() == reflect.Ptr && out.IsNil() {
return nil
}
return out.Interface().(Getter)
}
// --------------------------------------------------------------------------
// Marshaling of the document value itself.
type encoder struct {
out []byte
}
func (e *encoder) addDoc(v reflect.Value) {
for {
if vi, ok := v.Interface().(Getter); ok {
getv, err := vi.GetBSON()
if err != nil {
panic(err)
}
v = reflect.ValueOf(getv)
continue
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
continue
}
break
}
if v.Type() == typeRaw {
raw := v.Interface().(Raw)
if raw.Kind != 0x03 && raw.Kind != 0x00 {
panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document")
}
if len(raw.Data) == 0 {
panic("Attempted to marshal empty Raw document")
}
e.addBytes(raw.Data...)
return
}
start := e.reserveInt32()
switch v.Kind() {
case reflect.Map:
e.addMap(v)
case reflect.Struct:
e.addStruct(v)
case reflect.Array, reflect.Slice:
e.addSlice(v)
default:
panic("Can't marshal " + v.Type().String() + " as a BSON document")
}
e.addBytes(0)
e.setInt32(start, int32(len(e.out)-start))
}
func (e *encoder) addMap(v reflect.Value) {
for _, k := range v.MapKeys() {
e.addElem(fmt.Sprint(k), v.MapIndex(k), false)
}
}
func (e *encoder) addStruct(v reflect.Value) {
sinfo, err := getStructInfo(v.Type())
if err != nil {
panic(err)
}
var value reflect.Value
if sinfo.InlineMap >= 0 {
m := v.Field(sinfo.InlineMap)
if m.Len() > 0 {
for _, k := range m.MapKeys() {
ks := k.String()
if _, found := sinfo.FieldsMap[ks]; found {
panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks))
}
e.addElem(ks, m.MapIndex(k), false)
}
}
}
for _, info := range sinfo.FieldsList {
if info.Inline == nil {
value = v.Field(info.Num)
} else {
// as pointers to struct are allowed here,
// there is no guarantee that pointer won't be nil.
//
// It is expected allowed behaviour
// so info.Inline MAY consist index to a nil pointer
// and that is why we safely call v.FieldByIndex and just continue on panic
field, errField := safeFieldByIndex(v, info.Inline)
if errField != nil {
continue
}
value = field
}
if info.OmitEmpty && isZero(value) {
continue
}
if useRespectNilValues &&
(value.Kind() == reflect.Slice || value.Kind() == reflect.Map) &&
value.IsNil() {
e.addElem(info.Key, reflect.ValueOf(nil), info.MinSize)
continue
}
e.addElem(info.Key, value, info.MinSize)
}
}
func safeFieldByIndex(v reflect.Value, index []int) (result reflect.Value, err error) {
defer func() {
if recovered := recover(); recovered != nil {
switch r := recovered.(type) {
case string:
err = fmt.Errorf("%s", r)
case error:
err = r
}
}
}()
result = v.FieldByIndex(index)
return
}
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.String:
return len(v.String()) == 0
case reflect.Ptr, reflect.Interface:
return v.IsNil()
case reflect.Slice:
return v.Len() == 0
case reflect.Map:
return v.Len() == 0
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Struct:
vt := v.Type()
if vt == typeTime {
return v.Interface().(time.Time).IsZero()
}
for i := 0; i < v.NumField(); i++ {
if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous {
continue // Private field
}
if !isZero(v.Field(i)) {
return false
}
}
return true
}
return false
}
func (e *encoder) addSlice(v reflect.Value) {
vi := v.Interface()
if d, ok := vi.(D); ok {
for _, elem := range d {
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
}
return
}
if d, ok := vi.(RawD); ok {
for _, elem := range d {
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
}
return
}
l := v.Len()
et := v.Type().Elem()
if et == typeDocElem {
for i := 0; i < l; i++ {
elem := v.Index(i).Interface().(DocElem)
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
}
return
}
if et == typeRawDocElem {
for i := 0; i < l; i++ {
elem := v.Index(i).Interface().(RawDocElem)
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
}
return
}
for i := 0; i < l; i++ {
e.addElem(itoa(i), v.Index(i), false)
}
}
// --------------------------------------------------------------------------
// Marshaling of elements in a document.
func (e *encoder) addElemName(kind byte, name string) {
e.addBytes(kind)
e.addBytes([]byte(name)...)
e.addBytes(0)
}
func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
if !v.IsValid() {
e.addElemName(0x0A, name)
return
}
if getter := getGetter(v.Type(), v); getter != nil {
getv, err := getter.GetBSON()
if err != nil {
panic(err)
}
e.addElem(name, reflect.ValueOf(getv), minSize)
return
}
switch v.Kind() {
case reflect.Interface:
e.addElem(name, v.Elem(), minSize)
case reflect.Ptr:
e.addElem(name, v.Elem(), minSize)
case reflect.String:
s := v.String()
switch v.Type() {
case typeObjectId:
if len(s) != 12 {
panic("ObjectIDs must be exactly 12 bytes long (got " +
strconv.Itoa(len(s)) + ")")
}
e.addElemName(0x07, name)
e.addBytes([]byte(s)...)
case typeSymbol:
e.addElemName(0x0E, name)
e.addStr(s)
case typeJSONNumber:
n := v.Interface().(json.Number)
if i, err := n.Int64(); err == nil {
e.addElemName(0x12, name)
e.addInt64(i)
} else if f, err := n.Float64(); err == nil {
e.addElemName(0x01, name)
e.addFloat64(f)
} else {
panic("failed to convert json.Number to a number: " + s)
}
default:
e.addElemName(0x02, name)
e.addStr(s)
}
case reflect.Float32, reflect.Float64:
e.addElemName(0x01, name)
e.addFloat64(v.Float())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
u := v.Uint()
if int64(u) < 0 {
panic("BSON has no uint64 type, and value is too large to fit correctly in an int64")
} else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) {
e.addElemName(0x10, name)
e.addInt32(int32(u))
} else {
e.addElemName(0x12, name)
e.addInt64(int64(u))
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch v.Type() {
case typeMongoTimestamp:
e.addElemName(0x11, name)
e.addInt64(v.Int())
case typeOrderKey:
if v.Int() == int64(MaxKey) {
e.addElemName(0x7F, name)
} else {
e.addElemName(0xFF, name)
}
case typeTimeDuration:
// Stored as int64
e.addElemName(0x12, name)
e.addInt64(int64(v.Int() / 1e6))
default:
i := v.Int()
if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 {
// It fits into an int32, encode as such.
e.addElemName(0x10, name)
e.addInt32(int32(i))
} else {
e.addElemName(0x12, name)
e.addInt64(i)
}
}
case reflect.Bool:
e.addElemName(0x08, name)
if v.Bool() {
e.addBytes(1)
} else {
e.addBytes(0)
}
case reflect.Map:
e.addElemName(0x03, name)
e.addDoc(v)
case reflect.Slice:
vt := v.Type()
et := vt.Elem()
if et.Kind() == reflect.Uint8 {
if arrayOps[name] {
e.addElemName(0x04, name)
e.addDoc(v)
} else {
e.addElemName(0x05, name)
e.addBinary(0x00, v.Bytes())
}
} else if et == typeDocElem || et == typeRawDocElem {
e.addElemName(0x03, name)
e.addDoc(v)
} else {
e.addElemName(0x04, name)
e.addDoc(v)
}
case reflect.Array:
et := v.Type().Elem()
if et.Kind() == reflect.Uint8 {
if arrayOps[name] {
e.addElemName(0x04, name)
e.addDoc(v)
} else {
e.addElemName(0x05, name)
if v.CanAddr() {
e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte))
} else {
n := v.Len()
e.addInt32(int32(n))
e.addBytes(0x00)
for i := 0; i < n; i++ {
el := v.Index(i)
e.addBytes(byte(el.Uint()))
}
}
}
} else {
e.addElemName(0x04, name)
e.addDoc(v)
}
case reflect.Struct:
switch s := v.Interface().(type) {
case Raw:
kind := s.Kind
if kind == 0x00 {
kind = 0x03
}
if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F {
panic("Attempted to marshal empty Raw document")
}
e.addElemName(kind, name)
e.addBytes(s.Data...)
case Binary:
e.addElemName(0x05, name)
e.addBinary(s.Kind, s.Data)
case Decimal128:
e.addElemName(0x13, name)
e.addInt64(int64(s.l))
e.addInt64(int64(s.h))
case DBPointer:
e.addElemName(0x0C, name)
e.addStr(s.Namespace)
if len(s.Id) != 12 {
panic("ObjectIDs must be exactly 12 bytes long (got " +
strconv.Itoa(len(s.Id)) + ")")
}
e.addBytes([]byte(s.Id)...)
case RegEx:
e.addElemName(0x0B, name)
e.addCStr(s.Pattern)
options := runes(s.Options)
sort.Sort(options)
e.addCStr(string(options))
case JavaScript:
if s.Scope == nil {
e.addElemName(0x0D, name)
e.addStr(s.Code)
} else {
e.addElemName(0x0F, name)
start := e.reserveInt32()
e.addStr(s.Code)
e.addDoc(reflect.ValueOf(s.Scope))
e.setInt32(start, int32(len(e.out)-start))
}
case time.Time:
// MongoDB handles timestamps as milliseconds.
e.addElemName(0x09, name)
e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6))
case url.URL:
e.addElemName(0x02, name)
e.addStr(s.String())
case undefined:
e.addElemName(0x06, name)
default:
e.addElemName(0x03, name)
e.addDoc(v)
}
default:
panic("Can't marshal " + v.Type().String() + " in a BSON document")
}
}
// -------------
// Helper method for sorting regex options
type runes []rune
func (a runes) Len() int { return len(a) }
func (a runes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a runes) Less(i, j int) bool { return a[i] < a[j] }
// --------------------------------------------------------------------------
// Marshaling of base types.
func (e *encoder) addBinary(subtype byte, v []byte) {
if subtype == 0x02 {
// Wonder how that brilliant idea came to life. Obsolete, luckily.
e.addInt32(int32(len(v) + 4))
e.addBytes(subtype)
e.addInt32(int32(len(v)))
} else {
e.addInt32(int32(len(v)))
e.addBytes(subtype)
}
e.addBytes(v...)
}
func (e *encoder) addStr(v string) {
e.addInt32(int32(len(v) + 1))
e.addCStr(v)
}
func (e *encoder) addCStr(v string) {
e.addBytes([]byte(v)...)
e.addBytes(0)
}
func (e *encoder) reserveInt32() (pos int) {
pos = len(e.out)
e.addBytes(0, 0, 0, 0)
return pos
}
func (e *encoder) setInt32(pos int, v int32) {
e.out[pos+0] = byte(v)
e.out[pos+1] = byte(v >> 8)
e.out[pos+2] = byte(v >> 16)
e.out[pos+3] = byte(v >> 24)
}
func (e *encoder) addInt32(v int32) {
u := uint32(v)
e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24))
}
func (e *encoder) addInt64(v int64) {
u := uint64(v)
e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24),
byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56))
}
func (e *encoder) addFloat64(v float64) {
e.addInt64(int64(math.Float64bits(v)))
}
func (e *encoder) addBytes(v ...byte) {
e.out = append(e.out, v...)
}

384
vendor/github.com/globalsign/mgo/bson/json.go generated vendored Normal file
View File

@ -0,0 +1,384 @@
package bson
import (
"bytes"
"encoding/base64"
"fmt"
"strconv"
"strings"
"time"
"github.com/globalsign/mgo/internal/json"
)
// UnmarshalJSON unmarshals a JSON value that may hold non-standard
// syntax as defined in BSON's extended JSON specification.
func UnmarshalJSON(data []byte, value interface{}) error {
d := json.NewDecoder(bytes.NewBuffer(data))
d.Extend(&jsonExt)
return d.Decode(value)
}
// MarshalJSON marshals a JSON value that may hold non-standard
// syntax as defined in BSON's extended JSON specification.
func MarshalJSON(value interface{}) ([]byte, error) {
var buf bytes.Buffer
e := json.NewEncoder(&buf)
e.Extend(&jsonExt)
err := e.Encode(value)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// jdec is used internally by the JSON decoding functions
// so they may unmarshal functions without getting into endless
// recursion due to keyed objects.
func jdec(data []byte, value interface{}) error {
d := json.NewDecoder(bytes.NewBuffer(data))
d.Extend(&funcExt)
return d.Decode(value)
}
var jsonExt json.Extension
var funcExt json.Extension
// TODO
// - Shell regular expressions ("/regexp/opts")
func init() {
jsonExt.DecodeUnquotedKeys(true)
jsonExt.DecodeTrailingCommas(true)
funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary")
jsonExt.DecodeKeyed("$binary", jdecBinary)
jsonExt.DecodeKeyed("$binaryFunc", jdecBinary)
jsonExt.EncodeType([]byte(nil), jencBinarySlice)
jsonExt.EncodeType(Binary{}, jencBinaryType)
funcExt.DecodeFunc("ISODate", "$dateFunc", "S")
funcExt.DecodeFunc("new Date", "$dateFunc", "S")
jsonExt.DecodeKeyed("$date", jdecDate)
jsonExt.DecodeKeyed("$dateFunc", jdecDate)
jsonExt.EncodeType(time.Time{}, jencDate)
funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i")
jsonExt.DecodeKeyed("$timestamp", jdecTimestamp)
jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp)
funcExt.DecodeConst("undefined", Undefined)
jsonExt.DecodeKeyed("$regex", jdecRegEx)
jsonExt.EncodeType(RegEx{}, jencRegEx)
funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id")
jsonExt.DecodeKeyed("$oid", jdecObjectId)
jsonExt.DecodeKeyed("$oidFunc", jdecObjectId)
jsonExt.EncodeType(ObjectId(""), jencObjectId)
funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id")
jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef)
funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N")
jsonExt.DecodeKeyed("$numberLong", jdecNumberLong)
jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong)
jsonExt.EncodeType(int64(0), jencNumberLong)
jsonExt.EncodeType(int(0), jencInt)
funcExt.DecodeConst("MinKey", MinKey)
funcExt.DecodeConst("MaxKey", MaxKey)
jsonExt.DecodeKeyed("$minKey", jdecMinKey)
jsonExt.DecodeKeyed("$maxKey", jdecMaxKey)
jsonExt.EncodeType(orderKey(0), jencMinMaxKey)
jsonExt.DecodeKeyed("$undefined", jdecUndefined)
jsonExt.EncodeType(Undefined, jencUndefined)
jsonExt.Extend(&funcExt)
}
func fbytes(format string, args ...interface{}) []byte {
var buf bytes.Buffer
fmt.Fprintf(&buf, format, args...)
return buf.Bytes()
}
func jdecBinary(data []byte) (interface{}, error) {
var v struct {
Binary []byte `json:"$binary"`
Type string `json:"$type"`
Func struct {
Binary []byte `json:"$binary"`
Type int64 `json:"$type"`
} `json:"$binaryFunc"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
var binData []byte
var binKind int64
if v.Type == "" && v.Binary == nil {
binData = v.Func.Binary
binKind = v.Func.Type
} else if v.Type == "" {
return v.Binary, nil
} else {
binData = v.Binary
binKind, err = strconv.ParseInt(v.Type, 0, 64)
if err != nil {
binKind = -1
}
}
if binKind == 0 {
return binData, nil
}
if binKind < 0 || binKind > 255 {
return nil, fmt.Errorf("invalid type in binary object: %s", data)
}
return Binary{Kind: byte(binKind), Data: binData}, nil
}
func jencBinarySlice(v interface{}) ([]byte, error) {
in := v.([]byte)
out := make([]byte, base64.StdEncoding.EncodedLen(len(in)))
base64.StdEncoding.Encode(out, in)
return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil
}
func jencBinaryType(v interface{}) ([]byte, error) {
in := v.(Binary)
out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data)))
base64.StdEncoding.Encode(out, in.Data)
return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil
}
const jdateFormat = "2006-01-02T15:04:05.999Z07:00"
func jdecDate(data []byte) (interface{}, error) {
var v struct {
S string `json:"$date"`
Func struct {
S string
} `json:"$dateFunc"`
}
_ = jdec(data, &v)
if v.S == "" {
v.S = v.Func.S
}
if v.S != "" {
var errs []string
for _, format := range []string{jdateFormat, "2006-01-02"} {
t, err := time.Parse(format, v.S)
if err == nil {
return t, nil
}
errs = append(errs, err.Error())
}
return nil, fmt.Errorf("cannot parse date: %q [%s]", v.S, strings.Join(errs, ", "))
}
var vn struct {
Date struct {
N int64 `json:"$numberLong,string"`
} `json:"$date"`
Func struct {
S int64
} `json:"$dateFunc"`
}
err := jdec(data, &vn)
if err != nil {
return nil, fmt.Errorf("cannot parse date: %q", data)
}
n := vn.Date.N
if n == 0 {
n = vn.Func.S
}
return time.Unix(n/1000, n%1000*1e6).UTC(), nil
}
func jencDate(v interface{}) ([]byte, error) {
t := v.(time.Time)
return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil
}
func jdecTimestamp(data []byte) (interface{}, error) {
var v struct {
Func struct {
T int32 `json:"t"`
I int32 `json:"i"`
} `json:"$timestamp"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil
}
func jencTimestamp(v interface{}) ([]byte, error) {
ts := uint64(v.(MongoTimestamp))
return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil
}
func jdecRegEx(data []byte) (interface{}, error) {
var v struct {
Regex string `json:"$regex"`
Options string `json:"$options"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
return RegEx{v.Regex, v.Options}, nil
}
func jencRegEx(v interface{}) ([]byte, error) {
re := v.(RegEx)
type regex struct {
Regex string `json:"$regex"`
Options string `json:"$options"`
}
return json.Marshal(regex{re.Pattern, re.Options})
}
func jdecObjectId(data []byte) (interface{}, error) {
var v struct {
Id string `json:"$oid"`
Func struct {
Id string
} `json:"$oidFunc"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
if v.Id == "" {
v.Id = v.Func.Id
}
return ObjectIdHex(v.Id), nil
}
func jencObjectId(v interface{}) ([]byte, error) {
return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil
}
func jdecDBRef(data []byte) (interface{}, error) {
// TODO Support unmarshaling $ref and $id into the input value.
var v struct {
Obj map[string]interface{} `json:"$dbrefFunc"`
}
// TODO Fix this. Must not be required.
v.Obj = make(map[string]interface{})
err := jdec(data, &v)
if err != nil {
return nil, err
}
return v.Obj, nil
}
func jdecNumberLong(data []byte) (interface{}, error) {
var v struct {
N int64 `json:"$numberLong,string"`
Func struct {
N int64 `json:",string"`
} `json:"$numberLongFunc"`
}
var vn struct {
N int64 `json:"$numberLong"`
Func struct {
N int64
} `json:"$numberLongFunc"`
}
err := jdec(data, &v)
if err != nil {
err = jdec(data, &vn)
v.N = vn.N
v.Func.N = vn.Func.N
}
if err != nil {
return nil, err
}
if v.N != 0 {
return v.N, nil
}
return v.Func.N, nil
}
func jencNumberLong(v interface{}) ([]byte, error) {
n := v.(int64)
f := `{"$numberLong":"%d"}`
if n <= 1<<53 {
f = `{"$numberLong":%d}`
}
return fbytes(f, n), nil
}
func jencInt(v interface{}) ([]byte, error) {
n := v.(int)
f := `{"$numberLong":"%d"}`
if int64(n) <= 1<<53 {
f = `%d`
}
return fbytes(f, n), nil
}
func jdecMinKey(data []byte) (interface{}, error) {
var v struct {
N int64 `json:"$minKey"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
if v.N != 1 {
return nil, fmt.Errorf("invalid $minKey object: %s", data)
}
return MinKey, nil
}
func jdecMaxKey(data []byte) (interface{}, error) {
var v struct {
N int64 `json:"$maxKey"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
if v.N != 1 {
return nil, fmt.Errorf("invalid $maxKey object: %s", data)
}
return MaxKey, nil
}
func jencMinMaxKey(v interface{}) ([]byte, error) {
switch v.(orderKey) {
case MinKey:
return []byte(`{"$minKey":1}`), nil
case MaxKey:
return []byte(`{"$maxKey":1}`), nil
}
panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v))
}
func jdecUndefined(data []byte) (interface{}, error) {
var v struct {
B bool `json:"$undefined"`
}
err := jdec(data, &v)
if err != nil {
return nil, err
}
if !v.B {
return nil, fmt.Errorf("invalid $undefined object: %s", data)
}
return Undefined, nil
}
func jencUndefined(v interface{}) ([]byte, error) {
return []byte(`{"$undefined":true}`), nil
}

90
vendor/github.com/globalsign/mgo/bson/stream.go generated vendored Normal file
View File

@ -0,0 +1,90 @@
package bson
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
const (
// MinDocumentSize is the size of the smallest possible valid BSON document:
// an int32 size header + 0x00 (end of document).
MinDocumentSize = 5
// MaxDocumentSize is the largest possible size for a BSON document allowed by MongoDB,
// that is, 16 MiB (see https://docs.mongodb.com/manual/reference/limits/).
MaxDocumentSize = 16777216
)
// ErrInvalidDocumentSize is an error returned when a BSON document's header
// contains a size smaller than MinDocumentSize or greater than MaxDocumentSize.
type ErrInvalidDocumentSize struct {
DocumentSize int32
}
func (e ErrInvalidDocumentSize) Error() string {
return fmt.Sprintf("invalid document size %d", e.DocumentSize)
}
// A Decoder reads and decodes BSON values from an input stream.
type Decoder struct {
source io.Reader
}
// NewDecoder returns a new Decoder that reads from source.
// It does not add any extra buffering, and may not read data from source beyond the BSON values requested.
func NewDecoder(source io.Reader) *Decoder {
return &Decoder{source: source}
}
// Decode reads the next BSON-encoded value from its input and stores it in the value pointed to by v.
// See the documentation for Unmarshal for details about the conversion of BSON into a Go value.
func (dec *Decoder) Decode(v interface{}) (err error) {
// BSON documents start with their size as a *signed* int32.
var docSize int32
if err = binary.Read(dec.source, binary.LittleEndian, &docSize); err != nil {
return
}
if docSize < MinDocumentSize || docSize > MaxDocumentSize {
return ErrInvalidDocumentSize{DocumentSize: docSize}
}
docBuffer := bytes.NewBuffer(make([]byte, 0, docSize))
if err = binary.Write(docBuffer, binary.LittleEndian, docSize); err != nil {
return
}
// docSize is the *full* document's size (including the 4-byte size header,
// which has already been read).
if _, err = io.CopyN(docBuffer, dec.source, int64(docSize-4)); err != nil {
return
}
// Let Unmarshal handle the rest.
defer handleErr(&err)
return Unmarshal(docBuffer.Bytes(), v)
}
// An Encoder encodes and writes BSON values to an output stream.
type Encoder struct {
target io.Writer
}
// NewEncoder returns a new Encoder that writes to target.
func NewEncoder(target io.Writer) *Encoder {
return &Encoder{target: target}
}
// Encode encodes v to BSON, and if successful writes it to the Encoder's output stream.
// See the documentation for Marshal for details about the conversion of Go values to BSON.
func (enc *Encoder) Encode(v interface{}) error {
data, err := Marshal(v)
if err != nil {
return err
}
_, err = enc.target.Write(data)
return err
}