blob: 8001d705955218b254c60c6face4c709852f1a3f [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// 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
7package bsonx
8
9import (
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.
20var ErrNilArray = errors.New("array is nil")
21
22// Arr represents an array in BSON.
23type Arr []Val
24
25// String implements the fmt.Stringer interface.
26func (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.
41func (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.
61func (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.
85func (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
97func (Arr) idoc() {}