github.com/openconfig/goyang@v1.4.5/pkg/yang/yangtype.go (about) 1 // Copyright 2021 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 20 "github.com/google/go-cmp/cmp" 21 ) 22 23 var ( 24 // TypeKindFromName maps the string name used in a YANG file to the enumerated 25 // TypeKind used in this library. 26 TypeKindFromName = map[string]TypeKind{ 27 "none": Ynone, 28 "int8": Yint8, 29 "int16": Yint16, 30 "int32": Yint32, 31 "int64": Yint64, 32 "uint8": Yuint8, 33 "uint16": Yuint16, 34 "uint32": Yuint32, 35 "uint64": Yuint64, 36 "binary": Ybinary, 37 "bits": Ybits, 38 "boolean": Ybool, 39 "decimal64": Ydecimal64, 40 "empty": Yempty, 41 "enumeration": Yenum, 42 "identityref": Yidentityref, 43 "instance-identifier": YinstanceIdentifier, 44 "leafref": Yleafref, 45 "string": Ystring, 46 "union": Yunion, 47 } 48 49 // TypeKindToName maps the enumerated type used in this library to the string 50 // used in a YANG file. 51 TypeKindToName = map[TypeKind]string{ 52 Ynone: "none", 53 Yint8: "int8", 54 Yint16: "int16", 55 Yint32: "int32", 56 Yint64: "int64", 57 Yuint8: "uint8", 58 Yuint16: "uint16", 59 Yuint32: "uint32", 60 Yuint64: "uint64", 61 Ybinary: "binary", 62 Ybits: "bits", 63 Ybool: "boolean", 64 Ydecimal64: "decimal64", 65 Yempty: "empty", 66 Yenum: "enumeration", 67 Yidentityref: "identityref", 68 YinstanceIdentifier: "instance-identifier", 69 Yleafref: "leafref", 70 Ystring: "string", 71 Yunion: "union", 72 } 73 74 // BaseTypedefs is a map of all base types to the Typedef structure manufactured 75 // for the type. 76 BaseTypedefs = map[string]*Typedef{} 77 78 baseTypes = map[string]*YangType{ 79 "int8": { 80 Name: "int8", 81 Kind: Yint8, 82 Range: Int8Range, 83 }, 84 "int16": { 85 Name: "int16", 86 Kind: Yint16, 87 Range: Int16Range, 88 }, 89 "int32": { 90 Name: "int32", 91 Kind: Yint32, 92 Range: Int32Range, 93 }, 94 "int64": { 95 Name: "int64", 96 Kind: Yint64, 97 Range: Int64Range, 98 }, 99 "uint8": { 100 Name: "uint8", 101 Kind: Yuint8, 102 Range: Uint8Range, 103 }, 104 "uint16": { 105 Name: "uint16", 106 Kind: Yuint16, 107 Range: Uint16Range, 108 }, 109 "uint32": { 110 Name: "uint32", 111 Kind: Yuint32, 112 Range: Uint32Range, 113 }, 114 "uint64": { 115 Name: "uint64", 116 Kind: Yuint64, 117 Range: Uint64Range, 118 }, 119 120 "decimal64": { 121 Name: "decimal64", 122 Kind: Ydecimal64, 123 }, 124 "string": { 125 Name: "string", 126 Kind: Ystring, 127 }, 128 "boolean": { 129 Name: "boolean", 130 Kind: Ybool, 131 }, 132 "enumeration": { 133 Name: "enumeration", 134 Kind: Yenum, 135 }, 136 "bits": { 137 Name: "bits", 138 Kind: Ybits, 139 }, 140 "binary": { 141 Name: "binary", 142 Kind: Ybinary, 143 }, 144 "leafref": { 145 Name: "leafref", 146 Kind: Yleafref, 147 }, 148 "identityref": { 149 Name: "identityref", 150 Kind: Yidentityref, 151 }, 152 "empty": { 153 Name: "empty", 154 Kind: Yempty, 155 }, 156 "union": { 157 Name: "union", 158 Kind: Yunion, 159 }, 160 "instance-identifier": { 161 Name: "instance-identifier", 162 Kind: YinstanceIdentifier, 163 }, 164 } 165 ) 166 167 // Install builtin types as know types 168 func init() { 169 for k, v := range baseTypes { 170 // Base types are always their own root 171 v.Root = v 172 BaseTypedefs[k] = v.typedef() 173 } 174 } 175 176 // TypeKind is the enumeration of the base types available in YANG. It 177 // is analogous to reflect.Kind. 178 type TypeKind uint 179 180 func (k TypeKind) String() string { 181 if s := TypeKindToName[k]; s != "" { 182 return s 183 } 184 return fmt.Sprintf("unknown-type-%d", k) 185 } 186 187 const ( 188 // Ynone represents the invalid (unset) type. 189 Ynone = TypeKind(iota) 190 // Yint8 is an int in the range [-128, 127]. 191 Yint8 192 // Yint16 is an int in the range [-32768, 32767]. 193 Yint16 194 // Yint32 is an int in the range [-2147483648, 2147483647]. 195 Yint32 196 // Yint64 is an int in the range [-9223372036854775808, 9223372036854775807] 197 Yint64 198 // Yuint8 is an int in the range [0, 255] 199 Yuint8 200 // Yuint16 is an int in the range [0, 65535] 201 Yuint16 202 // Yuint32 is an int in the range [0, 4294967295] 203 Yuint32 204 // Yuint64 is an int in the range [0, 18446744073709551615] 205 Yuint64 206 207 // Ybinary stores arbitrary data. 208 Ybinary 209 // Ybits is a named set of bits or flags. 210 Ybits 211 // Ybool is true or false. 212 Ybool 213 // Ydecimal64 is a signed decimal number. 214 Ydecimal64 215 // Yempty has no associated value. 216 Yempty 217 // Yenum stores enumerated strings. 218 Yenum 219 // Yidentityref stores an extensible enumeration. 220 Yidentityref 221 // YinstanceIdentifier stores a reference to a data tree node. 222 YinstanceIdentifier 223 // Yleafref stores a reference to a leaf instance. 224 Yleafref 225 // Ystring is a human readable string. 226 Ystring 227 // Yunion is a choice of types. 228 Yunion 229 ) 230 231 // A YangType is the internal representation of a type in YANG. It may 232 // refer to either a builtin type or type specified with typedef. Not 233 // all fields in YangType are used for all types. 234 type YangType struct { 235 Name string 236 Kind TypeKind // Ynone if not a base type 237 Base *Type `json:"-"` // Base type for non-builtin types 238 IdentityBase *Identity `json:",omitempty"` // Base statement for a type using identityref 239 Root *YangType `json:"-"` // root of this type that is the same 240 Bit *EnumType `json:",omitempty"` // bit position, "status" is lost 241 Enum *EnumType `json:",omitempty"` // enum name to value, "status" is lost 242 Units string `json:",omitempty"` // units to be used for this type 243 Default string `json:",omitempty"` // default value, if any 244 HasDefault bool `json:",omitempty"` // whether the type has a default. 245 FractionDigits int `json:",omitempty"` // decimal64 fixed point precision 246 Length YangRange `json:",omitempty"` // this should be processed by section 12 247 OptionalInstance bool `json:",omitempty"` // !require-instances which defaults to true 248 Path string `json:",omitempty"` // the path in a leafref 249 Pattern []string `json:",omitempty"` // limiting XSD-TYPES expressions on strings 250 POSIXPattern []string `json:",omitempty"` // limiting POSIX ERE on strings (specified by openconfig-extensions:posix-pattern) 251 Range YangRange `json:",omitempty"` // range for integers 252 Type []*YangType `json:",omitempty"` // for unions 253 } 254 255 // Equal returns true if y and t describe the same type. 256 func (y *YangType) Equal(t *YangType) bool { 257 switch { 258 case y == t: 259 return true 260 case y == nil || t == nil: 261 return false 262 case 263 // Don't check the Name, it contains no information 264 y.Kind != t.Kind, 265 y.Units != t.Units, 266 y.Default != t.Default, 267 y.HasDefault != t.HasDefault, 268 y.FractionDigits != t.FractionDigits, 269 y.IdentityBase != t.IdentityBase, 270 len(y.Length) != len(t.Length), 271 !y.Length.Equal(t.Length), 272 y.OptionalInstance != t.OptionalInstance, 273 y.Path != t.Path, 274 !ssEqual(y.Pattern, t.Pattern), 275 !ssEqual(y.POSIXPattern, t.POSIXPattern), 276 len(y.Range) != len(t.Range), 277 !y.Range.Equal(t.Range), 278 !tsEqual(y.Type, t.Type), 279 !cmp.Equal(y.Enum, t.Enum, cmp.Comparer(func(t, u EnumType) bool { 280 return cmp.Equal(t.unique, u.unique) && cmp.Equal(t.ToInt, u.ToInt) && cmp.Equal(t.ToString, u.ToString) 281 })): 282 283 return false 284 } 285 // TODO(borman): Base, Bit 286 return true 287 } 288 289 // typedef returns a Typedef created from y for insertion into the BaseTypedefs 290 // map. 291 func (y *YangType) typedef() *Typedef { 292 return &Typedef{ 293 Name: y.Name, 294 Source: &Statement{}, 295 Type: &Type{ 296 Name: y.Name, 297 Source: &Statement{}, 298 YangType: y, 299 }, 300 YangType: y, 301 } 302 } 303 304 // ssEqual returns true if the two slices are equivalent. 305 func ssEqual(s1, s2 []string) bool { 306 if len(s1) != len(s2) { 307 return false 308 } 309 for x, s := range s1 { 310 if s != s2[x] { 311 return false 312 } 313 } 314 return true 315 } 316 317 // tsEqual returns true if the two Type slices are identical. 318 func tsEqual(t1, t2 []*YangType) bool { 319 if len(t1) != len(t2) { 320 return false 321 } 322 // For now we compare absolute pointers. 323 // This may be wrong. 324 for x, t := range t1 { 325 if !t.Equal(t2[x]) { 326 return false 327 } 328 } 329 return true 330 }