...

Source file src/go.mongodb.org/mongo-driver/bson/bsoncodec/uint_codec.go

Documentation: go.mongodb.org/mongo-driver/bson/bsoncodec

     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 bsoncodec
     8  
     9  import (
    10  	"fmt"
    11  	"math"
    12  	"reflect"
    13  
    14  	"go.mongodb.org/mongo-driver/bson/bsonoptions"
    15  	"go.mongodb.org/mongo-driver/bson/bsonrw"
    16  	"go.mongodb.org/mongo-driver/bson/bsontype"
    17  )
    18  
    19  // UIntCodec is the Codec used for uint values.
    20  //
    21  // Deprecated: UIntCodec will not be directly configurable in Go Driver 2.0. To
    22  // configure the uint encode and decode behavior, use the configuration methods
    23  // on a [go.mongodb.org/mongo-driver/bson.Encoder] or
    24  // [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the uint encode and
    25  // decode behavior for a mongo.Client, use
    26  // [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
    27  //
    28  // For example, to configure a mongo.Client to marshal Go uint values as the
    29  // minimum BSON int size that can represent the value, use:
    30  //
    31  //	opt := options.Client().SetBSONOptions(&options.BSONOptions{
    32  //	    IntMinSize: true,
    33  //	})
    34  //
    35  // See the deprecation notice for each field in UIntCodec for the corresponding
    36  // settings.
    37  type UIntCodec struct {
    38  	// EncodeToMinSize causes EncodeValue to marshal Go uint values (excluding uint64) as the
    39  	// minimum BSON int size (either 32-bit or 64-bit) that can represent the integer value.
    40  	//
    41  	// Deprecated: Use bson.Encoder.IntMinSize or options.BSONOptions.IntMinSize instead.
    42  	EncodeToMinSize bool
    43  }
    44  
    45  var (
    46  	defaultUIntCodec = NewUIntCodec()
    47  
    48  	// Assert that defaultUIntCodec satisfies the typeDecoder interface, which allows it to be used
    49  	// by collection type decoders (e.g. map, slice, etc) to set individual values in a collection.
    50  	_ typeDecoder = defaultUIntCodec
    51  )
    52  
    53  // NewUIntCodec returns a UIntCodec with options opts.
    54  //
    55  // Deprecated: NewUIntCodec will not be available in Go Driver 2.0. See
    56  // [UIntCodec] for more details.
    57  func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec {
    58  	uintOpt := bsonoptions.MergeUIntCodecOptions(opts...)
    59  
    60  	codec := UIntCodec{}
    61  	if uintOpt.EncodeToMinSize != nil {
    62  		codec.EncodeToMinSize = *uintOpt.EncodeToMinSize
    63  	}
    64  	return &codec
    65  }
    66  
    67  // EncodeValue is the ValueEncoder for uint types.
    68  func (uic *UIntCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
    69  	switch val.Kind() {
    70  	case reflect.Uint8, reflect.Uint16:
    71  		return vw.WriteInt32(int32(val.Uint()))
    72  	case reflect.Uint, reflect.Uint32, reflect.Uint64:
    73  		u64 := val.Uint()
    74  
    75  		// If ec.MinSize or if encodeToMinSize is true for a non-uint64 value we should write val as an int32
    76  		useMinSize := ec.MinSize || (uic.EncodeToMinSize && val.Kind() != reflect.Uint64)
    77  
    78  		if u64 <= math.MaxInt32 && useMinSize {
    79  			return vw.WriteInt32(int32(u64))
    80  		}
    81  		if u64 > math.MaxInt64 {
    82  			return fmt.Errorf("%d overflows int64", u64)
    83  		}
    84  		return vw.WriteInt64(int64(u64))
    85  	}
    86  
    87  	return ValueEncoderError{
    88  		Name:     "UintEncodeValue",
    89  		Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
    90  		Received: val,
    91  	}
    92  }
    93  
    94  func (uic *UIntCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
    95  	var i64 int64
    96  	var err error
    97  	switch vrType := vr.Type(); vrType {
    98  	case bsontype.Int32:
    99  		i32, err := vr.ReadInt32()
   100  		if err != nil {
   101  			return emptyValue, err
   102  		}
   103  		i64 = int64(i32)
   104  	case bsontype.Int64:
   105  		i64, err = vr.ReadInt64()
   106  		if err != nil {
   107  			return emptyValue, err
   108  		}
   109  	case bsontype.Double:
   110  		f64, err := vr.ReadDouble()
   111  		if err != nil {
   112  			return emptyValue, err
   113  		}
   114  		if !dc.Truncate && math.Floor(f64) != f64 {
   115  			return emptyValue, errCannotTruncate
   116  		}
   117  		if f64 > float64(math.MaxInt64) {
   118  			return emptyValue, fmt.Errorf("%g overflows int64", f64)
   119  		}
   120  		i64 = int64(f64)
   121  	case bsontype.Boolean:
   122  		b, err := vr.ReadBoolean()
   123  		if err != nil {
   124  			return emptyValue, err
   125  		}
   126  		if b {
   127  			i64 = 1
   128  		}
   129  	case bsontype.Null:
   130  		if err = vr.ReadNull(); err != nil {
   131  			return emptyValue, err
   132  		}
   133  	case bsontype.Undefined:
   134  		if err = vr.ReadUndefined(); err != nil {
   135  			return emptyValue, err
   136  		}
   137  	default:
   138  		return emptyValue, fmt.Errorf("cannot decode %v into an integer type", vrType)
   139  	}
   140  
   141  	switch t.Kind() {
   142  	case reflect.Uint8:
   143  		if i64 < 0 || i64 > math.MaxUint8 {
   144  			return emptyValue, fmt.Errorf("%d overflows uint8", i64)
   145  		}
   146  
   147  		return reflect.ValueOf(uint8(i64)), nil
   148  	case reflect.Uint16:
   149  		if i64 < 0 || i64 > math.MaxUint16 {
   150  			return emptyValue, fmt.Errorf("%d overflows uint16", i64)
   151  		}
   152  
   153  		return reflect.ValueOf(uint16(i64)), nil
   154  	case reflect.Uint32:
   155  		if i64 < 0 || i64 > math.MaxUint32 {
   156  			return emptyValue, fmt.Errorf("%d overflows uint32", i64)
   157  		}
   158  
   159  		return reflect.ValueOf(uint32(i64)), nil
   160  	case reflect.Uint64:
   161  		if i64 < 0 {
   162  			return emptyValue, fmt.Errorf("%d overflows uint64", i64)
   163  		}
   164  
   165  		return reflect.ValueOf(uint64(i64)), nil
   166  	case reflect.Uint:
   167  		if i64 < 0 || int64(uint(i64)) != i64 { // Can we fit this inside of an uint
   168  			return emptyValue, fmt.Errorf("%d overflows uint", i64)
   169  		}
   170  
   171  		return reflect.ValueOf(uint(i64)), nil
   172  	default:
   173  		return emptyValue, ValueDecoderError{
   174  			Name:     "UintDecodeValue",
   175  			Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
   176  			Received: reflect.Zero(t),
   177  		}
   178  	}
   179  }
   180  
   181  // DecodeValue is the ValueDecoder for uint types.
   182  func (uic *UIntCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
   183  	if !val.CanSet() {
   184  		return ValueDecoderError{
   185  			Name:     "UintDecodeValue",
   186  			Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
   187  			Received: val,
   188  		}
   189  	}
   190  
   191  	elem, err := uic.decodeType(dc, vr, val.Type())
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	val.SetUint(elem.Uint())
   197  	return nil
   198  }
   199  

View as plain text