blob: 85adcd227abb97ea16a1af2512ba3ad461fe83cb [file] [log] [blame]
Joe Tsaieeca8bb2018-12-04 16:24:22 -08001// Copyright 2012 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
5// +build purego
6
7package protoV1
8
9import (
10 "reflect"
11 "sync"
12
13 "github.com/golang/protobuf/protoapi"
14)
15
16// A field identifies a field in a struct, accessible from a pointer.
17// In this implementation, a field is identified by the sequence of field indices
18// passed to reflect's FieldByIndex.
19type field []int
20
21// toField returns a field equivalent to the given reflect field.
22func toField(f *reflect.StructField) field {
23 return f.Index
24}
25
26// invalidField is an invalid field identifier.
27var invalidField = field(nil)
28
29// zeroField is a noop when calling pointer.offset.
30var zeroField = field([]int{})
31
32// IsValid reports whether the field identifier is valid.
33func (f field) IsValid() bool { return f != nil }
34
35// The pointer type is for the table-driven decoder.
36// The implementation here uses a reflect.Value of pointer type to
37// create a generic pointer. In pointer_unsafe.go we use unsafe
38// instead of reflect to implement the same (but faster) interface.
39type pointer struct {
40 v reflect.Value
41}
42
43// toPointer converts an interface of pointer type to a pointer
44// that points to the same target.
45func toPointer(i *Message) pointer {
46 return pointer{v: reflect.ValueOf(*i)}
47}
48
49// valToPointer converts v to a pointer. v must be of pointer type.
50func valToPointer(v reflect.Value) pointer {
51 return pointer{v: v}
52}
53
54// offset converts from a pointer to a structure to a pointer to
55// one of its fields.
56func (p pointer) offset(f field) pointer {
57 return pointer{v: p.v.Elem().FieldByIndex(f).Addr()}
58}
59
60func (p pointer) isNil() bool {
61 return p.v.IsNil()
62}
63
64// grow updates the slice s in place to make it one element longer.
65// s must be addressable.
66// Returns the (addressable) new element.
67func grow(s reflect.Value) reflect.Value {
68 n, m := s.Len(), s.Cap()
69 if n < m {
70 s.SetLen(n + 1)
71 } else {
72 s.Set(reflect.Append(s, reflect.Zero(s.Type().Elem())))
73 }
74 return s.Index(n)
75}
76
77func (p pointer) toInt64() *int64 {
78 return p.v.Interface().(*int64)
79}
80func (p pointer) toInt64Ptr() **int64 {
81 return p.v.Interface().(**int64)
82}
83func (p pointer) toInt64Slice() *[]int64 {
84 return p.v.Interface().(*[]int64)
85}
86
87var int32ptr = reflect.TypeOf((*int32)(nil))
88
89func (p pointer) toInt32() *int32 {
90 return p.v.Convert(int32ptr).Interface().(*int32)
91}
92
93// The toInt32Ptr/Slice methods don't work because of enums.
94// Instead, we must use set/get methods for the int32ptr/slice case.
95/*
96 func (p pointer) toInt32Ptr() **int32 {
97 return p.v.Interface().(**int32)
98}
99 func (p pointer) toInt32Slice() *[]int32 {
100 return p.v.Interface().(*[]int32)
101}
102*/
103func (p pointer) setInt32Ptr(v int32) {
104 // Allocate value in a *int32. Possibly convert that to a *enum.
105 // Then assign it to a **int32 or **enum.
106 // Note: we can convert *int32 to *enum, but we can't convert
107 // **int32 to **enum!
108 p.v.Elem().Set(reflect.ValueOf(&v).Convert(p.v.Type().Elem()))
109}
110
111func (p pointer) appendInt32Slice(v int32) {
112 grow(p.v.Elem()).SetInt(int64(v))
113}
114
115func (p pointer) toUint64() *uint64 {
116 return p.v.Interface().(*uint64)
117}
118func (p pointer) toUint64Ptr() **uint64 {
119 return p.v.Interface().(**uint64)
120}
121func (p pointer) toUint64Slice() *[]uint64 {
122 return p.v.Interface().(*[]uint64)
123}
124func (p pointer) toUint32() *uint32 {
125 return p.v.Interface().(*uint32)
126}
127func (p pointer) toUint32Ptr() **uint32 {
128 return p.v.Interface().(**uint32)
129}
130func (p pointer) toUint32Slice() *[]uint32 {
131 return p.v.Interface().(*[]uint32)
132}
133func (p pointer) toBool() *bool {
134 return p.v.Interface().(*bool)
135}
136func (p pointer) toBoolPtr() **bool {
137 return p.v.Interface().(**bool)
138}
139func (p pointer) toBoolSlice() *[]bool {
140 return p.v.Interface().(*[]bool)
141}
142func (p pointer) toFloat64() *float64 {
143 return p.v.Interface().(*float64)
144}
145func (p pointer) toFloat64Ptr() **float64 {
146 return p.v.Interface().(**float64)
147}
148func (p pointer) toFloat64Slice() *[]float64 {
149 return p.v.Interface().(*[]float64)
150}
151func (p pointer) toFloat32() *float32 {
152 return p.v.Interface().(*float32)
153}
154func (p pointer) toFloat32Ptr() **float32 {
155 return p.v.Interface().(**float32)
156}
157func (p pointer) toFloat32Slice() *[]float32 {
158 return p.v.Interface().(*[]float32)
159}
160func (p pointer) toString() *string {
161 return p.v.Interface().(*string)
162}
163func (p pointer) toStringPtr() **string {
164 return p.v.Interface().(**string)
165}
166func (p pointer) toStringSlice() *[]string {
167 return p.v.Interface().(*[]string)
168}
169func (p pointer) toBytes() *[]byte {
170 return p.v.Interface().(*[]byte)
171}
172func (p pointer) toBytesSlice() *[][]byte {
173 return p.v.Interface().(*[][]byte)
174}
175func (p pointer) toExtensions() *protoapi.XXX_InternalExtensions {
176 return p.v.Interface().(*protoapi.XXX_InternalExtensions)
177}
178func (p pointer) toOldExtensions() *map[int32]protoapi.ExtensionField {
179 return p.v.Interface().(*map[int32]protoapi.ExtensionField)
180}
181func (p pointer) getPointer() pointer {
182 return pointer{v: p.v.Elem()}
183}
184func (p pointer) setPointer(q pointer) {
185 p.v.Elem().Set(q.v)
186}
187func (p pointer) appendPointer(q pointer) {
188 grow(p.v.Elem()).Set(q.v)
189}
190
191func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
192 // TODO: check that p.v.Type().Elem() == t?
193 return p.v
194}
195
196func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
197 atomicLock.Lock()
198 defer atomicLock.Unlock()
199 return *p
200}
201func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
202 atomicLock.Lock()
203 defer atomicLock.Unlock()
204 *p = v
205}
206
207var atomicLock sync.Mutex