blob: c1590d07ae2f1f8ff6b004e5ac7d093d3b9d6ac3 [file] [log] [blame]
Joe Tsai88bc5a72018-11-05 11:42:22 -08001// 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 value
6
7import (
8 "reflect"
9
10 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
11)
12
13func MapOf(p interface{}, kc, kv Converter) pref.Map {
14 // TODO: Validate that p is a *map[K]V?
15 rv := reflect.ValueOf(p).Elem()
16 return mapReflect{rv, kc, kv}
17}
18
19type mapReflect struct {
20 v reflect.Value // addressable map[K]V
21 keyConv Converter
22 valConv Converter
23}
24
25func (ms mapReflect) Len() int {
26 return ms.v.Len()
27}
28func (ms mapReflect) Has(k pref.MapKey) bool {
29 rk := ms.keyConv.GoValueOf(k.Value())
30 rv := ms.v.MapIndex(rk)
31 return rv.IsValid()
32}
33func (ms mapReflect) Get(k pref.MapKey) pref.Value {
34 rk := ms.keyConv.GoValueOf(k.Value())
35 rv := ms.v.MapIndex(rk)
36 if !rv.IsValid() {
37 return pref.Value{}
38 }
39 return ms.valConv.PBValueOf(rv)
40}
41func (ms mapReflect) Set(k pref.MapKey, v pref.Value) {
42 if ms.v.IsNil() {
43 ms.v.Set(reflect.MakeMap(ms.v.Type()))
44 }
45 rk := ms.keyConv.GoValueOf(k.Value())
46 rv := ms.valConv.GoValueOf(v)
47 ms.v.SetMapIndex(rk, rv)
48}
49func (ms mapReflect) Clear(k pref.MapKey) {
50 rk := ms.keyConv.GoValueOf(k.Value())
51 ms.v.SetMapIndex(rk, reflect.Value{})
52}
53func (ms mapReflect) Mutable(k pref.MapKey) pref.Mutable {
54 // Mutable is only valid for messages and panics for other kinds.
55 if ms.v.IsNil() {
56 ms.v.Set(reflect.MakeMap(ms.v.Type()))
57 }
58 rk := ms.keyConv.GoValueOf(k.Value())
59 rv := ms.v.MapIndex(rk)
60 if !rv.IsValid() || rv.IsNil() {
61 // TODO: Is checking for nil proper behavior for custom messages?
62 pv := pref.ValueOf(ms.valConv.NewMessage())
63 rv = ms.valConv.GoValueOf(pv)
64 ms.v.SetMapIndex(rk, rv)
65 }
66 return rv.Interface().(pref.Message)
67}
68func (ms mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
69 for _, k := range ms.v.MapKeys() {
70 if v := ms.v.MapIndex(k); v.IsValid() {
71 pk := ms.keyConv.PBValueOf(k).MapKey()
72 pv := ms.valConv.PBValueOf(v)
73 if !f(pk, pv) {
74 return
75 }
76 }
77 }
78}
79func (ms mapReflect) Unwrap() interface{} {
80 return ms.v.Interface()
81}
82func (ms mapReflect) ProtoMutable() {}
83
84var (
85 _ pref.Map = mapReflect{}
86 _ Unwrapper = mapReflect{}
87)