...

Source file src/go.mongodb.org/mongo-driver/bson/mgocompat/setter_getter.go

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

     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 mgocompat
     8  
     9  import (
    10  	"errors"
    11  	"reflect"
    12  
    13  	"go.mongodb.org/mongo-driver/bson"
    14  	"go.mongodb.org/mongo-driver/bson/bsoncodec"
    15  	"go.mongodb.org/mongo-driver/bson/bsonrw"
    16  )
    17  
    18  // Setter interface: a value implementing the bson.Setter interface will receive the BSON
    19  // value via the SetBSON method during unmarshaling, and the object
    20  // itself will not be changed as usual.
    21  //
    22  // If setting the value works, the method should return nil or alternatively
    23  // mgocompat.ErrSetZero to set the respective field to its zero value (nil for
    24  // pointer types). If SetBSON returns a non-nil error, the unmarshalling
    25  // procedure will stop and error out with the provided value.
    26  //
    27  // This interface is generally useful in pointer receivers, since the method
    28  // will want to change the receiver. A type field that implements the Setter
    29  // interface doesn't have to be a pointer, though.
    30  //
    31  // For example:
    32  //
    33  //	type MyString string
    34  //
    35  //	func (s *MyString) SetBSON(raw bson.RawValue) error {
    36  //	    return raw.Unmarshal(s)
    37  //	}
    38  type Setter interface {
    39  	SetBSON(raw bson.RawValue) error
    40  }
    41  
    42  // Getter interface: a value implementing the bson.Getter interface will have its GetBSON
    43  // method called when the given value has to be marshalled, and the result
    44  // of this method will be marshaled in place of the actual object.
    45  //
    46  // If GetBSON returns return a non-nil error, the marshalling procedure
    47  // will stop and error out with the provided value.
    48  type Getter interface {
    49  	GetBSON() (interface{}, error)
    50  }
    51  
    52  // SetterDecodeValue is the ValueDecoderFunc for Setter types.
    53  func SetterDecodeValue(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
    54  	if !val.IsValid() || (!val.Type().Implements(tSetter) && !reflect.PtrTo(val.Type()).Implements(tSetter)) {
    55  		return bsoncodec.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
    56  	}
    57  
    58  	if val.Kind() == reflect.Ptr && val.IsNil() {
    59  		if !val.CanSet() {
    60  			return bsoncodec.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
    61  		}
    62  		val.Set(reflect.New(val.Type().Elem()))
    63  	}
    64  
    65  	if !val.Type().Implements(tSetter) {
    66  		if !val.CanAddr() {
    67  			return bsoncodec.ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
    68  		}
    69  		val = val.Addr() // If the type doesn't implement the interface, a pointer to it must.
    70  	}
    71  
    72  	t, src, err := bsonrw.Copier{}.CopyValueToBytes(vr)
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	m, ok := val.Interface().(Setter)
    78  	if !ok {
    79  		return bsoncodec.ValueDecoderError{Name: "SetterDecodeValue", Types: []reflect.Type{tSetter}, Received: val}
    80  	}
    81  	if err := m.SetBSON(bson.RawValue{Type: t, Value: src}); err != nil {
    82  		if !errors.Is(err, ErrSetZero) {
    83  			return err
    84  		}
    85  		val.Set(reflect.Zero(val.Type()))
    86  	}
    87  	return nil
    88  }
    89  
    90  // GetterEncodeValue is the ValueEncoderFunc for Getter types.
    91  func GetterEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
    92  	// Either val or a pointer to val must implement Getter
    93  	switch {
    94  	case !val.IsValid():
    95  		return bsoncodec.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val}
    96  	case val.Type().Implements(tGetter):
    97  		// If Getter is implemented on a concrete type, make sure that val isn't a nil pointer
    98  		if isImplementationNil(val, tGetter) {
    99  			return vw.WriteNull()
   100  		}
   101  	case reflect.PtrTo(val.Type()).Implements(tGetter) && val.CanAddr():
   102  		val = val.Addr()
   103  	default:
   104  		return bsoncodec.ValueEncoderError{Name: "GetterEncodeValue", Types: []reflect.Type{tGetter}, Received: val}
   105  	}
   106  
   107  	m, ok := val.Interface().(Getter)
   108  	if !ok {
   109  		return vw.WriteNull()
   110  	}
   111  	x, err := m.GetBSON()
   112  	if err != nil {
   113  		return err
   114  	}
   115  	if x == nil {
   116  		return vw.WriteNull()
   117  	}
   118  	vv := reflect.ValueOf(x)
   119  	encoder, err := ec.Registry.LookupEncoder(vv.Type())
   120  	if err != nil {
   121  		return err
   122  	}
   123  	return encoder.EncodeValue(ec, vw, vv)
   124  }
   125  
   126  // isImplementationNil returns if val is a nil pointer and inter is implemented on a concrete type
   127  func isImplementationNil(val reflect.Value, inter reflect.Type) bool {
   128  	vt := val.Type()
   129  	for vt.Kind() == reflect.Ptr {
   130  		vt = vt.Elem()
   131  	}
   132  	return vt.Implements(inter) && val.Kind() == reflect.Ptr && val.IsNil()
   133  }
   134  

View as plain text