blob: b22958144f8903957bae75fdb01646515c8bfb4e [file] [log] [blame]
Joe Tsai95b02902018-10-31 18:23:42 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package impl
6
7import (
8 "reflect"
9 "sync"
10 "unsafe"
11
12 protoV1 "github.com/golang/protobuf/proto"
13 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
14)
15
16// TODO: The logic below this is a hack since v1 currently exposes no
17// exported functionality for interacting with these data structures.
18// Eventually make changes to v1 such that v2 can access the necessary
19// fields without relying on unsafe.
20
21var (
22 extTypeA = reflect.TypeOf(map[int32]protoV1.Extension(nil))
23 extTypeB = reflect.TypeOf(protoV1.XXX_InternalExtensions{})
24)
25
26type legacyExtensionIface interface {
27 Len() int
28 Get(pref.FieldNumber) legacyExtensionEntry
29 Set(pref.FieldNumber, legacyExtensionEntry)
30 Range(f func(pref.FieldNumber, legacyExtensionEntry) bool)
31}
32
33func makeLegacyExtensionMapFunc(t reflect.Type) func(*messageDataType) legacyExtensionIface {
34 fx1, _ := t.FieldByName("XXX_extensions")
35 fx2, _ := t.FieldByName("XXX_InternalExtensions")
36 switch {
37 case fx1.Type == extTypeA:
38 return func(p *messageDataType) legacyExtensionIface {
39 rv := p.p.asType(t).Elem()
40 return (*legacyExtensionMap)(unsafe.Pointer(rv.UnsafeAddr() + fx1.Offset))
41 }
42 case fx2.Type == extTypeB:
43 return func(p *messageDataType) legacyExtensionIface {
44 rv := p.p.asType(t).Elem()
45 return (*legacyExtensionSyncMap)(unsafe.Pointer(rv.UnsafeAddr() + fx2.Offset))
46 }
47 default:
48 return nil
49 }
50}
51
52// legacyExtensionSyncMap is identical to protoV1.XXX_InternalExtensions.
53// It implements legacyExtensionIface.
54type legacyExtensionSyncMap struct {
55 p *struct {
56 mu sync.Mutex
57 m legacyExtensionMap
58 }
59}
60
61func (m legacyExtensionSyncMap) Len() int {
62 if m.p == nil {
63 return 0
64 }
65 m.p.mu.Lock()
66 defer m.p.mu.Unlock()
67 return m.p.m.Len()
68}
69func (m legacyExtensionSyncMap) Get(n pref.FieldNumber) legacyExtensionEntry {
70 if m.p == nil {
71 return legacyExtensionEntry{}
72 }
73 m.p.mu.Lock()
74 defer m.p.mu.Unlock()
75 return m.p.m.Get(n)
76}
77func (m *legacyExtensionSyncMap) Set(n pref.FieldNumber, x legacyExtensionEntry) {
78 if m.p == nil {
79 m.p = new(struct {
80 mu sync.Mutex
81 m legacyExtensionMap
82 })
83 }
84 m.p.mu.Lock()
85 defer m.p.mu.Unlock()
86 m.p.m.Set(n, x)
87}
88func (m legacyExtensionSyncMap) Range(f func(pref.FieldNumber, legacyExtensionEntry) bool) {
89 if m.p == nil {
90 return
91 }
92 m.p.mu.Lock()
93 defer m.p.mu.Unlock()
94 m.p.m.Range(f)
95}
96
97// legacyExtensionMap is identical to map[int32]protoV1.Extension.
98// It implements legacyExtensionIface.
99type legacyExtensionMap map[pref.FieldNumber]legacyExtensionEntry
100
101func (m legacyExtensionMap) Len() int {
102 return len(m)
103}
104func (m legacyExtensionMap) Get(n pref.FieldNumber) legacyExtensionEntry {
105 return m[n]
106}
107func (m *legacyExtensionMap) Set(n pref.FieldNumber, x legacyExtensionEntry) {
108 if *m == nil {
109 *m = make(map[pref.FieldNumber]legacyExtensionEntry)
110 }
111 (*m)[n] = x
112}
113func (m legacyExtensionMap) Range(f func(pref.FieldNumber, legacyExtensionEntry) bool) {
114 for n, x := range m {
115 if !f(n, x) {
116 return
117 }
118 }
119}
120
121// legacyExtensionEntry is identical to protoV1.Extension.
122type legacyExtensionEntry struct {
123 desc *protoV1.ExtensionDesc
124 val interface{}
125 raw []byte
126}