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 }