1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage impl 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "sync" 9*1c12ee1eSDan Willemsen "sync/atomic" 10*1c12ee1eSDan Willemsen 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/errors" 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 14*1c12ee1eSDan Willemsen) 15*1c12ee1eSDan Willemsen 16*1c12ee1eSDan Willemsentype extensionFieldInfo struct { 17*1c12ee1eSDan Willemsen wiretag uint64 18*1c12ee1eSDan Willemsen tagsize int 19*1c12ee1eSDan Willemsen unmarshalNeedsValue bool 20*1c12ee1eSDan Willemsen funcs valueCoderFuncs 21*1c12ee1eSDan Willemsen validation validationInfo 22*1c12ee1eSDan Willemsen} 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsenvar legacyExtensionFieldInfoCache sync.Map // map[protoreflect.ExtensionType]*extensionFieldInfo 25*1c12ee1eSDan Willemsen 26*1c12ee1eSDan Willemsenfunc getExtensionFieldInfo(xt protoreflect.ExtensionType) *extensionFieldInfo { 27*1c12ee1eSDan Willemsen if xi, ok := xt.(*ExtensionInfo); ok { 28*1c12ee1eSDan Willemsen xi.lazyInit() 29*1c12ee1eSDan Willemsen return xi.info 30*1c12ee1eSDan Willemsen } 31*1c12ee1eSDan Willemsen return legacyLoadExtensionFieldInfo(xt) 32*1c12ee1eSDan Willemsen} 33*1c12ee1eSDan Willemsen 34*1c12ee1eSDan Willemsen// legacyLoadExtensionFieldInfo dynamically loads a *ExtensionInfo for xt. 35*1c12ee1eSDan Willemsenfunc legacyLoadExtensionFieldInfo(xt protoreflect.ExtensionType) *extensionFieldInfo { 36*1c12ee1eSDan Willemsen if xi, ok := legacyExtensionFieldInfoCache.Load(xt); ok { 37*1c12ee1eSDan Willemsen return xi.(*extensionFieldInfo) 38*1c12ee1eSDan Willemsen } 39*1c12ee1eSDan Willemsen e := makeExtensionFieldInfo(xt.TypeDescriptor()) 40*1c12ee1eSDan Willemsen if e, ok := legacyMessageTypeCache.LoadOrStore(xt, e); ok { 41*1c12ee1eSDan Willemsen return e.(*extensionFieldInfo) 42*1c12ee1eSDan Willemsen } 43*1c12ee1eSDan Willemsen return e 44*1c12ee1eSDan Willemsen} 45*1c12ee1eSDan Willemsen 46*1c12ee1eSDan Willemsenfunc makeExtensionFieldInfo(xd protoreflect.ExtensionDescriptor) *extensionFieldInfo { 47*1c12ee1eSDan Willemsen var wiretag uint64 48*1c12ee1eSDan Willemsen if !xd.IsPacked() { 49*1c12ee1eSDan Willemsen wiretag = protowire.EncodeTag(xd.Number(), wireTypes[xd.Kind()]) 50*1c12ee1eSDan Willemsen } else { 51*1c12ee1eSDan Willemsen wiretag = protowire.EncodeTag(xd.Number(), protowire.BytesType) 52*1c12ee1eSDan Willemsen } 53*1c12ee1eSDan Willemsen e := &extensionFieldInfo{ 54*1c12ee1eSDan Willemsen wiretag: wiretag, 55*1c12ee1eSDan Willemsen tagsize: protowire.SizeVarint(wiretag), 56*1c12ee1eSDan Willemsen funcs: encoderFuncsForValue(xd), 57*1c12ee1eSDan Willemsen } 58*1c12ee1eSDan Willemsen // Does the unmarshal function need a value passed to it? 59*1c12ee1eSDan Willemsen // This is true for composite types, where we pass in a message, list, or map to fill in, 60*1c12ee1eSDan Willemsen // and for enums, where we pass in a prototype value to specify the concrete enum type. 61*1c12ee1eSDan Willemsen switch xd.Kind() { 62*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.EnumKind: 63*1c12ee1eSDan Willemsen e.unmarshalNeedsValue = true 64*1c12ee1eSDan Willemsen default: 65*1c12ee1eSDan Willemsen if xd.Cardinality() == protoreflect.Repeated { 66*1c12ee1eSDan Willemsen e.unmarshalNeedsValue = true 67*1c12ee1eSDan Willemsen } 68*1c12ee1eSDan Willemsen } 69*1c12ee1eSDan Willemsen return e 70*1c12ee1eSDan Willemsen} 71*1c12ee1eSDan Willemsen 72*1c12ee1eSDan Willemsentype lazyExtensionValue struct { 73*1c12ee1eSDan Willemsen atomicOnce uint32 // atomically set if value is valid 74*1c12ee1eSDan Willemsen mu sync.Mutex 75*1c12ee1eSDan Willemsen xi *extensionFieldInfo 76*1c12ee1eSDan Willemsen value protoreflect.Value 77*1c12ee1eSDan Willemsen b []byte 78*1c12ee1eSDan Willemsen fn func() protoreflect.Value 79*1c12ee1eSDan Willemsen} 80*1c12ee1eSDan Willemsen 81*1c12ee1eSDan Willemsentype ExtensionField struct { 82*1c12ee1eSDan Willemsen typ protoreflect.ExtensionType 83*1c12ee1eSDan Willemsen 84*1c12ee1eSDan Willemsen // value is either the value of GetValue, 85*1c12ee1eSDan Willemsen // or a *lazyExtensionValue that then returns the value of GetValue. 86*1c12ee1eSDan Willemsen value protoreflect.Value 87*1c12ee1eSDan Willemsen lazy *lazyExtensionValue 88*1c12ee1eSDan Willemsen} 89*1c12ee1eSDan Willemsen 90*1c12ee1eSDan Willemsenfunc (f *ExtensionField) appendLazyBytes(xt protoreflect.ExtensionType, xi *extensionFieldInfo, num protowire.Number, wtyp protowire.Type, b []byte) { 91*1c12ee1eSDan Willemsen if f.lazy == nil { 92*1c12ee1eSDan Willemsen f.lazy = &lazyExtensionValue{xi: xi} 93*1c12ee1eSDan Willemsen } 94*1c12ee1eSDan Willemsen f.typ = xt 95*1c12ee1eSDan Willemsen f.lazy.xi = xi 96*1c12ee1eSDan Willemsen f.lazy.b = protowire.AppendTag(f.lazy.b, num, wtyp) 97*1c12ee1eSDan Willemsen f.lazy.b = append(f.lazy.b, b...) 98*1c12ee1eSDan Willemsen} 99*1c12ee1eSDan Willemsen 100*1c12ee1eSDan Willemsenfunc (f *ExtensionField) canLazy(xt protoreflect.ExtensionType) bool { 101*1c12ee1eSDan Willemsen if f.typ == nil { 102*1c12ee1eSDan Willemsen return true 103*1c12ee1eSDan Willemsen } 104*1c12ee1eSDan Willemsen if f.typ == xt && f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0 { 105*1c12ee1eSDan Willemsen return true 106*1c12ee1eSDan Willemsen } 107*1c12ee1eSDan Willemsen return false 108*1c12ee1eSDan Willemsen} 109*1c12ee1eSDan Willemsen 110*1c12ee1eSDan Willemsenfunc (f *ExtensionField) lazyInit() { 111*1c12ee1eSDan Willemsen f.lazy.mu.Lock() 112*1c12ee1eSDan Willemsen defer f.lazy.mu.Unlock() 113*1c12ee1eSDan Willemsen if atomic.LoadUint32(&f.lazy.atomicOnce) == 1 { 114*1c12ee1eSDan Willemsen return 115*1c12ee1eSDan Willemsen } 116*1c12ee1eSDan Willemsen if f.lazy.xi != nil { 117*1c12ee1eSDan Willemsen b := f.lazy.b 118*1c12ee1eSDan Willemsen val := f.typ.New() 119*1c12ee1eSDan Willemsen for len(b) > 0 { 120*1c12ee1eSDan Willemsen var tag uint64 121*1c12ee1eSDan Willemsen if b[0] < 0x80 { 122*1c12ee1eSDan Willemsen tag = uint64(b[0]) 123*1c12ee1eSDan Willemsen b = b[1:] 124*1c12ee1eSDan Willemsen } else if len(b) >= 2 && b[1] < 128 { 125*1c12ee1eSDan Willemsen tag = uint64(b[0]&0x7f) + uint64(b[1])<<7 126*1c12ee1eSDan Willemsen b = b[2:] 127*1c12ee1eSDan Willemsen } else { 128*1c12ee1eSDan Willemsen var n int 129*1c12ee1eSDan Willemsen tag, n = protowire.ConsumeVarint(b) 130*1c12ee1eSDan Willemsen if n < 0 { 131*1c12ee1eSDan Willemsen panic(errors.New("bad tag in lazy extension decoding")) 132*1c12ee1eSDan Willemsen } 133*1c12ee1eSDan Willemsen b = b[n:] 134*1c12ee1eSDan Willemsen } 135*1c12ee1eSDan Willemsen num := protowire.Number(tag >> 3) 136*1c12ee1eSDan Willemsen wtyp := protowire.Type(tag & 7) 137*1c12ee1eSDan Willemsen var out unmarshalOutput 138*1c12ee1eSDan Willemsen var err error 139*1c12ee1eSDan Willemsen val, out, err = f.lazy.xi.funcs.unmarshal(b, val, num, wtyp, lazyUnmarshalOptions) 140*1c12ee1eSDan Willemsen if err != nil { 141*1c12ee1eSDan Willemsen panic(errors.New("decode failure in lazy extension decoding: %v", err)) 142*1c12ee1eSDan Willemsen } 143*1c12ee1eSDan Willemsen b = b[out.n:] 144*1c12ee1eSDan Willemsen } 145*1c12ee1eSDan Willemsen f.lazy.value = val 146*1c12ee1eSDan Willemsen } else { 147*1c12ee1eSDan Willemsen f.lazy.value = f.lazy.fn() 148*1c12ee1eSDan Willemsen } 149*1c12ee1eSDan Willemsen f.lazy.xi = nil 150*1c12ee1eSDan Willemsen f.lazy.fn = nil 151*1c12ee1eSDan Willemsen f.lazy.b = nil 152*1c12ee1eSDan Willemsen atomic.StoreUint32(&f.lazy.atomicOnce, 1) 153*1c12ee1eSDan Willemsen} 154*1c12ee1eSDan Willemsen 155*1c12ee1eSDan Willemsen// Set sets the type and value of the extension field. 156*1c12ee1eSDan Willemsen// This must not be called concurrently. 157*1c12ee1eSDan Willemsenfunc (f *ExtensionField) Set(t protoreflect.ExtensionType, v protoreflect.Value) { 158*1c12ee1eSDan Willemsen f.typ = t 159*1c12ee1eSDan Willemsen f.value = v 160*1c12ee1eSDan Willemsen f.lazy = nil 161*1c12ee1eSDan Willemsen} 162*1c12ee1eSDan Willemsen 163*1c12ee1eSDan Willemsen// SetLazy sets the type and a value that is to be lazily evaluated upon first use. 164*1c12ee1eSDan Willemsen// This must not be called concurrently. 165*1c12ee1eSDan Willemsenfunc (f *ExtensionField) SetLazy(t protoreflect.ExtensionType, fn func() protoreflect.Value) { 166*1c12ee1eSDan Willemsen f.typ = t 167*1c12ee1eSDan Willemsen f.lazy = &lazyExtensionValue{fn: fn} 168*1c12ee1eSDan Willemsen} 169*1c12ee1eSDan Willemsen 170*1c12ee1eSDan Willemsen// Value returns the value of the extension field. 171*1c12ee1eSDan Willemsen// This may be called concurrently. 172*1c12ee1eSDan Willemsenfunc (f *ExtensionField) Value() protoreflect.Value { 173*1c12ee1eSDan Willemsen if f.lazy != nil { 174*1c12ee1eSDan Willemsen if atomic.LoadUint32(&f.lazy.atomicOnce) == 0 { 175*1c12ee1eSDan Willemsen f.lazyInit() 176*1c12ee1eSDan Willemsen } 177*1c12ee1eSDan Willemsen return f.lazy.value 178*1c12ee1eSDan Willemsen } 179*1c12ee1eSDan Willemsen return f.value 180*1c12ee1eSDan Willemsen} 181*1c12ee1eSDan Willemsen 182*1c12ee1eSDan Willemsen// Type returns the type of the extension field. 183*1c12ee1eSDan Willemsen// This may be called concurrently. 184*1c12ee1eSDan Willemsenfunc (f ExtensionField) Type() protoreflect.ExtensionType { 185*1c12ee1eSDan Willemsen return f.typ 186*1c12ee1eSDan Willemsen} 187*1c12ee1eSDan Willemsen 188*1c12ee1eSDan Willemsen// IsSet returns whether the extension field is set. 189*1c12ee1eSDan Willemsen// This may be called concurrently. 190*1c12ee1eSDan Willemsenfunc (f ExtensionField) IsSet() bool { 191*1c12ee1eSDan Willemsen return f.typ != nil 192*1c12ee1eSDan Willemsen} 193*1c12ee1eSDan Willemsen 194*1c12ee1eSDan Willemsen// IsLazy reports whether a field is lazily encoded. 195*1c12ee1eSDan Willemsen// It is exported for testing. 196*1c12ee1eSDan Willemsenfunc IsLazy(m protoreflect.Message, fd protoreflect.FieldDescriptor) bool { 197*1c12ee1eSDan Willemsen var mi *MessageInfo 198*1c12ee1eSDan Willemsen var p pointer 199*1c12ee1eSDan Willemsen switch m := m.(type) { 200*1c12ee1eSDan Willemsen case *messageState: 201*1c12ee1eSDan Willemsen mi = m.messageInfo() 202*1c12ee1eSDan Willemsen p = m.pointer() 203*1c12ee1eSDan Willemsen case *messageReflectWrapper: 204*1c12ee1eSDan Willemsen mi = m.messageInfo() 205*1c12ee1eSDan Willemsen p = m.pointer() 206*1c12ee1eSDan Willemsen default: 207*1c12ee1eSDan Willemsen return false 208*1c12ee1eSDan Willemsen } 209*1c12ee1eSDan Willemsen xd, ok := fd.(protoreflect.ExtensionTypeDescriptor) 210*1c12ee1eSDan Willemsen if !ok { 211*1c12ee1eSDan Willemsen return false 212*1c12ee1eSDan Willemsen } 213*1c12ee1eSDan Willemsen xt := xd.Type() 214*1c12ee1eSDan Willemsen ext := mi.extensionMap(p) 215*1c12ee1eSDan Willemsen if ext == nil { 216*1c12ee1eSDan Willemsen return false 217*1c12ee1eSDan Willemsen } 218*1c12ee1eSDan Willemsen f, ok := (*ext)[int32(fd.Number())] 219*1c12ee1eSDan Willemsen if !ok { 220*1c12ee1eSDan Willemsen return false 221*1c12ee1eSDan Willemsen } 222*1c12ee1eSDan Willemsen return f.typ == xt && f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0 223*1c12ee1eSDan Willemsen} 224