7
7
package bson
8
8
9
9
import (
10
+ "encoding/binary"
10
11
"errors"
11
12
"fmt"
13
+ "math"
12
14
"reflect"
13
15
)
14
16
@@ -25,7 +27,7 @@ type sliceCodec struct {
25
27
func (sc * sliceCodec ) decodeVectorBinary (vr ValueReader , val reflect.Value ) error {
26
28
elemType := val .Type ().Elem ()
27
29
28
- if elemType != TInt8 && elemType != TFloat32 {
30
+ if elemType != tInt8 && elemType != tFloat32 {
29
31
return errNotAVectorBinary
30
32
}
31
33
@@ -39,14 +41,14 @@ func (sc *sliceCodec) decodeVectorBinary(vr ValueReader, val reflect.Value) erro
39
41
}
40
42
41
43
switch elemType {
42
- case TInt8 :
43
- int8Slice , err := DecodeVectorInt8 (data )
44
+ case tInt8 :
45
+ int8Slice , err := decodeVectorInt8 (data )
44
46
if err != nil {
45
47
return err
46
48
}
47
49
val .Set (reflect .ValueOf (int8Slice ))
48
- case TFloat32 :
49
- float32Slice , err := DecodeVectorFloat32 (data )
50
+ case tFloat32 :
51
+ float32Slice , err := decodeVectorFloat32 (data )
50
52
if err != nil {
51
53
return err
52
54
}
@@ -66,8 +68,9 @@ func (sc *sliceCodec) EncodeValue(ec EncodeContext, vw ValueWriter, val reflect.
66
68
return vw .WriteNull ()
67
69
}
68
70
69
- // Treat []byte as binary data, but skip for []int8 since it's a different type
70
- // even though byte is an alias for uint8 which has the same underlying type as int8
71
+ // Treat []byte as binary data, but skip for []int8 since it's a different type.
72
+ // Even though byte is an alias for uint8 which has the same underlying type as int8,
73
+ // we want to maintain the semantic difference between []byte (binary data) and []int8 (array of integers).
71
74
if val .Type ().Elem () == tByte && val .Type () != reflect .TypeOf ([]int8 {}) {
72
75
byteSlice := make ([]byte , val .Len ())
73
76
reflect .Copy (reflect .ValueOf (byteSlice ), val )
@@ -137,12 +140,6 @@ func (sc *sliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.
137
140
return ValueDecoderError {Name : "SliceDecodeValue" , Kinds : []reflect.Kind {reflect .Slice }, Received : val }
138
141
}
139
142
140
- if vr .Type () == TypeBinary {
141
- if err := sc .decodeVectorBinary (vr , val ); err != errNotAVectorBinary {
142
- return err
143
- }
144
- }
145
-
146
143
switch vrType := vr .Type (); vrType {
147
144
case TypeArray :
148
145
case TypeNull :
@@ -156,6 +153,16 @@ func (sc *sliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.
156
153
return fmt .Errorf ("cannot decode document into %s" , val .Type ())
157
154
}
158
155
case TypeBinary :
156
+ // First try to decode as a vector binary
157
+ err := sc .decodeVectorBinary (vr , val )
158
+ if err == nil {
159
+ return nil // Successfully decoded as vector
160
+ }
161
+ if err != errNotAVectorBinary {
162
+ return err // Return any actual errors
163
+ }
164
+
165
+ // If not a vector binary, handle as regular binary data
159
166
if val .Type ().Elem () != tByte {
160
167
return fmt .Errorf ("SliceDecodeValue can only decode a binary into a byte array, got %v" , vrType )
161
168
}
@@ -215,3 +222,62 @@ func (sc *sliceCodec) DecodeValue(dc DecodeContext, vr ValueReader, val reflect.
215
222
216
223
return nil
217
224
}
225
+
226
+ // decodeVectorInt8 decodes a BSON Vector binary value (subtype 9) into a []int8 slice.
227
+ // The binary data should be in the format: [<vector type> <padding> <data>]
228
+ // For int8 vectors, the vector type is Int8Vector (0x03).
229
+ func decodeVectorInt8 (data []byte ) ([]int8 , error ) {
230
+ if len (data ) < 2 {
231
+ return nil , fmt .Errorf ("insufficient bytes to decode vector: expected at least 2 bytes" )
232
+ }
233
+
234
+ vectorType := data [0 ]
235
+ if vectorType != Int8Vector {
236
+ return nil , fmt .Errorf ("invalid vector type: expected int8 vector (0x%02x), got 0x%02x" , Int8Vector , vectorType )
237
+ }
238
+
239
+ if padding := data [1 ]; padding != 0 {
240
+ return nil , fmt .Errorf ("invalid vector: padding byte must be 0" )
241
+ }
242
+
243
+ values := make ([]int8 , 0 , len (data )- 2 )
244
+ for i := 2 ; i < len (data ); i ++ {
245
+ values = append (values , int8 (data [i ]))
246
+ }
247
+
248
+ return values , nil
249
+ }
250
+
251
+ // decodeVectorFloat32 decodes a BSON Vector binary value (subtype 9) into a []float32 slice.
252
+ // The binary data should be in the format: [<vector type> <padding> <data>]
253
+ // For float32 vectors, the vector type is Float32Vector (0x27) and data must be a multiple of 4 bytes.
254
+ func decodeVectorFloat32 (data []byte ) ([]float32 , error ) {
255
+ if len (data ) < 2 {
256
+ return nil , fmt .Errorf ("insufficient bytes to decode vector: expected at least 2 bytes" )
257
+ }
258
+
259
+ vectorType := data [0 ]
260
+ if vectorType != Float32Vector {
261
+ return nil , fmt .Errorf ("invalid vector type: expected float32 vector (0x%02x), got 0x%02x" , Float32Vector , vectorType )
262
+ }
263
+
264
+ if padding := data [1 ]; padding != 0 {
265
+ return nil , fmt .Errorf ("invalid vector: padding byte must be 0" )
266
+ }
267
+
268
+ floatData := data [2 :]
269
+ if len (floatData )% 4 != 0 {
270
+ return nil , fmt .Errorf ("invalid float32 vector: data length must be a multiple of 4" )
271
+ }
272
+
273
+ values := make ([]float32 , 0 , len (floatData )/ 4 )
274
+ for i := 0 ; i < len (floatData ); i += 4 {
275
+ if i + 4 > len (floatData ) {
276
+ return nil , fmt .Errorf ("invalid float32 vector: truncated data" )
277
+ }
278
+ bits := binary .LittleEndian .Uint32 (floatData [i : i + 4 ])
279
+ values = append (values , math .Float32frombits (bits ))
280
+ }
281
+
282
+ return values , nil
283
+ }
0 commit comments