github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/bson/bsoncodec/pointer_codec.go (about) 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 "reflect" 11 "sync" 12 13 "go.mongodb.org/mongo-driver/bson/bsonrw" 14 "go.mongodb.org/mongo-driver/bson/bsontype" 15 ) 16 17 var _ ValueEncoder = &PointerCodec{} 18 var _ ValueDecoder = &PointerCodec{} 19 20 // PointerCodec is the Codec used for pointers. 21 // 22 // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the 23 // PointerCodec registered. 24 type PointerCodec struct { 25 ecache map[reflect.Type]ValueEncoder 26 dcache map[reflect.Type]ValueDecoder 27 l sync.RWMutex 28 } 29 30 // NewPointerCodec returns a PointerCodec that has been initialized. 31 // 32 // Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with the 33 // PointerCodec registered. 34 func NewPointerCodec() *PointerCodec { 35 return &PointerCodec{ 36 ecache: make(map[reflect.Type]ValueEncoder), 37 dcache: make(map[reflect.Type]ValueDecoder), 38 } 39 } 40 41 // EncodeValue handles encoding a pointer by either encoding it to BSON Null if the pointer is nil 42 // or looking up an encoder for the type of value the pointer points to. 43 func (pc *PointerCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { 44 if val.Kind() != reflect.Ptr { 45 if !val.IsValid() { 46 return vw.WriteNull() 47 } 48 return ValueEncoderError{Name: "PointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} 49 } 50 51 if val.IsNil() { 52 return vw.WriteNull() 53 } 54 55 pc.l.RLock() 56 enc, ok := pc.ecache[val.Type()] 57 pc.l.RUnlock() 58 if ok { 59 if enc == nil { 60 return ErrNoEncoder{Type: val.Type()} 61 } 62 return enc.EncodeValue(ec, vw, val.Elem()) 63 } 64 65 enc, err := ec.LookupEncoder(val.Type().Elem()) 66 pc.l.Lock() 67 pc.ecache[val.Type()] = enc 68 pc.l.Unlock() 69 if err != nil { 70 return err 71 } 72 73 return enc.EncodeValue(ec, vw, val.Elem()) 74 } 75 76 // DecodeValue handles decoding a pointer by looking up a decoder for the type it points to and 77 // using that to decode. If the BSON value is Null, this method will set the pointer to nil. 78 func (pc *PointerCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { 79 if !val.CanSet() || val.Kind() != reflect.Ptr { 80 return ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} 81 } 82 83 if vr.Type() == bsontype.Null { 84 val.Set(reflect.Zero(val.Type())) 85 return vr.ReadNull() 86 } 87 if vr.Type() == bsontype.Undefined { 88 val.Set(reflect.Zero(val.Type())) 89 return vr.ReadUndefined() 90 } 91 92 if val.IsNil() { 93 val.Set(reflect.New(val.Type().Elem())) 94 } 95 96 pc.l.RLock() 97 dec, ok := pc.dcache[val.Type()] 98 pc.l.RUnlock() 99 if ok { 100 if dec == nil { 101 return ErrNoDecoder{Type: val.Type()} 102 } 103 return dec.DecodeValue(dc, vr, val.Elem()) 104 } 105 106 dec, err := dc.LookupDecoder(val.Type().Elem()) 107 pc.l.Lock() 108 pc.dcache[val.Type()] = dec 109 pc.l.Unlock() 110 if err != nil { 111 return err 112 } 113 114 return dec.DecodeValue(dc, vr, val.Elem()) 115 }