-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcomposite_generic_map.go
More file actions
124 lines (110 loc) · 3.68 KB
/
composite_generic_map.go
File metadata and controls
124 lines (110 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package protopath
import (
"strconv"
"github.com/daishe/protoreflectextra"
"google.golang.org/protobuf/reflect/protoreflect"
)
// mapKey parses the provided name as map key. It returns invalid map key if the provided name cannot be parsed.
func mapKey(keyType protoreflect.FieldDescriptor, name string) protoreflect.MapKey {
k := protoreflect.MapKey{}
switch keyType.Kind() {
case protoreflect.BoolKind:
if v, err := strconv.ParseBool(name); err == nil {
k = protoreflect.ValueOfBool(v).MapKey()
}
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
if v, err := strconv.ParseInt(name, 0, 32); err == nil {
k = protoreflect.ValueOfInt32(int32(v)).MapKey()
}
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
if v, err := strconv.ParseInt(name, 0, 64); err == nil {
k = protoreflect.ValueOfInt64(v).MapKey()
}
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
if v, err := strconv.ParseUint(name, 0, 32); err == nil {
k = protoreflect.ValueOfUint32(uint32(v)).MapKey()
}
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
if v, err := strconv.ParseUint(name, 0, 64); err == nil {
k = protoreflect.ValueOfUint64(v).MapKey()
}
case protoreflect.StringKind:
k = protoreflect.ValueOfString(name).MapKey()
}
return k
}
// mapKeyInMap parses the provided name as map key. It returns invalid map key if the provided name cannot be parsed or was not found in map.
func mapKeyInMap(m protoreflectextra.Map, keyType protoreflect.FieldDescriptor, name string) protoreflect.MapKey {
if !m.IsMutable() {
return protoreflect.MapKey{}
}
k := mapKey(keyType, name)
if !k.IsValid() || !m.Has(k) {
return protoreflect.MapKey{}
}
return k
}
func mapKeyInMapOrError(ma protoreflectextra.Map, name string) (protoreflect.MapKey, error) {
if !ma.IsMutable() {
return protoreflect.MapKey{}, &ErrNotFound{Kind: "key", Value: name}
}
k := mapKeyInMap(ma, ma.Descriptor().MapKey(), name)
if !k.IsValid() {
return protoreflect.MapKey{}, &ErrNotFound{Kind: "key", Value: name}
}
return k, nil
}
func interfaceOfMapItem(field protoreflect.FieldDescriptor, value protoreflect.Value) any {
if field.Kind() == protoreflect.EnumKind {
return protoreflectextra.NewEnum(field.Enum(), value.Enum())
}
return value.Interface()
}
type genericMapComposite struct {
Map protoreflectextra.Map
}
func newGenericMapComposite(ma protoreflectextra.Map) genericMapComposite {
return genericMapComposite{Map: ma}
}
func (c genericMapComposite) IsReadOnly() bool {
return !c.Map.IsMutable()
}
func (c genericMapComposite) Self() any {
return c.Map
}
func (c genericMapComposite) Get(s Segment) (any, error) {
mk, err := mapKeyInMapOrError(c.Map, s.Value())
if err != nil {
return nil, err
}
return interfaceOfMapItem(c.Map.Descriptor().MapValue(), c.Map.Get(mk)), nil
}
func (c genericMapComposite) Mutable(s Segment) (any, error) {
if !c.Map.IsMutable() {
return nil, ErrMutationOfReadOnlyValue
}
return c.Get(s)
}
func (c genericMapComposite) Access(s Segment) (any, error) {
mk, err := mapKeyInMapOrError(c.Map, s.Value())
if err != nil {
return nil, err
}
if c.Map.Descriptor().MapValue().Kind() != protoreflect.MessageKind {
return nil, newErrInSegment(s, ErrAccessToNonCompositeType)
}
return c.Map.Get(mk).Message(), nil
}
func (c genericMapComposite) AccessMutable(s Segment) (any, error) {
if !c.Map.IsMutable() {
return nil, ErrMutationOfReadOnlyValue
}
mk, err := mapKeyInMapOrError(c.Map, s.Value())
if err != nil {
return nil, err
}
if c.Map.Descriptor().MapValue().Kind() != protoreflect.MessageKind {
return nil, newErrInSegment(s, ErrAccessToNonCompositeType)
}
return c.Map.Get(mk).Message(), nil
}