go.ligato.io/vpp-agent/v3@v3.5.0/pkg/models/model.go (about)

     1  //  Copyright (c) 2018 Cisco and/or its affiliates.
     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 models
    16  
    17  import (
    18  	"reflect"
    19  	"strings"
    20  
    21  	"google.golang.org/protobuf/proto"
    22  	"google.golang.org/protobuf/reflect/protoreflect"
    23  
    24  	"go.ligato.io/vpp-agent/v3/proto/ligato/generic"
    25  )
    26  
    27  // LocallyKnownModel represents a registered local model (local model has go types compiled into program binary)
    28  type LocallyKnownModel struct {
    29  	spec Spec
    30  	modelOptions
    31  
    32  	goType reflect.Type
    33  	proto  protoreflect.ProtoMessage
    34  
    35  	// cache
    36  	keyPrefix *string
    37  	modelName *string
    38  }
    39  
    40  // Spec returns model specification for the model.
    41  func (m *LocallyKnownModel) Spec() *Spec {
    42  	spec := m.spec
    43  	return &spec
    44  }
    45  
    46  // ModelDetail returns descriptor for the model.
    47  func (m *LocallyKnownModel) ModelDetail() *generic.ModelDetail {
    48  	return &generic.ModelDetail{
    49  		Spec:      m.Spec().Proto(),
    50  		ProtoName: m.ProtoName(),
    51  		Options: []*generic.ModelDetail_Option{
    52  			{Key: "nameTemplate", Values: []string{m.NameTemplate()}},
    53  			{Key: "goType", Values: []string{m.GoType()}},
    54  			{Key: "pkgPath", Values: []string{m.PkgPath()}},
    55  			{Key: "protoFile", Values: []string{m.ProtoFile()}},
    56  		},
    57  	}
    58  }
    59  
    60  // NewInstance creates new instance value for model type.
    61  func (m *LocallyKnownModel) NewInstance() proto.Message {
    62  	return reflect.New(m.goType.Elem()).Interface().(proto.Message)
    63  }
    64  
    65  // ProtoName returns proto message name registered with the model.
    66  func (m *LocallyKnownModel) ProtoName() string {
    67  	if m.proto != nil {
    68  		return string(m.proto.ProtoReflect().Descriptor().FullName())
    69  	}
    70  	return ""
    71  }
    72  
    73  // ProtoFile returns proto file name for the model.
    74  func (m *LocallyKnownModel) ProtoFile() string {
    75  	if m.proto != nil {
    76  		return m.proto.ProtoReflect().Descriptor().ParentFile().Path()
    77  	}
    78  	return ""
    79  }
    80  
    81  // NameTemplate returns name template for the model.
    82  func (m *LocallyKnownModel) NameTemplate() string {
    83  	return m.nameTemplate
    84  }
    85  
    86  // GoType returns go type for the model.
    87  func (m *LocallyKnownModel) GoType() string {
    88  	return m.goType.String()
    89  }
    90  
    91  // LocalGoType returns reflect go type for the model.
    92  func (m *LocallyKnownModel) LocalGoType() reflect.Type {
    93  	return m.goType
    94  }
    95  
    96  // PkgPath returns package import path for the model definition.
    97  func (m *LocallyKnownModel) PkgPath() string {
    98  	return m.goType.Elem().PkgPath()
    99  }
   100  
   101  // Name returns name for the model.
   102  func (m *LocallyKnownModel) Name() string {
   103  	if m.modelName == nil {
   104  		modelName := m.spec.ModelName()
   105  		m.modelName = &modelName
   106  	}
   107  	return *m.modelName
   108  }
   109  
   110  // KeyPrefix returns key prefix for the model.
   111  func (m *LocallyKnownModel) KeyPrefix() string {
   112  	if m.keyPrefix == nil {
   113  		keyPrefix := m.getKeyPrefix()
   114  		m.keyPrefix = &keyPrefix
   115  	}
   116  	return *m.keyPrefix
   117  }
   118  
   119  func (m *LocallyKnownModel) getKeyPrefix() string {
   120  	return keyPrefix(m.spec, m.nameFunc != nil)
   121  }
   122  
   123  // ParseKey parses the given key and returns item name
   124  // or returns empty name and valid as false if the key is not valid.
   125  func (m *LocallyKnownModel) ParseKey(key string) (name string, valid bool) {
   126  	name = strings.TrimPrefix(key, m.KeyPrefix())
   127  	if name == key || (name == "" && m.nameFunc != nil) {
   128  		name = strings.TrimPrefix(key, m.Name())
   129  	}
   130  	// key had the prefix and also either
   131  	// non-empty name or no name template
   132  	if name != key && (name != "" || m.nameFunc == nil) {
   133  		// TODO: validate name?
   134  		return name, true
   135  	}
   136  	return "", false
   137  }
   138  
   139  // IsKeyValid returns true if given key is valid for this model.
   140  func (m *LocallyKnownModel) IsKeyValid(key string) bool {
   141  	_, valid := m.ParseKey(key)
   142  	return valid
   143  }
   144  
   145  // StripKeyPrefix returns key with prefix stripped.
   146  func (m *LocallyKnownModel) StripKeyPrefix(key string) string {
   147  	if name, valid := m.ParseKey(key); valid {
   148  		return name
   149  	}
   150  	return key
   151  }
   152  
   153  // InstanceName computes message name for given proto message using name template (if present).
   154  func (m *LocallyKnownModel) InstanceName(x interface{}) (string, error) {
   155  	if m.nameFunc == nil {
   156  		return "", nil
   157  	}
   158  	return m.nameFunc(x)
   159  }