github.com/psiphon-labs/goarista@v0.0.0-20160825065156-d002785f4c67/key/key.go (about) 1 // Copyright (C) 2015 Arista Networks, Inc. 2 // Use of this source code is governed by the Apache License 2.0 3 // that can be found in the COPYING file. 4 5 package key 6 7 import ( 8 "encoding/json" 9 "fmt" 10 11 "github.com/aristanetworks/goarista/value" 12 ) 13 14 // Key represents the Key in the updates and deletes of the Notification 15 // objects. The only reason this exists is that Go won't let us define 16 // our own hash function for non-hashable types, and unfortunately we 17 // need to be able to index maps by map[string]interface{} objects. 18 type Key interface { 19 Key() interface{} 20 String() string 21 Equal(other interface{}) bool 22 23 // Helper methods to manipulate maps keyed by `Key'. 24 25 // GetFromMap returns the value for the entry of this Key. 26 GetFromMap(map[Key]interface{}) (interface{}, bool) 27 // DeleteFromMap deletes the entry in the map for this Key. 28 // This is a no-op if the key does not exist in the map. 29 DeleteFromMap(map[Key]interface{}) 30 // SetToMap updates or inserts an entry in the map for this Key. 31 SetToMap(m map[Key]interface{}, value interface{}) 32 } 33 34 type keyImpl struct { 35 key interface{} 36 } 37 38 // New wraps the given value in a Key. 39 // This function panics if the value passed in isn't allowed in a Key or 40 // doesn't implement value.Value. 41 func New(intf interface{}) Key { 42 switch t := intf.(type) { 43 case map[string]interface{}: 44 return composite{sentinel, t} 45 case int8, int16, int32, int64, 46 uint8, uint16, uint32, uint64, 47 float32, float64, string, bool, 48 value.Value: 49 return keyImpl{key: intf} 50 default: 51 panic(fmt.Sprintf("Invalid type for key: %T", intf)) 52 } 53 } 54 55 func (k keyImpl) Key() interface{} { 56 return k.key 57 } 58 59 func (k keyImpl) String() string { 60 return stringify(k.key) 61 } 62 63 func (k keyImpl) GetFromMap(m map[Key]interface{}) (interface{}, bool) { 64 v, ok := m[k] 65 return v, ok 66 } 67 68 func (k keyImpl) DeleteFromMap(m map[Key]interface{}) { 69 delete(m, k) 70 } 71 72 func (k keyImpl) SetToMap(m map[Key]interface{}, value interface{}) { 73 m[k] = value 74 } 75 76 func (k keyImpl) GoString() string { 77 return fmt.Sprintf("key.New(%#v)", k.Key()) 78 } 79 80 func (k keyImpl) MarshalJSON() ([]byte, error) { 81 return json.Marshal(k.Key()) 82 } 83 84 func (k keyImpl) Equal(other interface{}) bool { 85 o, ok := other.(Key) 86 if !ok { 87 return false 88 } 89 return keyEqual(k.key, o.Key()) 90 } 91 92 // Comparable types have an equality-testing method. 93 type Comparable interface { 94 // Equal returns true if this object is equal to the other one. 95 Equal(other interface{}) bool 96 } 97 98 func keyEqual(a, b interface{}) bool { 99 switch a := a.(type) { 100 case map[string]interface{}: 101 b, ok := b.(map[string]interface{}) 102 if !ok || len(a) != len(b) { 103 return false 104 } 105 for k, av := range a { 106 if bv, ok := b[k]; !ok || !keyEqual(av, bv) { 107 return false 108 } 109 } 110 return true 111 case map[Key]interface{}: 112 b, ok := b.(map[Key]interface{}) 113 if !ok || len(a) != len(b) { 114 return false 115 } 116 for k, av := range a { 117 if bv, ok := k.GetFromMap(b); !ok || !keyEqual(av, bv) { 118 return false 119 } 120 } 121 return true 122 case Comparable: 123 return a.Equal(b) 124 } 125 126 return a == b 127 }