github.com/openconfig/goyang@v1.4.5/pkg/yang/identity.go (about) 1 // Copyright 2016 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package yang 16 17 import ( 18 "fmt" 19 "sort" 20 "sync" 21 ) 22 23 // This file implements data structures and functions that relate to the 24 // identity type. 25 26 // identityDictionary stores a set of identities across all parsed Modules that 27 // have been resolved to be identified by their module and name. 28 type identityDictionary struct { 29 mu sync.Mutex 30 // dict is a global cache of identities keyed by 31 // modulename:identityname, where modulename is the full name of the 32 // module to which the identity belongs. If the identity were defined 33 // in a submodule, then the parent module name is used instead. 34 dict map[string]resolvedIdentity 35 } 36 37 // resolvedIdentity is an Identity that has been disambiguated. 38 type resolvedIdentity struct { 39 Module *Module 40 Identity *Identity 41 } 42 43 // isEmpty determines whether the resolvedIdentity struct value is populated. 44 func (r resolvedIdentity) isEmpty() bool { 45 return r.Module == nil && r.Identity == nil 46 } 47 48 // newResolvedIdentity creates a resolved identity from an identity and its 49 // associated module, and returns the prefixed name (Prefix:IdentityName) 50 // along with the resolved identity. 51 func newResolvedIdentity(m *Module, i *Identity) (string, *resolvedIdentity) { 52 r := &resolvedIdentity{ 53 Module: m, 54 Identity: i, 55 } 56 return i.modulePrefixedName(), r 57 } 58 59 func appendIfNotIn(ids []*Identity, chk *Identity) []*Identity { 60 for _, id := range ids { 61 if id == chk { 62 return ids 63 } 64 } 65 return append(ids, chk) 66 } 67 68 // addChildren adds identity r and all of its children to ids 69 // deterministically. 70 func addChildren(r *Identity, ids []*Identity) []*Identity { 71 ids = appendIfNotIn(ids, r) 72 73 // Iterate through the values of r. 74 for _, ch := range r.Values { 75 ids = addChildren(ch, ids) 76 } 77 return ids 78 } 79 80 // findIdentityBase returns the resolved identity that is corresponds to the 81 // baseStr string in the context of the module/submodule mod. 82 func (mod *Module) findIdentityBase(baseStr string) (*resolvedIdentity, []error) { 83 var base resolvedIdentity 84 var ok bool 85 var errs []error 86 87 basePrefix, baseName := getPrefix(baseStr) 88 rootPrefix := mod.GetPrefix() 89 source := Source(mod) 90 typeDict := mod.Modules.typeDict 91 92 switch basePrefix { 93 case "", rootPrefix: 94 // This is a local identity which is defined within the current 95 // module 96 keyName := fmt.Sprintf("%s:%s", module(mod).Name, baseName) 97 base, ok = typeDict.identities.dict[keyName] 98 if !ok { 99 errs = append(errs, fmt.Errorf("%s: can't resolve the local base %s as %s", source, baseStr, keyName)) 100 } 101 default: 102 // This is an identity which is defined within another module 103 extmod := FindModuleByPrefix(mod, basePrefix) 104 if extmod == nil { 105 errs = append(errs, 106 fmt.Errorf("%s: can't find external module with prefix %s", source, basePrefix)) 107 break 108 } 109 // The identity we are looking for is modulename:basename. 110 if id, ok := typeDict.identities.dict[fmt.Sprintf("%s:%s", module(extmod).Name, baseName)]; ok { 111 base = id 112 break 113 } 114 115 // Error if we did not find the identity that had the name specified in 116 // the module it was expected to be in. 117 if base.isEmpty() { 118 errs = append(errs, fmt.Errorf("%s: can't resolve remote base %s", source, baseStr)) 119 } 120 } 121 return &base, errs 122 } 123 124 func (ms *Modules) resolveIdentities() []error { 125 defer ms.typeDict.identities.mu.Unlock() 126 ms.typeDict.identities.mu.Lock() 127 128 var errs []error 129 130 // Across all modules, read the identity values that have been extracted 131 // from them, and compile them into a "fully resolved" map that means that 132 // we can look them up based on the 'real' prefix of the module and the 133 // name of the identity. 134 for _, mod := range ms.Modules { 135 for _, i := range mod.Identities() { 136 keyName, r := newResolvedIdentity(mod, i) 137 ms.typeDict.identities.dict[keyName] = *r 138 } 139 140 // Hoist up all identities in our included submodules. 141 // We could just do a range on ms.SubModules, but that 142 // might process a submodule that no module included. 143 for _, in := range mod.Include { 144 if in.Module == nil { 145 continue 146 } 147 for _, i := range in.Module.Identities() { 148 keyName, r := newResolvedIdentity(in.Module, i) 149 ms.typeDict.identities.dict[keyName] = *r 150 } 151 } 152 } 153 154 // Determine which identities have a base statement, and link this to a 155 // fully resolved identity statement. The intention here is to make sure 156 // that the Children slice is fully populated with pointers to all identities 157 // that have a base, so that we can do inheritance of these later. 158 for _, i := range ms.typeDict.identities.dict { 159 if i.Identity.Base != nil { 160 // This identity inherits from one or more other identities. 161 162 root := RootNode(i.Identity) 163 for _, b := range i.Identity.Base { 164 base, baseErr := root.findIdentityBase(b.asString()) 165 166 if baseErr != nil { 167 errs = append(errs, baseErr...) 168 continue 169 } 170 171 // Build up a list of direct children of this identity. 172 base.Identity.Values = append(base.Identity.Values, i.Identity) 173 } 174 } 175 } 176 177 // Do a final sweep through the identities to build up their children. 178 for _, i := range ms.typeDict.identities.dict { 179 newValues := []*Identity{} 180 for _, j := range i.Identity.Values { 181 newValues = addChildren(j, newValues) 182 } 183 sort.SliceStable(newValues, func(j, k int) bool { 184 return newValues[j].Name < newValues[k].Name 185 }) 186 i.Identity.Values = newValues 187 } 188 189 return errs 190 }