Don Newton | 379ae25 | 2019-04-01 12:17:06 -0400 | [diff] [blame^] | 1 | // Copyright (C) MongoDB, Inc. 2017-present. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 4 | // not use this file except in compliance with the License. You may obtain |
| 5 | // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | |
| 7 | package bsonx |
| 8 | |
| 9 | import ( |
| 10 | "bytes" |
| 11 | "errors" |
| 12 | "fmt" |
| 13 | "strconv" |
| 14 | |
| 15 | "github.com/mongodb/mongo-go-driver/bson/bsontype" |
| 16 | "github.com/mongodb/mongo-go-driver/x/bsonx/bsoncore" |
| 17 | ) |
| 18 | |
| 19 | // ErrNilArray indicates that an operation was attempted on a nil *Array. |
| 20 | var ErrNilArray = errors.New("array is nil") |
| 21 | |
| 22 | // Arr represents an array in BSON. |
| 23 | type Arr []Val |
| 24 | |
| 25 | // String implements the fmt.Stringer interface. |
| 26 | func (a Arr) String() string { |
| 27 | var buf bytes.Buffer |
| 28 | buf.Write([]byte("bson.Array[")) |
| 29 | for idx, val := range a { |
| 30 | if idx > 0 { |
| 31 | buf.Write([]byte(", ")) |
| 32 | } |
| 33 | fmt.Fprintf(&buf, "%s", val) |
| 34 | } |
| 35 | buf.WriteByte(']') |
| 36 | |
| 37 | return buf.String() |
| 38 | } |
| 39 | |
| 40 | // MarshalBSONValue implements the bsoncodec.ValueMarshaler interface. |
| 41 | func (a Arr) MarshalBSONValue() (bsontype.Type, []byte, error) { |
| 42 | if a == nil { |
| 43 | // TODO: Should we do this? |
| 44 | return bsontype.Null, nil, nil |
| 45 | } |
| 46 | |
| 47 | idx, dst := bsoncore.ReserveLength(nil) |
| 48 | for idx, value := range a { |
| 49 | t, data, _ := value.MarshalBSONValue() // marshalBSONValue never returns an error. |
| 50 | dst = append(dst, byte(t)) |
| 51 | dst = append(dst, strconv.Itoa(idx)...) |
| 52 | dst = append(dst, 0x00) |
| 53 | dst = append(dst, data...) |
| 54 | } |
| 55 | dst = append(dst, 0x00) |
| 56 | dst = bsoncore.UpdateLength(dst, idx, int32(len(dst[idx:]))) |
| 57 | return bsontype.Array, dst, nil |
| 58 | } |
| 59 | |
| 60 | // UnmarshalBSONValue implements the bsoncodec.ValueUnmarshaler interface. |
| 61 | func (a *Arr) UnmarshalBSONValue(t bsontype.Type, data []byte) error { |
| 62 | if a == nil { |
| 63 | return ErrNilArray |
| 64 | } |
| 65 | *a = (*a)[:0] |
| 66 | |
| 67 | elements, err := bsoncore.Document(data).Elements() |
| 68 | if err != nil { |
| 69 | return err |
| 70 | } |
| 71 | |
| 72 | for _, elem := range elements { |
| 73 | var val Val |
| 74 | rawval := elem.Value() |
| 75 | err = val.UnmarshalBSONValue(rawval.Type, rawval.Data) |
| 76 | if err != nil { |
| 77 | return err |
| 78 | } |
| 79 | *a = append(*a, val) |
| 80 | } |
| 81 | return nil |
| 82 | } |
| 83 | |
| 84 | // Equal compares this document to another, returning true if they are equal. |
| 85 | func (a Arr) Equal(a2 Arr) bool { |
| 86 | if len(a) != len(a2) { |
| 87 | return false |
| 88 | } |
| 89 | for idx := range a { |
| 90 | if !a[idx].Equal(a2[idx]) { |
| 91 | return false |
| 92 | } |
| 93 | } |
| 94 | return true |
| 95 | } |
| 96 | |
| 97 | func (Arr) idoc() {} |