github.com/enbility/spine-go@v0.7.0/model/commandframe_additions.go (about)

     1  package model
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  
     8  	"github.com/enbility/spine-go/util"
     9  )
    10  
    11  func (r *MsgCounterType) String() string {
    12  	if r == nil {
    13  		return ""
    14  	}
    15  	return fmt.Sprintf("%d", *r)
    16  }
    17  
    18  // FilterData stores the function field name and
    19  // selector field name for a function
    20  type FilterData struct {
    21  	Elements any
    22  	Selector any
    23  	Function *FunctionType
    24  }
    25  
    26  func (f *FilterData) SelectorMatch(item any) bool {
    27  	if f.Selector == nil {
    28  		return false
    29  	}
    30  
    31  	v := reflect.ValueOf(f.Selector).Elem()
    32  	t := reflect.TypeOf(f.Selector).Elem()
    33  
    34  	for i := 0; i < v.NumField(); i++ {
    35  		field := v.Field(i)
    36  		if field.Kind() != reflect.Ptr {
    37  			continue
    38  		}
    39  
    40  		if field.IsNil() {
    41  			continue
    42  		}
    43  
    44  		fieldname := t.Field(i).Name
    45  		value := field.Elem().Interface()
    46  
    47  		itemV := reflect.ValueOf(item).Elem()
    48  		itemF := itemV.FieldByName(fieldname)
    49  		if !itemF.IsValid() {
    50  			continue
    51  		}
    52  
    53  		itemValue := itemF.Elem().Interface()
    54  		if itemValue != value {
    55  			return false
    56  		}
    57  	}
    58  
    59  	return true
    60  }
    61  
    62  // Get the field for a given functionType
    63  func (f *FilterType) SetDataForFunction(tagType EEBusTagTypeType, fct FunctionType, data any) {
    64  	if data == nil || reflect.ValueOf(data).Kind() != reflect.Ptr {
    65  		return
    66  	}
    67  
    68  	v := reflect.ValueOf(*f)
    69  	dv := reflect.ValueOf(f).Elem()
    70  	for i := 0; i < v.NumField(); i++ {
    71  		field := v.Field(i)
    72  		if field.Kind() != reflect.Ptr {
    73  			continue
    74  		}
    75  
    76  		sf := v.Type().Field(i)
    77  		// Exclude the generic fields
    78  		if sf.Name == "CmdControl" || sf.Name == "FilterId" {
    79  			continue
    80  		}
    81  
    82  		eebusTags := EEBusTags(sf)
    83  		function, exists := eebusTags[EEBusTagFunction]
    84  		if !exists {
    85  			continue
    86  		}
    87  		typ, exists := eebusTags[EEBusTagType]
    88  		if !exists || len(typ) == 0 {
    89  			continue
    90  		}
    91  		if typ != string(tagType) {
    92  			continue
    93  		}
    94  
    95  		if fct != FunctionType(function) {
    96  			continue
    97  		}
    98  
    99  		n := v.Type().Field(i).Name
   100  		ff := dv.FieldByName(n)
   101  
   102  		if !ff.CanSet() {
   103  			break
   104  		}
   105  
   106  		if reflect.ValueOf(data).IsNil() {
   107  			typ := reflect.TypeOf(data).Elem()
   108  			ff.Set(reflect.New(typ))
   109  			return
   110  		}
   111  
   112  		dataV := reflect.ValueOf(data)
   113  		dataC := dataV.Convert(ff.Type())
   114  		ff.Set(dataC)
   115  		return
   116  	}
   117  }
   118  
   119  // Get the data and some meta data for the current value
   120  func (f *FilterType) Data() (*FilterData, error) {
   121  	var elements any = nil
   122  	var selector any = nil
   123  	var function string
   124  
   125  	v := reflect.ValueOf(*f)
   126  	for i := 0; i < v.NumField(); i++ {
   127  		f := v.Field(i)
   128  		if f.Kind() != reflect.Ptr {
   129  			continue
   130  		}
   131  
   132  		if f.IsNil() {
   133  			continue
   134  		}
   135  
   136  		sf := v.Type().Field(i)
   137  		// Exclude the generic fields
   138  		if sf.Name == "CmdControl" || sf.Name == "FilterId" {
   139  			continue
   140  		}
   141  
   142  		eebusTags := EEBusTags(sf)
   143  		fname, exists := eebusTags[EEBusTagFunction]
   144  		if !exists || len(fname) == 0 {
   145  			continue
   146  		}
   147  		typ, exists := eebusTags[EEBusTagType]
   148  		if !exists || len(typ) == 0 {
   149  			continue
   150  		}
   151  
   152  		function = fname
   153  
   154  		switch typ {
   155  		case string(EEBusTagTypeTypeSelector):
   156  			selector = f.Interface()
   157  		case string(EEbusTagTypeTypeElements):
   158  			elements = f.Interface()
   159  		}
   160  	}
   161  
   162  	if len(function) == 0 {
   163  		return nil, errors.New("Data not found in Filter")
   164  	}
   165  
   166  	ft := util.Ptr(FunctionType(function))
   167  
   168  	return &FilterData{
   169  		Elements: elements,
   170  		Selector: selector,
   171  		Function: ft,
   172  	}, nil
   173  }
   174  
   175  // CmdData stores the function field name for a cmd field
   176  type CmdData struct {
   177  	FieldName string
   178  	Function  *FunctionType
   179  	Value     any
   180  }
   181  
   182  // Get the field for a given functionType
   183  func (cmd *CmdType) SetDataForFunction(fct FunctionType, data any) {
   184  	if data == nil || reflect.ValueOf(data).Kind() != reflect.Ptr {
   185  		return
   186  	}
   187  
   188  	v := reflect.ValueOf(*cmd)
   189  	dv := reflect.ValueOf(cmd).Elem()
   190  	for i := 0; i < v.NumField(); i++ {
   191  		f := v.Field(i)
   192  		if f.Kind() != reflect.Ptr {
   193  			continue
   194  		}
   195  
   196  		sf := v.Type().Field(i)
   197  		// Exclude the CmdOptionGroup fields
   198  		if sf.Name == "Function" || sf.Name == "Filter" {
   199  			continue
   200  		}
   201  
   202  		eebusTags := EEBusTags(sf)
   203  		function, exists := eebusTags[EEBusTagFunction]
   204  		if !exists {
   205  			continue
   206  		}
   207  
   208  		if fct != FunctionType(function) {
   209  			continue
   210  		}
   211  
   212  		n := v.Type().Field(i).Name
   213  		ff := dv.FieldByName(n)
   214  
   215  		if !ff.CanSet() {
   216  			break
   217  		}
   218  
   219  		if reflect.ValueOf(data).IsNil() {
   220  			typ := reflect.TypeOf(data).Elem()
   221  			ff.Set(reflect.New(typ))
   222  			return
   223  		}
   224  
   225  		dataV := reflect.ValueOf(data)
   226  		dataC := dataV.Convert(ff.Type())
   227  		ff.Set(dataC)
   228  		return
   229  	}
   230  }
   231  
   232  // Get the data and some meta data of the current value
   233  func (cmd *CmdType) Data() (*CmdData, error) {
   234  	v := reflect.ValueOf(*cmd)
   235  	for i := 0; i < v.NumField(); i++ {
   236  		f := v.Field(i)
   237  		if f.Kind() != reflect.Ptr {
   238  			continue
   239  		}
   240  
   241  		if f.IsNil() {
   242  			continue
   243  		}
   244  
   245  		sf := v.Type().Field(i)
   246  		// Exclude the CmdOptionGroup fields
   247  		if sf.Name == "Function" || sf.Name == "Filter" {
   248  			continue
   249  		}
   250  
   251  		eebusTags := EEBusTags(sf)
   252  		function, exists := eebusTags[EEBusTagFunction]
   253  		if !exists {
   254  			continue
   255  		}
   256  
   257  		var ft *FunctionType = nil
   258  		if len(function) > 0 {
   259  			ft = util.Ptr(FunctionType(function))
   260  		}
   261  
   262  		return &CmdData{
   263  			FieldName: sf.Name,
   264  			Function:  ft,
   265  			Value:     f.Interface(),
   266  		}, nil
   267  	}
   268  
   269  	return nil, errors.New("Data not found in Cmd")
   270  }
   271  
   272  // Get the non empty field name of the data type
   273  func (cmd *CmdType) DataName() string {
   274  	data, err := cmd.Data()
   275  	if err != nil {
   276  		return "unknown"
   277  	}
   278  
   279  	return data.FieldName
   280  }
   281  
   282  func (cmd *CmdType) ExtractFilter() (filterPartial *FilterType, filterDelete *FilterType) {
   283  	if cmd != nil && cmd.Filter != nil && len(cmd.Filter) > 0 {
   284  		for i := range cmd.Filter {
   285  			if cmd.Filter[i].CmdControl.Partial != nil {
   286  				filterPartial = &cmd.Filter[i]
   287  			} else if cmd.Filter[i].CmdControl.Delete != nil {
   288  				filterDelete = &cmd.Filter[i]
   289  			}
   290  		}
   291  	}
   292  	return
   293  }
   294  
   295  func NewFilterTypePartial() *FilterType {
   296  	return &FilterType{CmdControl: &CmdControlType{Partial: &ElementTagType{}}}
   297  }