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  }