|  | // Copyright 2024 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package impl | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "reflect" | 
|  |  | 
|  | "google.golang.org/protobuf/encoding/protowire" | 
|  | "google.golang.org/protobuf/internal/errors" | 
|  | "google.golang.org/protobuf/reflect/protoreflect" | 
|  | ) | 
|  |  | 
|  | func makeOpaqueMessageFieldCoder(fd protoreflect.FieldDescriptor, ft reflect.Type) (*MessageInfo, pointerCoderFuncs) { | 
|  | mi := getMessageInfo(ft) | 
|  | if mi == nil { | 
|  | panic(fmt.Sprintf("invalid field: %v: unsupported message type %v", fd.FullName(), ft)) | 
|  | } | 
|  | switch fd.Kind() { | 
|  | case protoreflect.MessageKind: | 
|  | return mi, pointerCoderFuncs{ | 
|  | size:      sizeOpaqueMessage, | 
|  | marshal:   appendOpaqueMessage, | 
|  | unmarshal: consumeOpaqueMessage, | 
|  | isInit:    isInitOpaqueMessage, | 
|  | merge:     mergeOpaqueMessage, | 
|  | } | 
|  | case protoreflect.GroupKind: | 
|  | return mi, pointerCoderFuncs{ | 
|  | size:      sizeOpaqueGroup, | 
|  | marshal:   appendOpaqueGroup, | 
|  | unmarshal: consumeOpaqueGroup, | 
|  | isInit:    isInitOpaqueMessage, | 
|  | merge:     mergeOpaqueMessage, | 
|  | } | 
|  | } | 
|  | panic("unexpected field kind") | 
|  | } | 
|  |  | 
|  | func sizeOpaqueMessage(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) { | 
|  | return protowire.SizeBytes(f.mi.sizePointer(p.AtomicGetPointer(), opts)) + f.tagsize | 
|  | } | 
|  |  | 
|  | func appendOpaqueMessage(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) { | 
|  | mp := p.AtomicGetPointer() | 
|  | calculatedSize := f.mi.sizePointer(mp, opts) | 
|  | b = protowire.AppendVarint(b, f.wiretag) | 
|  | b = protowire.AppendVarint(b, uint64(calculatedSize)) | 
|  | before := len(b) | 
|  | b, err := f.mi.marshalAppendPointer(b, mp, opts) | 
|  | if measuredSize := len(b) - before; calculatedSize != measuredSize && err == nil { | 
|  | return nil, errors.MismatchedSizeCalculation(calculatedSize, measuredSize) | 
|  | } | 
|  | return b, err | 
|  | } | 
|  |  | 
|  | func consumeOpaqueMessage(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { | 
|  | if wtyp != protowire.BytesType { | 
|  | return out, errUnknown | 
|  | } | 
|  | v, n := protowire.ConsumeBytes(b) | 
|  | if n < 0 { | 
|  | return out, errDecode | 
|  | } | 
|  | mp := p.AtomicGetPointer() | 
|  | if mp.IsNil() { | 
|  | mp = p.AtomicSetPointerIfNil(pointerOfValue(reflect.New(f.mi.GoReflectType.Elem()))) | 
|  | } | 
|  | o, err := f.mi.unmarshalPointer(v, mp, 0, opts) | 
|  | if err != nil { | 
|  | return out, err | 
|  | } | 
|  | out.n = n | 
|  | out.initialized = o.initialized | 
|  | return out, nil | 
|  | } | 
|  |  | 
|  | func isInitOpaqueMessage(p pointer, f *coderFieldInfo) error { | 
|  | mp := p.AtomicGetPointer() | 
|  | if mp.IsNil() { | 
|  | return nil | 
|  | } | 
|  | return f.mi.checkInitializedPointer(mp) | 
|  | } | 
|  |  | 
|  | func mergeOpaqueMessage(dst, src pointer, f *coderFieldInfo, opts mergeOptions) { | 
|  | dstmp := dst.AtomicGetPointer() | 
|  | if dstmp.IsNil() { | 
|  | dstmp = dst.AtomicSetPointerIfNil(pointerOfValue(reflect.New(f.mi.GoReflectType.Elem()))) | 
|  | } | 
|  | f.mi.mergePointer(dstmp, src.AtomicGetPointer(), opts) | 
|  | } | 
|  |  | 
|  | func sizeOpaqueGroup(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) { | 
|  | return 2*f.tagsize + f.mi.sizePointer(p.AtomicGetPointer(), opts) | 
|  | } | 
|  |  | 
|  | func appendOpaqueGroup(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) { | 
|  | b = protowire.AppendVarint(b, f.wiretag) // start group | 
|  | b, err := f.mi.marshalAppendPointer(b, p.AtomicGetPointer(), opts) | 
|  | b = protowire.AppendVarint(b, f.wiretag+1) // end group | 
|  | return b, err | 
|  | } | 
|  |  | 
|  | func consumeOpaqueGroup(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { | 
|  | if wtyp != protowire.StartGroupType { | 
|  | return out, errUnknown | 
|  | } | 
|  | mp := p.AtomicGetPointer() | 
|  | if mp.IsNil() { | 
|  | mp = p.AtomicSetPointerIfNil(pointerOfValue(reflect.New(f.mi.GoReflectType.Elem()))) | 
|  | } | 
|  | o, e := f.mi.unmarshalPointer(b, mp, f.num, opts) | 
|  | return o, e | 
|  | } | 
|  |  | 
|  | func makeOpaqueRepeatedMessageFieldCoder(fd protoreflect.FieldDescriptor, ft reflect.Type) (*MessageInfo, pointerCoderFuncs) { | 
|  | if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice { | 
|  | panic(fmt.Sprintf("invalid field: %v: unsupported type for opaque repeated message: %v", fd.FullName(), ft)) | 
|  | } | 
|  | mt := ft.Elem().Elem() // *[]*T -> *T | 
|  | mi := getMessageInfo(mt) | 
|  | if mi == nil { | 
|  | panic(fmt.Sprintf("invalid field: %v: unsupported message type %v", fd.FullName(), mt)) | 
|  | } | 
|  | switch fd.Kind() { | 
|  | case protoreflect.MessageKind: | 
|  | return mi, pointerCoderFuncs{ | 
|  | size:      sizeOpaqueMessageSlice, | 
|  | marshal:   appendOpaqueMessageSlice, | 
|  | unmarshal: consumeOpaqueMessageSlice, | 
|  | isInit:    isInitOpaqueMessageSlice, | 
|  | merge:     mergeOpaqueMessageSlice, | 
|  | } | 
|  | case protoreflect.GroupKind: | 
|  | return mi, pointerCoderFuncs{ | 
|  | size:      sizeOpaqueGroupSlice, | 
|  | marshal:   appendOpaqueGroupSlice, | 
|  | unmarshal: consumeOpaqueGroupSlice, | 
|  | isInit:    isInitOpaqueMessageSlice, | 
|  | merge:     mergeOpaqueMessageSlice, | 
|  | } | 
|  | } | 
|  | panic("unexpected field kind") | 
|  | } | 
|  |  | 
|  | func sizeOpaqueMessageSlice(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) { | 
|  | s := p.AtomicGetPointer().PointerSlice() | 
|  | n := 0 | 
|  | for _, v := range s { | 
|  | n += protowire.SizeBytes(f.mi.sizePointer(v, opts)) + f.tagsize | 
|  | } | 
|  | return n | 
|  | } | 
|  |  | 
|  | func appendOpaqueMessageSlice(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) { | 
|  | s := p.AtomicGetPointer().PointerSlice() | 
|  | var err error | 
|  | for _, v := range s { | 
|  | b = protowire.AppendVarint(b, f.wiretag) | 
|  | siz := f.mi.sizePointer(v, opts) | 
|  | b = protowire.AppendVarint(b, uint64(siz)) | 
|  | before := len(b) | 
|  | b, err = f.mi.marshalAppendPointer(b, v, opts) | 
|  | if err != nil { | 
|  | return b, err | 
|  | } | 
|  | if measuredSize := len(b) - before; siz != measuredSize { | 
|  | return nil, errors.MismatchedSizeCalculation(siz, measuredSize) | 
|  | } | 
|  | } | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | func consumeOpaqueMessageSlice(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { | 
|  | if wtyp != protowire.BytesType { | 
|  | return out, errUnknown | 
|  | } | 
|  | v, n := protowire.ConsumeBytes(b) | 
|  | if n < 0 { | 
|  | return out, errDecode | 
|  | } | 
|  | mp := pointerOfValue(reflect.New(f.mi.GoReflectType.Elem())) | 
|  | o, err := f.mi.unmarshalPointer(v, mp, 0, opts) | 
|  | if err != nil { | 
|  | return out, err | 
|  | } | 
|  | sp := p.AtomicGetPointer() | 
|  | if sp.IsNil() { | 
|  | sp = p.AtomicSetPointerIfNil(pointerOfValue(reflect.New(f.ft.Elem()))) | 
|  | } | 
|  | sp.AppendPointerSlice(mp) | 
|  | out.n = n | 
|  | out.initialized = o.initialized | 
|  | return out, nil | 
|  | } | 
|  |  | 
|  | func isInitOpaqueMessageSlice(p pointer, f *coderFieldInfo) error { | 
|  | sp := p.AtomicGetPointer() | 
|  | if sp.IsNil() { | 
|  | return nil | 
|  | } | 
|  | s := sp.PointerSlice() | 
|  | for _, v := range s { | 
|  | if err := f.mi.checkInitializedPointer(v); err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func mergeOpaqueMessageSlice(dst, src pointer, f *coderFieldInfo, opts mergeOptions) { | 
|  | ds := dst.AtomicGetPointer() | 
|  | if ds.IsNil() { | 
|  | ds = dst.AtomicSetPointerIfNil(pointerOfValue(reflect.New(f.ft.Elem()))) | 
|  | } | 
|  | for _, sp := range src.AtomicGetPointer().PointerSlice() { | 
|  | dm := pointerOfValue(reflect.New(f.mi.GoReflectType.Elem())) | 
|  | f.mi.mergePointer(dm, sp, opts) | 
|  | ds.AppendPointerSlice(dm) | 
|  | } | 
|  | } | 
|  |  | 
|  | func sizeOpaqueGroupSlice(p pointer, f *coderFieldInfo, opts marshalOptions) (size int) { | 
|  | s := p.AtomicGetPointer().PointerSlice() | 
|  | n := 0 | 
|  | for _, v := range s { | 
|  | n += 2*f.tagsize + f.mi.sizePointer(v, opts) | 
|  | } | 
|  | return n | 
|  | } | 
|  |  | 
|  | func appendOpaqueGroupSlice(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) { | 
|  | s := p.AtomicGetPointer().PointerSlice() | 
|  | var err error | 
|  | for _, v := range s { | 
|  | b = protowire.AppendVarint(b, f.wiretag) // start group | 
|  | b, err = f.mi.marshalAppendPointer(b, v, opts) | 
|  | if err != nil { | 
|  | return b, err | 
|  | } | 
|  | b = protowire.AppendVarint(b, f.wiretag+1) // end group | 
|  | } | 
|  | return b, nil | 
|  | } | 
|  |  | 
|  | func consumeOpaqueGroupSlice(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { | 
|  | if wtyp != protowire.StartGroupType { | 
|  | return out, errUnknown | 
|  | } | 
|  | mp := pointerOfValue(reflect.New(f.mi.GoReflectType.Elem())) | 
|  | out, err = f.mi.unmarshalPointer(b, mp, f.num, opts) | 
|  | if err != nil { | 
|  | return out, err | 
|  | } | 
|  | sp := p.AtomicGetPointer() | 
|  | if sp.IsNil() { | 
|  | sp = p.AtomicSetPointerIfNil(pointerOfValue(reflect.New(f.ft.Elem()))) | 
|  | } | 
|  | sp.AppendPointerSlice(mp) | 
|  | return out, err | 
|  | } |