本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
2.8KB

  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. package bsoncodec
  7. import (
  8. "reflect"
  9. "sync"
  10. "go.mongodb.org/mongo-driver/bson/bsonrw"
  11. "go.mongodb.org/mongo-driver/bson/bsontype"
  12. )
  13. var defaultPointerCodec = &PointerCodec{
  14. ecache: make(map[reflect.Type]ValueEncoder),
  15. dcache: make(map[reflect.Type]ValueDecoder),
  16. }
  17. var _ ValueEncoder = &PointerCodec{}
  18. var _ ValueDecoder = &PointerCodec{}
  19. // PointerCodec is the Codec used for pointers.
  20. type PointerCodec struct {
  21. ecache map[reflect.Type]ValueEncoder
  22. dcache map[reflect.Type]ValueDecoder
  23. l sync.RWMutex
  24. }
  25. // NewPointerCodec returns a PointerCodec that has been initialized.
  26. func NewPointerCodec() *PointerCodec {
  27. return &PointerCodec{
  28. ecache: make(map[reflect.Type]ValueEncoder),
  29. dcache: make(map[reflect.Type]ValueDecoder),
  30. }
  31. }
  32. // EncodeValue handles encoding a pointer by either encoding it to BSON Null if the pointer is nil
  33. // or looking up an encoder for the type of value the pointer points to.
  34. func (pc *PointerCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
  35. if val.Kind() != reflect.Ptr {
  36. if !val.IsValid() {
  37. return vw.WriteNull()
  38. }
  39. return ValueEncoderError{Name: "PointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val}
  40. }
  41. if val.IsNil() {
  42. return vw.WriteNull()
  43. }
  44. pc.l.RLock()
  45. enc, ok := pc.ecache[val.Type()]
  46. pc.l.RUnlock()
  47. if ok {
  48. if enc == nil {
  49. return ErrNoEncoder{Type: val.Type()}
  50. }
  51. return enc.EncodeValue(ec, vw, val.Elem())
  52. }
  53. enc, err := ec.LookupEncoder(val.Type().Elem())
  54. pc.l.Lock()
  55. pc.ecache[val.Type()] = enc
  56. pc.l.Unlock()
  57. if err != nil {
  58. return err
  59. }
  60. return enc.EncodeValue(ec, vw, val.Elem())
  61. }
  62. // DecodeValue handles decoding a pointer by looking up a decoder for the type it points to and
  63. // using that to decode. If the BSON value is Null, this method will set the pointer to nil.
  64. func (pc *PointerCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
  65. if !val.CanSet() || val.Kind() != reflect.Ptr {
  66. return ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val}
  67. }
  68. if vr.Type() == bsontype.Null {
  69. val.Set(reflect.Zero(val.Type()))
  70. return vr.ReadNull()
  71. }
  72. if val.IsNil() {
  73. val.Set(reflect.New(val.Type().Elem()))
  74. }
  75. pc.l.RLock()
  76. dec, ok := pc.dcache[val.Type()]
  77. pc.l.RUnlock()
  78. if ok {
  79. if dec == nil {
  80. return ErrNoDecoder{Type: val.Type()}
  81. }
  82. return dec.DecodeValue(dc, vr, val.Elem())
  83. }
  84. dec, err := dc.LookupDecoder(val.Type().Elem())
  85. pc.l.Lock()
  86. pc.dcache[val.Type()] = dec
  87. pc.l.Unlock()
  88. if err != nil {
  89. return err
  90. }
  91. return dec.DecodeValue(dc, vr, val.Elem())
  92. }
上海开阖软件有限公司 沪ICP备12045867号-1