diff --git a/internal/config/schema.go b/internal/config/schema.go index 083005a..ad91f28 100644 --- a/internal/config/schema.go +++ b/internal/config/schema.go @@ -3,7 +3,9 @@ package config -import "fmt" +import ( + "fmt" +) type Config struct { Devices []DeviceConfig @@ -11,35 +13,35 @@ type Config struct { Rules []RuleConfig } -// These structs use custom unmarshaling to inline each available sub-type +// These top-level structs use custom unmarshaling to unpack each available sub-type type DeviceConfig struct { Type string - Config interface{} `yaml:",inline"` + Config interface{} } type RuleConfig struct { Type string Name string Modes []string - Config interface{} `yaml:",inline"` + Config interface{} } type DeviceConfigPhysical struct { - Name string `yaml:"name"` + Name string DeviceName string `yaml:"device_name,omitempty"` DevicePath string `yaml:"device_path,omitempty"` - Lock bool `yaml:"lock,omitempty"` + Lock bool } // TODO: configure custom unmarshaling so we can overload Buttons, Axes, and RelativeAxes... type DeviceConfigVirtual struct { - Name string `yaml:"name"` - Preset string `yaml:"preset,omitempty"` - NumButtons int `yaml:"num_buttons,omitempty"` - NumAxes int `yaml:"num_axes,omitempty"` - NumRelativeAxes int `yaml:"num_rel_axes"` - Buttons []string `yaml:"buttons,omitempty"` - Axes []string `yaml:"axes,omitempty"` + Name string + Preset string + NumButtons int `yaml:"num_buttons,omitempty"` + NumAxes int `yaml:"num_axes,omitempty"` + NumRelativeAxes int `yaml:"num_rel_axes"` + Buttons []string + Axes []string RelativeAxes []string `yaml:"rel_axes,omitempty"` } @@ -116,42 +118,83 @@ type RuleTargetConfigModeSelect struct { } func (dc *DeviceConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { - var config interface{} - dc.Config = config - - switch dc.Type { - case DeviceTypePhysical: - config = &DeviceConfigPhysical{} - case DeviceTypeVirtual: - config = &DeviceConfigVirtual{} - default: - return fmt.Errorf("invalid device type '%s'", dc.Type) + metaConfig := &struct { + Type string + }{} + err := unmarshal(metaConfig) + if err != nil { + return err } + dc.Type = metaConfig.Type - return unmarshal(&config) + err = nil + switch metaConfig.Type { + case DeviceTypePhysical: + config := DeviceConfigPhysical{} + err = unmarshal(&config) + dc.Config = config + case DeviceTypeVirtual: + config := DeviceConfigVirtual{} + err = unmarshal(&config) + dc.Config = config + default: + err = fmt.Errorf("invalid device type '%s'", dc.Type) + } + return err } func (dc *RuleConfig) UnmarshalYAML(unmarshal func(data interface{}) error) error { + metaConfig := &struct { + Type string + Name string + Modes []string + }{} + err := unmarshal(metaConfig) + if err != nil { + return err + } + dc.Type = metaConfig.Type + dc.Name = metaConfig.Name + dc.Modes = metaConfig.Modes + switch dc.Type { case RuleTypeButton: - dc.Config = &RuleConfigButton{} + config := RuleConfigButton{} + err = unmarshal(&config) + dc.Config = config case RuleTypeButtonCombo: - dc.Config = &RuleConfigButtonCombo{} + config := RuleConfigButtonCombo{} + err = unmarshal(&config) + dc.Config = config case RuleTypeButtonLatched: - dc.Config = &RuleConfigButtonLatched{} + config := RuleConfigButtonLatched{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxis: - dc.Config = &RuleConfigAxis{} + config := RuleConfigAxis{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxisCombined: - dc.Config = &RuleConfigAxisCombined{} + config := RuleConfigAxisCombined{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxisToButton: - dc.Config = &RuleConfigAxisToButton{} + config := RuleConfigAxisToButton{} + err = unmarshal(&config) + dc.Config = config case RuleTypeAxisToRelaxis: - dc.Config = &RuleConfigAxisToRelaxis{} + config := RuleConfigAxisToRelaxis{} + err = unmarshal(&config) + dc.Config = config + case RuleTypeModeSelect: + config := RuleConfigModeSelect{} + err = unmarshal(&config) + dc.Config = config default: - return fmt.Errorf("invalid rule type '%s'", dc.Type) + err = fmt.Errorf("invalid rule type '%s'", dc.Type) } - return unmarshal(&dc.Config) + return err } // TODO: custom yaml unmarshaling is obtuse; do we really need to do all of this work