github.com/openconfig/goyang@v1.4.5/pkg/yang/types_builtin.go (about) 1 // Copyright 2015 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 // This module contains all the builtin types as well as types related 18 // to types (such as ranges, enums, etc). 19 20 import ( 21 "errors" 22 "fmt" 23 "math" 24 "sort" 25 "strconv" 26 "strings" 27 ) 28 29 // This file handles interpretation of types 30 31 // These are the default ranges defined by the YANG standard. 32 var ( 33 Int8Range = mustParseRangesInt("-128..127") 34 Int16Range = mustParseRangesInt("-32768..32767") 35 Int32Range = mustParseRangesInt("-2147483648..2147483647") 36 Int64Range = mustParseRangesInt("-9223372036854775808..9223372036854775807") 37 38 Uint8Range = mustParseRangesInt("0..255") 39 Uint16Range = mustParseRangesInt("0..65535") 40 Uint32Range = mustParseRangesInt("0..4294967295") 41 Uint64Range = mustParseRangesInt("0..18446744073709551615") 42 ) 43 44 const ( 45 // MaxInt64 corresponds to the maximum value of a signed int64. 46 MaxInt64 = 1<<63 - 1 47 // MinInt64 corresponds to the maximum value of a signed int64. 48 MinInt64 = -1 << 63 49 // Min/MaxDecimal64 are the max/min decimal64 values. 50 MinDecimal64 float64 = -922337203685477580.8 51 MaxDecimal64 float64 = 922337203685477580.7 52 // AbsMinInt64 is the absolute value of MinInt64. 53 AbsMinInt64 = 1 << 63 54 // MaxEnum is the maximum value of an enumeration. 55 MaxEnum = 1<<31 - 1 56 // MinEnum is the minimum value of an enumeration. 57 MinEnum = -1 << 31 58 // MaxBitfieldSize is the maximum number of bits in a bitfield. 59 MaxBitfieldSize = 1 << 32 60 // MaxFractionDigits is the maximum number of fractional digits as per RFC6020 Section 9.3.4. 61 MaxFractionDigits uint8 = 18 62 63 space18 = "000000000000000000" // used for prepending 0's 64 ) 65 66 // A Number is either an integer the range of [-(1<<64) - 1, (1<<64)-1], or a 67 // YANG decimal conforming to https://tools.ietf.org/html/rfc6020#section-9.3.4. 68 type Number struct { 69 // Absolute value of the number. 70 Value uint64 71 // Number of fractional digits. 72 // 0 means it's an integer. For decimal64 it falls within [1, 18]. 73 FractionDigits uint8 74 // Negative indicates whether the number is negative. 75 Negative bool 76 } 77 78 // IsDecimal reports whether n is a decimal number. 79 func (n Number) IsDecimal() bool { 80 return n.FractionDigits != 0 81 } 82 83 // String returns n as a string in decimal. 84 func (n Number) String() string { 85 out := strconv.FormatUint(n.Value, 10) 86 87 if n.IsDecimal() { 88 if fd := int(n.FractionDigits); fd > 0 { 89 ofd := len(out) - fd 90 if ofd <= 0 { 91 // We want 0.1 not .1 92 out = space18[:-ofd+1] + out 93 ofd = 1 94 } 95 out = out[:ofd] + "." + out[ofd:] 96 } 97 } 98 if n.Negative { 99 out = "-" + out 100 } 101 102 return out 103 } 104 105 // Int returns n as an int64. It returns an error if n overflows an int64 or 106 // the number is decimal. 107 func (n Number) Int() (int64, error) { 108 if n.IsDecimal() { 109 return 0, errors.New("called Int() on decimal64 value") 110 } 111 if n.Negative { 112 return -int64(n.Value), nil 113 } 114 if n.Value <= MaxInt64 { 115 return int64(n.Value), nil 116 } 117 return 0, errors.New("signed integer overflow") 118 } 119 120 // addQuantum adds the smallest quantum to n without checking overflow. 121 func (n Number) addQuantum(i uint64) Number { 122 switch n.Negative { 123 case true: 124 if n.Value <= i { 125 n.Value = i - n.Value 126 n.Negative = false 127 } else { 128 n.Value -= i 129 } 130 case false: 131 n.Value += i 132 } 133 return n 134 } 135 136 // Less returns true if n is less than m. Panics if n and m are a mix of integer 137 // and decimal. 138 func (n Number) Less(m Number) bool { 139 switch { 140 case n.Negative && !m.Negative: 141 return true 142 case !n.Negative && m.Negative: 143 return false 144 } 145 146 nt, mt := n.Trunc(), m.Trunc() 147 lt := nt < mt 148 if nt == mt { 149 nf, mf := n.frac(), m.frac() 150 if nf == mf { 151 return false 152 } 153 lt = nf < mf 154 } 155 156 if n.Negative { 157 return !lt 158 } 159 return lt 160 } 161 162 // Equal returns true if n is equal to m. 163 func (n Number) Equal(m Number) bool { 164 return !n.Less(m) && !m.Less(n) 165 } 166 167 // Trunc returns the whole part of abs(n) as a signed integer. 168 func (n Number) Trunc() uint64 { 169 nv := n.Value 170 e := pow10(n.FractionDigits) 171 return nv / e 172 } 173 174 // frac returns the fraction part with a precision of 18 fractional digits. 175 // E.g. if n is 3.1 then n.frac() returns 100,000,000,000,000,000 176 func (n Number) frac() uint64 { 177 frac := n.FractionDigits 178 i := n.Trunc() * pow10(frac) 179 return (n.Value - i) * pow10(uint8(18-frac)) 180 } 181 182 // YRange is a single range of consecutive numbers, inclusive. 183 type YRange struct { 184 Min Number 185 Max Number 186 } 187 188 // Valid returns false if r is not a valid range (min > max). 189 func (r YRange) Valid() bool { 190 return !r.Max.Less(r.Min) 191 } 192 193 // String returns r as a string using YANG notation, either a simple 194 // value if min == max or min..max. 195 func (r YRange) String() string { 196 if r.Min.Equal(r.Max) { 197 return r.Min.String() 198 } 199 return r.Min.String() + ".." + r.Max.String() 200 } 201 202 // Equal compares whether two YRanges are equal. 203 func (r YRange) Equal(s YRange) bool { 204 return r.Min.Equal(s.Min) && r.Max.Equal(s.Max) 205 } 206 207 // A YangRange is a set of non-overlapping ranges. 208 type YangRange []YRange 209 210 // String returns the ranges r using YANG notation. Individual ranges 211 // are separated by pipes (|). 212 func (r YangRange) String() string { 213 s := make([]string, len(r)) 214 for i, r := range r { 215 s[i] = r.String() 216 } 217 return strings.Join(s, "|") 218 } 219 220 func (r YangRange) Len() int { return len(r) } 221 func (r YangRange) Swap(i, j int) { r[i], r[j] = r[j], r[i] } 222 func (r YangRange) Less(i, j int) bool { 223 switch { 224 case r[i].Min.Less(r[j].Min): 225 return true 226 case r[j].Min.Less(r[i].Min): 227 return false 228 default: 229 return r[i].Max.Less(r[j].Max) 230 } 231 } 232 233 // Validate returns an error if r has either an invalid range or has 234 // overlapping ranges. 235 // r is expected to be sorted use YangRange.Sort() 236 func (r YangRange) Validate() error { 237 if !sort.IsSorted(r) { 238 return errors.New("range not sorted") 239 } 240 switch { 241 case len(r) == 0: 242 return nil 243 case !r[0].Valid(): 244 return errors.New("invalid number") 245 } 246 p := r[0] 247 248 for _, n := range r[1:] { 249 if n.Min.Less(p.Max) { 250 return errors.New("overlapping ranges") 251 } 252 } 253 return nil 254 } 255 256 // Sort r. Must be called before Validate and coalesce if unsorted 257 func (r YangRange) Sort() { 258 sort.Sort(r) 259 } 260 261 // Equal returns true if ranges r and q are identically equivalent. 262 // TODO(borman): should we coalesce ranges in the comparison? 263 func (r YangRange) Equal(q YangRange) bool { 264 if len(r) != len(q) { 265 return false 266 } 267 for i, r := range r { 268 if !r.Equal(q[i]) { 269 return false 270 } 271 } 272 return true 273 } 274 275 // Contains returns true if all possible values in s are also possible values 276 // in r. An empty range is assumed to be min..max when it is the receiver 277 // argument. 278 func (r YangRange) Contains(s YangRange) bool { 279 if len(r) == 0 || len(s) == 0 { 280 return true 281 } 282 283 // Check if every range in s is subsumed under r. 284 // Both range lists should be in order and non-adjacent (coalesced). 285 ri := 0 286 for _, ss := range s { 287 for r[ri].Max.Less(ss.Min) { 288 ri++ 289 if ri == len(r) { 290 return false 291 } 292 } 293 if ss.Min.Less(r[ri].Min) || r[ri].Max.Less(ss.Max) { 294 return false 295 } 296 } 297 return true 298 } 299 300 // FromInt creates a Number from an int64. 301 func FromInt(i int64) Number { 302 if i < 0 { 303 return Number{Negative: true, Value: uint64(-i)} 304 } 305 return Number{Value: uint64(i)} 306 } 307 308 // FromUint creates a Number from a uint64. 309 func FromUint(i uint64) Number { 310 return Number{Value: i} 311 } 312 313 // FromFloat creates a Number from a float64. Input values with absolute value 314 // outside the boundaries specified for the decimal64 value specified in 315 // RFC6020/RFC7950 are clamped down to the closest boundary value. 316 func FromFloat(f float64) Number { 317 if f > MaxDecimal64 { 318 return Number{ 319 Value: FromInt(MaxInt64).Value, 320 FractionDigits: 1, 321 } 322 } 323 if f < MinDecimal64 { 324 return Number{ 325 Negative: true, 326 Value: FromInt(MaxInt64).Value, 327 FractionDigits: 1, 328 } 329 } 330 331 // Per RFC7950/6020, fraction-digits must be at least 1. 332 fracDig := uint8(1) 333 f *= 10.0 334 for ; Frac(f) != 0.0 && fracDig <= MaxFractionDigits; fracDig++ { 335 f *= 10.0 336 } 337 v := uint64(f) 338 negative := false 339 if f < 0 { 340 negative = true 341 v = -v 342 } 343 344 return Number{Negative: negative, Value: v, FractionDigits: fracDig} 345 } 346 347 // ParseInt returns s as a Number with FractionDigits=0. 348 // octal, or hexadecimal using the standard prefix notations (e.g., 0 and 0x) 349 func ParseInt(s string) (Number, error) { 350 s = strings.TrimSpace(s) 351 var n Number 352 switch s { 353 case "": 354 return n, errors.New("converting empty string to number") 355 case "+", "-": 356 return n, errors.New("sign with no value") 357 } 358 359 ns := s 360 switch s[0] { 361 case '+': 362 ns = s[1:] 363 case '-': 364 n.Negative = true 365 ns = s[1:] 366 } 367 368 var err error 369 n.Value, err = strconv.ParseUint(ns, 0, 64) 370 return n, err 371 } 372 373 // ParseDecimal returns s as a Number with a non-zero FractionDigits. 374 // octal, or hexadecimal using the standard prefix notations (e.g., 0 and 0x) 375 func ParseDecimal(s string, fracDigRequired uint8) (n Number, err error) { 376 s = strings.TrimSpace(s) 377 switch s { 378 case "": 379 return n, errors.New("converting empty string to number") 380 case "+", "-": 381 return n, errors.New("sign with no value") 382 } 383 384 return decimalValueFromString(s, fracDigRequired) 385 } 386 387 // decimalValueFromString returns a decimal Number representation of numStr. 388 // fracDigRequired is used to set the number of fractional digits, which must 389 // be at least the greatest precision seen in numStr. 390 // which must be between 1 and 18. 391 // numStr must conform to Section 9.3.4. 392 func decimalValueFromString(numStr string, fracDigRequired uint8) (n Number, err error) { 393 if fracDigRequired > MaxFractionDigits || fracDigRequired < 1 { 394 return n, fmt.Errorf("invalid number of fraction digits %d > max of %d, minimum 1", fracDigRequired, MaxFractionDigits) 395 } 396 397 s := numStr 398 dx := strings.Index(s, ".") 399 var fracDig uint8 400 if dx >= 0 { 401 fracDig = uint8(len(s) - 1 - dx) 402 // remove first decimal, if dx > 1, will fail ParseInt below 403 s = s[:dx] + s[dx+1:] 404 } 405 406 if fracDig > fracDigRequired { 407 return n, fmt.Errorf("%s has too much precision, expect <= %d fractional digits", s, fracDigRequired) 408 } 409 410 s += space18[:fracDigRequired-fracDig] 411 412 v, err := strconv.ParseInt(s, 10, 64) 413 if err != nil { 414 return n, fmt.Errorf("%s is not a valid decimal number: %s", numStr, err) 415 } 416 417 negative := false 418 if v < 0 { 419 negative = true 420 v = -v 421 } 422 423 return Number{Value: uint64(v), FractionDigits: fracDigRequired, Negative: negative}, nil 424 } 425 426 // ParseRangesInt parses s into a series of ranges. Each individual range is in s 427 // is separated by the pipe character (|). The min and max value of a range 428 // are separated by "..". An error is returned if the range is invalid. The 429 // output range is sorted and coalesced. 430 func ParseRangesInt(s string) (YangRange, error) { 431 return YangRange{}.parseChildRanges(s, false, 0) 432 } 433 434 // ParseRangesDecimal parses s into a series of ranges. Each individual range is in s 435 // is separated by the pipe character (|). The min and max value of a range 436 // are separated by "..". An error is returned if the range is invalid. The 437 // output range is sorted and coalesced. 438 func ParseRangesDecimal(s string, fracDigRequired uint8) (YangRange, error) { 439 return YangRange{}.parseChildRanges(s, true, fracDigRequired) 440 } 441 442 // parseChildRanges parses a child ranges statement 's' into a series of ranges 443 // based on an already-parsed parent YangRange. Each individual range is in s 444 // is separated by the pipe character (|). The min and max value of a range are 445 // separated by "..". An error is returned if the child ranges are not 446 // equally-limiting or more limiting than the parent range 447 // (rfc7950#section-9.2.5). The output range is sorted and coalesced. 448 // fracDigRequired is ignored when decimal=false. 449 func (y YangRange) parseChildRanges(s string, decimal bool, fracDigRequired uint8) (YangRange, error) { 450 parseNumber := func(s string) (Number, error) { 451 switch { 452 case s == "max": 453 if len(y) == 0 { 454 return Number{}, errors.New("cannot resolve 'max' keyword using an empty YangRange parent object") 455 } 456 max := y[len(y)-1].Max 457 max.FractionDigits = fracDigRequired 458 return max, nil 459 case s == "min": 460 if len(y) == 0 { 461 return Number{}, errors.New("cannot resolve 'min' keyword using an empty YangRange parent object") 462 } 463 min := y[0].Min 464 min.FractionDigits = fracDigRequired 465 return min, nil 466 case decimal: 467 return ParseDecimal(s, fracDigRequired) 468 default: 469 return ParseInt(s) 470 } 471 } 472 473 parts := strings.Split(s, "|") 474 r := make(YangRange, len(parts)) 475 for i, s := range parts { 476 parts := strings.Split(s, "..") 477 min, err := parseNumber(strings.TrimSpace(parts[0])) 478 if err != nil { 479 return nil, err 480 } 481 var max Number 482 switch len(parts) { 483 case 1: 484 max = min 485 case 2: 486 if max, err = parseNumber(strings.TrimSpace(parts[1])); err != nil { 487 return nil, err 488 } 489 default: 490 return nil, fmt.Errorf("too many '..' in %s", s) 491 } 492 if max.Less(min) { 493 return nil, fmt.Errorf("range boundaries out of order (%s less than %s): %s", max, min, s) 494 } 495 r[i] = YRange{min, max} 496 } 497 r.Sort() 498 r = coalesce(r) 499 500 if !y.Contains(r) { 501 return nil, fmt.Errorf("%v not within %v", s, y) 502 } 503 504 if err := r.Validate(); err != nil { 505 return nil, err 506 } 507 return r, nil 508 } 509 510 // coalesce coalesces r into as few ranges as possible. For example, 511 // 1..5|6..10 would become 1..10. r is assumed to be sorted. 512 func coalesce(r YangRange) YangRange { 513 // coalesce the ranges if we have more than 1. 514 if len(r) < 2 { 515 return r 516 } 517 cr := make(YangRange, len(r)) 518 i := 0 519 cr[i] = r[0] 520 for _, r1 := range r[1:] { 521 // r1.Min is always at least as large as cr[i].Min 522 // Cases are: 523 // r1 is contained in cr[i] 524 // r1 starts inside of cr[i] 525 // r1.Min cr[i].Max+1 526 // r1 is beyond cr[i] 527 if cr[i].Max.addQuantum(1).Less(r1.Min) { 528 // r1 starts after cr[i], this is a new range 529 i++ 530 cr[i] = r1 531 } else if cr[i].Max.Less(r1.Max) { 532 cr[i].Max = r1.Max 533 } 534 } 535 return cr[:i+1] 536 } 537 538 func mustParseRangesInt(s string) YangRange { 539 r, err := ParseRangesInt(s) 540 if err != nil { 541 panic(err) 542 } 543 return r 544 } 545 546 func mustParseRangesDecimal(s string, fracDigRequired uint8) YangRange { 547 r, err := ParseRangesDecimal(s, fracDigRequired) 548 if err != nil { 549 panic(err) 550 } 551 return r 552 } 553 554 // Frac returns the fractional part of f. 555 func Frac(f float64) float64 { 556 return f - math.Trunc(f) 557 } 558 559 // pow10 returns 10^e without checking for overflow. 560 func pow10(e uint8) uint64 { 561 var out uint64 = 1 562 for i := uint8(0); i < e; i++ { 563 out *= 10 564 } 565 return out 566 } 567 568 // A EnumType represents a mapping of strings to integers. It is used both 569 // for enumerations as well as bitfields. 570 type EnumType struct { 571 last int64 // maximum value assigned thus far 572 min int64 // minimum value allowed 573 max int64 // maximum value allowed 574 unique bool // numeric values must be unique (enums) 575 ToString map[int64]string `json:",omitempty"` // map of enum entries by value (integer) 576 ToInt map[string]int64 `json:",omitempty"` // map of enum entries by name (string) 577 } 578 579 // NewEnumType returns an initialized EnumType. 580 func NewEnumType() *EnumType { 581 return &EnumType{ 582 last: -1, // +1 will start at 0 583 min: MinEnum, 584 max: MaxEnum, 585 unique: true, 586 ToString: map[int64]string{}, 587 ToInt: map[string]int64{}, 588 } 589 } 590 591 // NewBitfield returns an EnumType initialized as a bitfield. Multiple string 592 // values may map to the same numeric values. Numeric values must be small 593 // non-negative integers. 594 func NewBitfield() *EnumType { 595 return &EnumType{ 596 last: -1, // +1 will start at 0 597 min: 0, 598 max: MaxBitfieldSize - 1, 599 ToString: map[int64]string{}, 600 ToInt: map[string]int64{}, 601 } 602 } 603 604 // Set sets name in e to the provided value. Set returns an error if the value 605 // is invalid, name is already signed, or when used as an enum rather than a 606 // bitfield, the value has previousl been used. When two different names are 607 // assigned to the same value, the conversion from value to name will result in 608 // the most recently assigned name. 609 func (e *EnumType) Set(name string, value int64) error { 610 if _, ok := e.ToInt[name]; ok { 611 return fmt.Errorf("field %s already assigned", name) 612 } 613 if oname, ok := e.ToString[value]; e.unique && ok { 614 return fmt.Errorf("fields %s and %s conflict on value %d", name, oname, value) 615 } 616 if value < e.min { 617 return fmt.Errorf("value %d for %s too small (minimum is %d)", value, name, e.min) 618 } 619 if value > e.max { 620 return fmt.Errorf("value %d for %s too large (maximum is %d)", value, name, e.max) 621 } 622 e.ToString[value] = name 623 e.ToInt[name] = value 624 if value >= e.last { 625 e.last = value 626 } 627 return nil 628 } 629 630 // SetNext sets the name in e using the next possible value that is greater than 631 // all previous values. 632 func (e *EnumType) SetNext(name string) error { 633 if e.last == MaxEnum { 634 return fmt.Errorf("enum %q must specify a value since previous enum is the maximum value allowed", name) 635 } 636 return e.Set(name, e.last+1) 637 } 638 639 // Name returns the name in e associated with value. The empty string is 640 // returned if no name has been assigned to value. 641 func (e *EnumType) Name(value int64) string { return e.ToString[value] } 642 643 // Value returns the value associated with name in e associated. 0 is returned 644 // if name is not in e, or if it is the first value in an unnumbered enum. Use 645 // IsDefined to definitively confirm name is in e. 646 func (e *EnumType) Value(name string) int64 { return e.ToInt[name] } 647 648 // IsDefined returns true if name is defined in e, else false. 649 func (e *EnumType) IsDefined(name string) bool { 650 _, defined := e.ToInt[name] 651 return defined 652 } 653 654 // Names returns the sorted list of enum string names. 655 func (e *EnumType) Names() []string { 656 names := make([]string, len(e.ToInt)) 657 i := 0 658 for name := range e.ToInt { 659 names[i] = name 660 i++ 661 } 662 sort.Strings(names) 663 return names 664 } 665 666 type int64Slice []int64 667 668 func (p int64Slice) Len() int { return len(p) } 669 func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] } 670 func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 671 672 // Values returns the sorted list of enum values. 673 func (e *EnumType) Values() []int64 { 674 values := make([]int64, len(e.ToInt)) 675 i := 0 676 for _, value := range e.ToInt { 677 values[i] = value 678 i++ 679 } 680 sort.Sort(int64Slice(values)) 681 return values 682 } 683 684 // NameMap returns a map of names to values. 685 func (e *EnumType) NameMap() map[string]int64 { 686 m := make(map[string]int64, len(e.ToInt)) 687 for name, value := range e.ToInt { 688 m[name] = value 689 } 690 return m 691 } 692 693 // ValueMap returns a map of values to names. 694 func (e *EnumType) ValueMap() map[int64]string { 695 m := make(map[int64]string, len(e.ToString)) 696 for name, value := range e.ToString { 697 m[name] = value 698 } 699 return m 700 }