Fix number parsing for MetaSettingsType (#806)

json.Unmarshal parses all numbers to float64, which breaks any integer
settings values. This PR changes MetaSettingsType.UnmarshalJSON to use
json.Decoder, which is capable of parsing into a meta-type json.Number,
which can be interpreted as a float or an integer. It also properly
handles pointer types.
This commit is contained in:
Evan Simkowitz 2024-09-23 18:51:30 -07:00 committed by GitHub
parent 96ad70ffdd
commit 4907552379
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 10 deletions

View File

@ -47,11 +47,16 @@ func parseMetaSets(metaSets []string) (map[string]interface{}, error) {
}
meta[fields[0]] = val
} else {
fval, err := strconv.ParseFloat(setVal, 64)
ival, err := strconv.ParseInt(setVal, 0, 64)
if err == nil {
meta[fields[0]] = fval
meta[fields[0]] = ival
} else {
meta[fields[0]] = setVal
fval, err := strconv.ParseFloat(setVal, 64)
if err == nil {
meta[fields[0]] = fval
} else {
meta[fields[0]] = setVal
}
}
}
}

View File

@ -26,7 +26,9 @@ type MetaSettingsType struct {
func (m *MetaSettingsType) UnmarshalJSON(data []byte) error {
var metaMap waveobj.MetaMapType
if err := json.Unmarshal(data, &metaMap); err != nil {
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
if err := decoder.Decode(&metaMap); err != nil {
return err
}
*m = MetaSettingsType{MetaMapType: metaMap}
@ -77,7 +79,7 @@ type SettingsType struct {
WindowOpacity *float64 `json:"window:opacity,omitempty"`
WindowBgColor string `json:"window:bgcolor,omitempty"`
WindowReducedMotion bool `json:"window:reducedmotion,omitempty"`
WindowTileGapSize *int8 `json:"window:tilegapsize,omitempty"`
WindowTileGapSize *int64 `json:"window:tilegapsize,omitempty"`
TelemetryClear bool `json:"telemetry:*,omitempty"`
TelemetryEnabled bool `json:"telemetry:enabled,omitempty"`
@ -98,8 +100,6 @@ type FullConfigType struct {
ConfigErrors []ConfigError `json:"configerrors" configfile:"-"`
}
var settingsAbsPath = filepath.Join(configDirAbsPath, SettingsFile)
func readConfigHelper(fileName string, barr []byte, readErr error) (waveobj.MetaMapType, []ConfigError) {
var cerrs []ConfigError
if readErr != nil && !os.IsNotExist(readErr) {
@ -242,7 +242,7 @@ func reindentJson(barr []byte, indentStr string) []byte {
if barr[0] != '{' && barr[0] != '[' {
return barr
}
if bytes.Index(barr, []byte("\n")) == -1 {
if bytes.Contains(barr, []byte("\n")) {
return barr
}
outputLines := bytes.Split(barr, []byte("\n"))
@ -286,6 +286,32 @@ func jsonMarshalConfigInOrder(m waveobj.MetaMapType) ([]byte, error) {
return buf.Bytes(), nil
}
var dummyNumber json.Number
func convertJsonNumber(num json.Number, ctype reflect.Type) (interface{}, error) {
// ctype might be int64, float64, string, *int64, *float64, *string
// switch on ctype first
if ctype.Kind() == reflect.Pointer {
ctype = ctype.Elem()
}
if reflect.Int64 == ctype.Kind() {
if ival, err := num.Int64(); err == nil {
return ival, nil
}
return nil, fmt.Errorf("invalid number for int64: %s", num)
}
if reflect.Float64 == ctype.Kind() {
if fval, err := num.Float64(); err == nil {
return fval, nil
}
return nil, fmt.Errorf("invalid number for float64: %s", num)
}
if reflect.String == ctype.Kind() {
return num.String(), nil
}
return nil, fmt.Errorf("cannot convert number to %s", ctype)
}
func SetBaseConfigValue(toMerge waveobj.MetaMapType) error {
m, cerrs := ReadWaveHomeConfigFile(SettingsFile)
if len(cerrs) > 0 {
@ -302,8 +328,21 @@ func SetBaseConfigValue(toMerge waveobj.MetaMapType) error {
if val == nil {
delete(m, configKey)
} else {
if reflect.TypeOf(val) != ctype {
return fmt.Errorf("invalid value type for %s: %T", configKey, val)
rtype := reflect.TypeOf(val)
if rtype == reflect.TypeOf(dummyNumber) {
convertedVal, err := convertJsonNumber(val.(json.Number), ctype)
if err != nil {
return fmt.Errorf("cannot convert %s: %v", configKey, err)
}
val = convertedVal
rtype = reflect.TypeOf(val)
}
if rtype != ctype {
if ctype == reflect.PointerTo(rtype) {
m[configKey] = &val
} else {
return fmt.Errorf("invalid value type for %s: %T", configKey, val)
}
}
m[configKey] = val
}