From c63ff8a46b0a497539a4029894cbc7b9619996f0 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Sat, 23 Sep 2023 19:28:16 +0100 Subject: [PATCH] =?UTF-8?q?interface{}=20=E2=86=92=20any?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bench_test.go | 10 ++--- cmd/toml-test-decoder/main.go | 2 +- cmd/toml-test-encoder/main.go | 2 +- cmd/tomlv/main.go | 2 +- decode.go | 62 +++++++++++++++------------- decode_test.go | 72 ++++++++++++++++---------------- deprecated.go | 4 +- encode.go | 6 +-- encode_test.go | 78 +++++++++++++++++------------------ error.go | 4 +- error_test.go | 4 +- example_test.go | 12 +++--- fuzz_test.go | 5 +-- internal/tag/add.go | 20 ++++----- internal/tag/rm.go | 14 +++---- lex.go | 2 +- meta.go | 8 ++-- parse.go | 54 ++++++++++++------------ toml_test.go | 6 +-- 19 files changed, 184 insertions(+), 183 deletions(-) diff --git a/bench_test.go b/bench_test.go index 76942593..b55aaf91 100644 --- a/bench_test.go +++ b/bench_test.go @@ -44,7 +44,7 @@ func BenchmarkDecode(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { for _, f := range tt.toml { - var val map[string]interface{} + var val map[string]any toml.Decode(f, &val) } } @@ -60,14 +60,14 @@ func BenchmarkDecode(b *testing.B) { b.ResetTimer() for n := 0; n < b.N; n++ { - var val map[string]interface{} + var val map[string]any toml.Decode(doc, &val) } }) } func BenchmarkEncode(b *testing.B) { - files := make(map[string][]map[string]interface{}) + files := make(map[string][]map[string]any) fs.WalkDir(tomltest.EmbeddedTests(), ".", func(path string, d fs.DirEntry, err error) error { if strings.HasPrefix(path, "valid/") && strings.HasSuffix(path, ".toml") { d, _ := fs.ReadFile(tomltest.EmbeddedTests(), path) @@ -84,7 +84,7 @@ func BenchmarkEncode(b *testing.B) { return nil } - var dec map[string]interface{} + var dec map[string]any _, err := toml.Decode(string(d), &dec) if err != nil { b.Fatalf("decode %q: %s", path, err) @@ -104,7 +104,7 @@ func BenchmarkEncode(b *testing.B) { type test struct { group string - data []map[string]interface{} + data []map[string]any } tests := make([]test, 0, len(files)) for k, v := range files { diff --git a/cmd/toml-test-decoder/main.go b/cmd/toml-test-decoder/main.go index 0823bbf8..6e5eef8f 100644 --- a/cmd/toml-test-decoder/main.go +++ b/cmd/toml-test-decoder/main.go @@ -30,7 +30,7 @@ func main() { flag.Usage() } - var decoded interface{} + var decoded any if _, err := toml.NewDecoder(os.Stdin).Decode(&decoded); err != nil { log.Fatalf("Error decoding TOML: %s", err) } diff --git a/cmd/toml-test-encoder/main.go b/cmd/toml-test-encoder/main.go index b5e47ab8..8af9f468 100644 --- a/cmd/toml-test-encoder/main.go +++ b/cmd/toml-test-encoder/main.go @@ -30,7 +30,7 @@ func main() { flag.Usage() } - var tmp interface{} + var tmp any if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil { log.Fatalf("Error decoding JSON: %s", err) } diff --git a/cmd/tomlv/main.go b/cmd/tomlv/main.go index 0eeb3cec..0a07fdd9 100644 --- a/cmd/tomlv/main.go +++ b/cmd/tomlv/main.go @@ -35,7 +35,7 @@ func main() { flag.Usage() } for _, f := range flag.Args() { - var tmp interface{} + var tmp any md, err := toml.DecodeFile(f, &tmp) if err != nil { log.Fatalf("Error in '%s': %s", f, err) diff --git a/decode.go b/decode.go index 455a1424..d1203c10 100644 --- a/decode.go +++ b/decode.go @@ -18,13 +18,13 @@ import ( // Unmarshaler is the interface implemented by objects that can unmarshal a // TOML description of themselves. type Unmarshaler interface { - UnmarshalTOML(interface{}) error + UnmarshalTOML(any) error } // Unmarshal decodes the contents of data in TOML format into a pointer v. // // See [Decoder] for a description of the decoding process. -func Unmarshal(data []byte, v interface{}) error { +func Unmarshal(data []byte, v any) error { _, err := NewDecoder(bytes.NewReader(data)).Decode(v) return err } @@ -32,12 +32,12 @@ func Unmarshal(data []byte, v interface{}) error { // Decode the TOML data in to the pointer v. // // See [Decoder] for a description of the decoding process. -func Decode(data string, v interface{}) (MetaData, error) { +func Decode(data string, v any) (MetaData, error) { return NewDecoder(strings.NewReader(data)).Decode(v) } // DecodeFile reads the contents of a file and decodes it with [Decode]. -func DecodeFile(path string, v interface{}) (MetaData, error) { +func DecodeFile(path string, v any) (MetaData, error) { fp, err := os.Open(path) if err != nil { return MetaData{}, err @@ -48,7 +48,7 @@ func DecodeFile(path string, v interface{}) (MetaData, error) { // DecodeFS reads the contents of a file from [fs.FS] and decodes it with // [Decode]. -func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) { +func DecodeFS(fsys fs.FS, path string, v any) (MetaData, error) { fp, err := fsys.Open(path) if err != nil { return MetaData{}, err @@ -69,7 +69,7 @@ func DecodeFS(fsys fs.FS, path string, v interface{}) (MetaData, error) { // overhead of reflection. They can be useful when you don't know the exact type // of TOML data until runtime. type Primitive struct { - undecoded interface{} + undecoded any context Key } @@ -133,7 +133,7 @@ var ( ) // Decode TOML data in to the pointer `v`. -func (dec *Decoder) Decode(v interface{}) (MetaData, error) { +func (dec *Decoder) Decode(v any) (MetaData, error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr { s := "%q" @@ -147,8 +147,8 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) { return MetaData{}, fmt.Errorf("toml: cannot decode to nil value of %q", reflect.TypeOf(v)) } - // Check if this is a supported type: struct, map, interface{}, or something - // that implements UnmarshalTOML or UnmarshalText. + // Check if this is a supported type: struct, map, any, or something that + // implements UnmarshalTOML or UnmarshalText. rv = indirect(rv) rt := rv.Type() if rv.Kind() != reflect.Struct && rv.Kind() != reflect.Map && @@ -190,7 +190,7 @@ func (dec *Decoder) Decode(v interface{}) (MetaData, error) { // will only reflect keys that were decoded. Namely, any keys hidden behind a // Primitive will be considered undecoded. Executing this method will update the // undecoded keys in the meta data. (See the example.) -func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { +func (md *MetaData) PrimitiveDecode(primValue Primitive, v any) error { md.context = primValue.context defer func() { md.context = nil }() return md.unify(primValue.undecoded, rvalue(v)) @@ -201,7 +201,7 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { // // Any type mismatch produces an error. Finding a type that we don't know // how to handle produces an unsupported type error. -func (md *MetaData) unify(data interface{}, rv reflect.Value) error { +func (md *MetaData) unify(data any, rv reflect.Value) error { // Special case. Look for a `Primitive` value. // TODO: #76 would make this superfluous after implemented. if rv.Type() == primitiveType { @@ -269,14 +269,13 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error { return md.e("unsupported type %s", rv.Kind()) } -func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { - tmap, ok := mapping.(map[string]interface{}) +func (md *MetaData) unifyStruct(mapping any, rv reflect.Value) error { + tmap, ok := mapping.(map[string]any) if !ok { if mapping == nil { return nil } - return md.e("type mismatch for %s: expected table but found %T", - rv.Type().String(), mapping) + return md.e("type mismatch for %s: expected table but found %s", rv.Type().String(), fmtType(mapping)) } for key, datum := range tmap { @@ -315,14 +314,14 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error { return nil } -func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { +func (md *MetaData) unifyMap(mapping any, rv reflect.Value) error { keyType := rv.Type().Key().Kind() if keyType != reflect.String && keyType != reflect.Interface { return fmt.Errorf("toml: cannot decode to a map with non-string key type (%s in %q)", keyType, rv.Type()) } - tmap, ok := mapping.(map[string]interface{}) + tmap, ok := mapping.(map[string]any) if !ok { if tmap == nil { return nil @@ -358,7 +357,7 @@ func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error { return nil } -func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyArray(data any, rv reflect.Value) error { datav := reflect.ValueOf(data) if datav.Kind() != reflect.Slice { if !datav.IsValid() { @@ -372,7 +371,7 @@ func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error { return md.unifySliceArray(datav, rv) } -func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifySlice(data any, rv reflect.Value) error { datav := reflect.ValueOf(data) if datav.Kind() != reflect.Slice { if !datav.IsValid() { @@ -399,7 +398,7 @@ func (md *MetaData) unifySliceArray(data, rv reflect.Value) error { return nil } -func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyString(data any, rv reflect.Value) error { _, ok := rv.Interface().(json.Number) if ok { if i, ok := data.(int64); ok { @@ -419,7 +418,7 @@ func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error { return md.badtype("string", data) } -func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyFloat64(data any, rv reflect.Value) error { rvk := rv.Kind() if num, ok := data.(float64); ok { @@ -449,7 +448,7 @@ func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error { return md.badtype("float", data) } -func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyInt(data any, rv reflect.Value) error { _, ok := rv.Interface().(time.Duration) if ok { // Parse as string duration, and fall back to regular integer parsing @@ -492,7 +491,7 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error { return nil } -func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyBool(data any, rv reflect.Value) error { if b, ok := data.(bool); ok { rv.SetBool(b) return nil @@ -500,12 +499,12 @@ func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error { return md.badtype("boolean", data) } -func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error { +func (md *MetaData) unifyAnything(data any, rv reflect.Value) error { rv.Set(reflect.ValueOf(data)) return nil } -func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) error { +func (md *MetaData) unifyText(data any, v encoding.TextUnmarshaler) error { var s string switch sdata := data.(type) { case Marshaler: @@ -539,8 +538,8 @@ func (md *MetaData) unifyText(data interface{}, v encoding.TextUnmarshaler) erro return nil } -func (md *MetaData) badtype(dst string, data interface{}) error { - return md.e("incompatible types: TOML value has type %T; destination has type %s", data, dst) +func (md *MetaData) badtype(dst string, data any) error { + return md.e("incompatible types: TOML value has type %s; destination has type %s", fmtType(data), dst) } func (md *MetaData) parseErr(err error) error { @@ -554,7 +553,7 @@ func (md *MetaData) parseErr(err error) error { } } -func (md *MetaData) e(format string, args ...interface{}) error { +func (md *MetaData) e(format string, args ...any) error { f := "toml: " if len(md.context) > 0 { f = fmt.Sprintf("toml: (last key %q): ", md.context) @@ -567,7 +566,7 @@ func (md *MetaData) e(format string, args ...interface{}) error { } // rvalue returns a reflect.Value of `v`. All pointers are resolved. -func rvalue(v interface{}) reflect.Value { +func rvalue(v any) reflect.Value { return indirect(reflect.ValueOf(v)) } @@ -611,3 +610,8 @@ func isUnifiable(rv reflect.Value) bool { } return false } + +// fmt %T with "interface {}" replaced with "any", which is far more readable. +func fmtType(t any) string { + return strings.ReplaceAll(fmt.Sprintf("%T", t), "interface {}", "any") +} diff --git a/decode_test.go b/decode_test.go index e9041080..4fac4ffe 100644 --- a/decode_test.go +++ b/decode_test.go @@ -109,8 +109,8 @@ func TestDecodeEmbedded(t *testing.T) { for _, test := range []struct { label string input string - decodeInto interface{} - wantDecoded interface{} + decodeInto any + wantDecoded any }{ { label: "embedded struct", @@ -156,7 +156,7 @@ func TestDecodeEmbedded(t *testing.T) { func TestDecodeErrors(t *testing.T) { tests := []struct { - s interface{} + s any toml string wantErr string }{ @@ -460,7 +460,7 @@ func TestDecodeSizedInts(t *testing.T) { type NopUnmarshalTOML int -func (n *NopUnmarshalTOML) UnmarshalTOML(p interface{}) error { +func (n *NopUnmarshalTOML) UnmarshalTOML(p any) error { *n = 42 return nil } @@ -468,22 +468,22 @@ func (n *NopUnmarshalTOML) UnmarshalTOML(p interface{}) error { func TestDecodeTypes(t *testing.T) { type ( mystr string - myiface interface{} + myiface any ) for _, tt := range []struct { - v interface{} + v any want string wantErr string }{ {new(map[string]bool), "&map[F:true]", ""}, {new(map[mystr]bool), "&map[F:true]", ""}, {new(NopUnmarshalTOML), "42", ""}, - {new(map[interface{}]bool), "&map[F:true]", ""}, + {new(map[any]bool), "&map[F:true]", ""}, {new(map[myiface]bool), "&map[F:true]", ""}, {3, "", `toml: cannot decode to non-pointer "int"`}, - {map[string]interface{}{}, "", `toml: cannot decode to non-pointer "map[string]interface {}"`}, + {map[string]any{}, "", `toml: cannot decode to non-pointer "map[string]interface {}"`}, {(*int)(nil), "", `toml: cannot decode to nil value of "*int"`}, {(*Unmarshaler)(nil), "", `toml: cannot decode to nil value of "*toml.Unmarshaler"`}, @@ -557,7 +557,7 @@ name = "Rice" } eggSalad := m.Dishes["eggsalad"] - if _, ok := interface{}(eggSalad).(dish); !ok { + if _, ok := any(eggSalad).(dish); !ok { t.Errorf("expected a dish") } @@ -679,12 +679,12 @@ type menu struct { Dishes map[string]dish } -func (m *menu) UnmarshalTOML(p interface{}) error { +func (m *menu) UnmarshalTOML(p any) error { m.Dishes = make(map[string]dish) - data, _ := p.(map[string]interface{}) - dishes := data["dishes"].(map[string]interface{}) + data, _ := p.(map[string]any) + dishes := data["dishes"].(map[string]any) for n, v := range dishes { - if d, ok := v.(map[string]interface{}); ok { + if d, ok := v.(map[string]any); ok { nd := dish{} nd.UnmarshalTOML(d) m.Dishes[n] = nd @@ -701,13 +701,13 @@ type dish struct { Ingredients []ingredient } -func (d *dish) UnmarshalTOML(p interface{}) error { - data, _ := p.(map[string]interface{}) +func (d *dish) UnmarshalTOML(p any) error { + data, _ := p.(map[string]any) d.Name, _ = data["name"].(string) d.Price, _ = data["price"].(float32) - ingredients, _ := data["ingredients"].([]map[string]interface{}) + ingredients, _ := data["ingredients"].([]map[string]any) for _, e := range ingredients { - n, _ := interface{}(e).(map[string]interface{}) + n, _ := any(e).(map[string]any) name, _ := n["name"].(string) i := ingredient{name} d.Ingredients = append(d.Ingredients, i) @@ -723,9 +723,9 @@ func TestDecodeSlices(t *testing.T) { type ( T struct { Arr []string - Tbl map[string]interface{} + Tbl map[string]any } - M map[string]interface{} + M map[string]any ) tests := []struct { input string @@ -746,7 +746,7 @@ func TestDecodeSlices(t *testing.T) { {`arr = [] tbl = {arr = []}`, T{}, - T{[]string{}, M{"arr": []interface{}{}}}}, + T{[]string{}, M{"arr": []any{}}}}, {`arr = [] tbl = {}`, T{[]string{}, M{}}, @@ -759,15 +759,15 @@ func TestDecodeSlices(t *testing.T) { {`arr = ["x"] tbl = {arr=["y"]}`, T{}, - T{[]string{"x"}, M{"arr": []interface{}{"y"}}}}, + T{[]string{"x"}, M{"arr": []any{"y"}}}}, {`arr = ["x"] tbl = {arr=["y"]}`, T{[]string{}, M{}}, - T{[]string{"x"}, M{"arr": []interface{}{"y"}}}}, + T{[]string{"x"}, M{"arr": []any{"y"}}}}, {`arr = ["x"] tbl = {arr=["y"]}`, - T{[]string{"a", "b"}, M{"arr": []interface{}{"c", "d"}}}, - T{[]string{"x"}, M{"arr": []interface{}{"y"}}}}, + T{[]string{"a", "b"}, M{"arr": []any{"c", "d"}}}, + T{[]string{"x"}, M{"arr": []any{"y"}}}}, } for _, tt := range tests { @@ -794,9 +794,9 @@ func TestDecodePrimitive(t *testing.T) { arrayp := func(a [2]int) *[2]int { return &a } mapp := func(m map[string]int) *map[string]int { return &m } for i, tt := range []struct { - v interface{} + v any input string - want interface{} + want any }{ // slices {slicep(nil), "", slicep(nil)}, @@ -887,7 +887,7 @@ func TestDecodeDatetime(t *testing.T) { func TestDecodeTextUnmarshaler(t *testing.T) { tests := []struct { name string - t interface{} + t any toml string want string }{ @@ -934,7 +934,7 @@ func TestDecodeTextUnmarshaler(t *testing.T) { func TestDecodeDuration(t *testing.T) { tests := []struct { - in interface{} + in any toml, want, wantErr string }{ {&struct{ T time.Duration }{}, `t = "0s"`, @@ -988,7 +988,7 @@ func TestDecodeDuration(t *testing.T) { func TestDecodeJSONNumber(t *testing.T) { tests := []struct { - in interface{} + in any toml, want, wantErr string }{ {&struct{ D json.Number }{}, `D = 2`, "&{2}", ""}, @@ -1021,7 +1021,7 @@ func TestDecodeJSONNumber(t *testing.T) { } func TestMetaDotConflict(t *testing.T) { - var m map[string]interface{} + var m map[string]any meta, err := Decode(` "a.b" = "str" a.b = 1 @@ -1074,7 +1074,7 @@ func (e *Enum) MarshalTOML() ([]byte, error) { return []byte(`"` + e.Value() + `"`), nil } -func (e *Enum) UnmarshalTOML(value interface{}) error { +func (e *Enum) UnmarshalTOML(value any) error { sValue, ok := value.(string) if !ok { return fmt.Errorf("value %v is not a string type", value) @@ -1091,7 +1091,7 @@ func (e *Enum) UnmarshalTOML(value interface{}) error { func (i *InnerInt) MarshalTOML() ([]byte, error) { return []byte(strconv.Itoa(i.value)), nil } -func (i *InnerInt) UnmarshalTOML(value interface{}) error { +func (i *InnerInt) UnmarshalTOML(value any) error { iValue, ok := value.(int64) if !ok { return fmt.Errorf("value %v is not a int type", value) @@ -1104,9 +1104,9 @@ func (as *InnerArrayString) MarshalTOML() ([]byte, error) { return []byte("[\"" + strings.Join(as.value, "\", \"") + "\"]"), nil } -func (as *InnerArrayString) UnmarshalTOML(value interface{}) error { +func (as *InnerArrayString) UnmarshalTOML(value any) error { if value != nil { - asValue, ok := value.([]interface{}) + asValue, ok := value.([]any) if !ok { return fmt.Errorf("value %v is not a [] type", value) } @@ -1207,7 +1207,7 @@ func TestMetaKeys(t *testing.T) { for _, tt := range tests { t.Run("", func(t *testing.T) { - var x interface{} + var x any meta, err := Decode(tt.in, &x) if err != nil { t.Fatal(err) @@ -1232,7 +1232,7 @@ func TestDecodeParallel(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - err := Unmarshal(doc, new(map[string]interface{})) + err := Unmarshal(doc, new(map[string]any)) if err != nil { t.Fatal(err) } diff --git a/deprecated.go b/deprecated.go index b9e30971..9538df2a 100644 --- a/deprecated.go +++ b/deprecated.go @@ -18,7 +18,7 @@ type TextUnmarshaler encoding.TextUnmarshaler // PrimitiveDecode is an alias for MetaData.PrimitiveDecode(). // // Deprecated: use MetaData.PrimitiveDecode. -func PrimitiveDecode(primValue Primitive, v interface{}) error { +func PrimitiveDecode(primValue Primitive, v any) error { md := MetaData{decoded: make(map[string]struct{})} return md.unify(primValue.undecoded, rvalue(v)) } @@ -26,4 +26,4 @@ func PrimitiveDecode(primValue Primitive, v interface{}) error { // DecodeReader is an alias for NewDecoder(r).Decode(v). // // Deprecated: use NewDecoder(reader).Decode(&value). -func DecodeReader(r io.Reader, v interface{}) (MetaData, error) { return NewDecoder(r).Decode(v) } +func DecodeReader(r io.Reader, v any) (MetaData, error) { return NewDecoder(r).Decode(v) } diff --git a/encode.go b/encode.go index 9cd25d75..bb726060 100644 --- a/encode.go +++ b/encode.go @@ -134,7 +134,7 @@ func NewEncoder(w io.Writer) *Encoder { // // An error is returned if the value given cannot be encoded to a valid TOML // document. -func (enc *Encoder) Encode(v interface{}) error { +func (enc *Encoder) Encode(v any) error { rv := eindirect(reflect.ValueOf(v)) err := enc.safeEncode(Key([]string{}), rv) if err != nil { @@ -304,7 +304,7 @@ func (enc *Encoder) eElement(rv reflect.Value) { case reflect.Interface: enc.eElement(rv.Elem()) default: - encPanic(fmt.Errorf("unexpected type: %T", rv.Interface())) + encPanic(fmt.Errorf("unexpected type: %s", fmtType(rv.Interface()))) } } @@ -712,7 +712,7 @@ func (enc *Encoder) writeKeyValue(key Key, val reflect.Value, inline bool) { } } -func (enc *Encoder) wf(format string, v ...interface{}) { +func (enc *Encoder) wf(format string, v ...any) { _, err := fmt.Fprintf(enc.w, format, v...) if err != nil { encPanic(err) diff --git a/encode_test.go b/encode_test.go index 53e59013..8ac72a18 100644 --- a/encode_test.go +++ b/encode_test.go @@ -130,7 +130,7 @@ func TestEncodeOmitEmptyStruct(t *testing.T) { ) tests := []struct { - in interface{} + in any want string }{ {struct { @@ -511,7 +511,7 @@ Data = ["Foo", "Bar"] func TestEncodeError(t *testing.T) { tests := []struct { - in interface{} + in any wantErr string }{ {make(chan int), "unsupported type for key '': chan"}, @@ -754,14 +754,14 @@ func TestEncode32bit(t *testing.T) { func TestEncodeSkipInvalidType(t *testing.T) { buf := new(bytes.Buffer) err := NewEncoder(buf).Encode(struct { - Str string `toml:"str"` - Arr []func() `toml:"-"` - Map map[string]interface{} `toml:"-"` - Func func() `toml:"-"` + Str string `toml:"str"` + Arr []func() `toml:"-"` + Map map[string]any `toml:"-"` + Func func() `toml:"-"` }{ Str: "a", Arr: []func(){func() {}}, - Map: map[string]interface{}{"f": func() {}}, + Map: map[string]any{"f": func() {}}, Func: func() {}, }) if err != nil { @@ -879,7 +879,7 @@ func TestEncode(t *testing.T) { dateStr := "2014-05-11T19:30:40Z" tests := map[string]struct { - input interface{} + input any wantOutput string wantError error }{ @@ -940,7 +940,7 @@ func TestEncode(t *testing.T) { "datetime field as primitive": { // Using a map here to fail if isStructOrMap() returns true for // time.Time. - input: map[string]interface{}{ + input: map[string]any{ "Date": date, "Int": 1, }, @@ -972,8 +972,8 @@ func TestEncode(t *testing.T) { ArrayOfSlices [2][]int SliceOfArraysOfSlices [][2][]int ArrayOfSlicesOfArrays [2][][2]int - SliceOfMixedArrays [][2]interface{} - ArrayOfMixedSlices [2][]interface{} + SliceOfMixedArrays [][2]any + ArrayOfMixedSlices [2][]any }{ [][2]int{{1, 2}, {3, 4}}, [2][]int{{1, 2}, {3, 4}}, @@ -993,10 +993,10 @@ func TestEncode(t *testing.T) { {5, 6}, {7, 8}, }, }, - [][2]interface{}{ + [][2]any{ {1, 2}, {"a", "b"}, }, - [2][]interface{}{ + [2][]any{ {1, 2}, {"a", "b"}, }, }, @@ -1009,44 +1009,44 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]] `, }, "empty slice": { - input: struct{ Empty []interface{} }{[]interface{}{}}, + input: struct{ Empty []any }{[]any{}}, wantOutput: "Empty = []\n", }, "(error) slice with element type mismatch (string and integer)": { - input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}}, + input: struct{ Mixed []any }{[]any{1, "a"}}, wantOutput: "Mixed = [1, \"a\"]\n", }, "(error) slice with element type mismatch (integer and float)": { - input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}}, + input: struct{ Mixed []any }{[]any{1, 2.5}}, wantOutput: "Mixed = [1, 2.5]\n", }, "slice with elems of differing Go types, same TOML types": { input: struct { - MixedInts []interface{} - MixedFloats []interface{} + MixedInts []any + MixedFloats []any }{ - []interface{}{ + []any{ int(1), int8(2), int16(3), int32(4), int64(5), uint(1), uint8(2), uint16(3), uint32(4), uint64(5), }, - []interface{}{float32(1.5), float64(2.5)}, + []any{float32(1.5), float64(2.5)}, }, wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" + "MixedFloats = [1.5, 2.5]\n", }, "(error) slice w/ element type mismatch (one is nested array)": { - input: struct{ Mixed []interface{} }{ - []interface{}{1, []interface{}{2}}, + input: struct{ Mixed []any }{ + []any{1, []any{2}}, }, wantOutput: "Mixed = [1, [2]]\n", }, "(error) slice with 1 nil element": { - input: struct{ NilElement1 []interface{} }{[]interface{}{nil}}, + input: struct{ NilElement1 []any }{[]any{nil}}, wantError: errArrayNilElement, }, "(error) slice with 1 nil element (and other non-nil elements)": { - input: struct{ NilElement []interface{} }{ - []interface{}{1, nil}, + input: struct{ NilElement []any }{ + []any{1, nil}, }, wantError: errArrayNilElement, }, @@ -1054,12 +1054,12 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]] input: map[string]int{"a": 1, "b": 2}, wantOutput: "a = 1\nb = 2\n", }, - "map with interface{} value type": { - input: map[string]interface{}{"a": 1, "b": "c"}, + "map with any value type": { + input: map[string]any{"a": 1, "b": "c"}, wantOutput: "a = 1\nb = \"c\"\n", }, - "map with interface{} value type, some of which are structs": { - input: map[string]interface{}{ + "map with any value type, some of which are structs": { + input: map[string]any{ "a": struct{ Int int }{2}, "b": 1, }, @@ -1163,8 +1163,8 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]] wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n", }, "array of tables order": { - input: map[string]interface{}{ - "map": map[string]interface{}{ + input: map[string]any{ + "map": map[string]any{ "zero": 5, "arr": []map[string]int{ { @@ -1185,7 +1185,7 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]] }, "empty map name": { - input: map[string]interface{}{ + input: map[string]any{ "": map[string]int{"v": 1}, }, wantOutput: "[\"\"]\n v = 1\n", @@ -1207,13 +1207,13 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]] }, "tbl-in-arr-map": { - input: map[string]interface{}{ - "arr": []interface{}{[]interface{}{ - map[string]interface{}{ - "a": []interface{}{"hello", "world"}, - "b": []interface{}{1.12, 4.1}, + input: map[string]any{ + "arr": []any{[]any{ + map[string]any{ + "a": []any{"hello", "world"}, + "b": []any{1.12, 4.1}, "c": 1, - "d": map[string]interface{}{"e": "E"}, + "d": map[string]any{"e": "E"}, "f": struct{ A, B int }{1, 2}, "g": []struct{ A, B int }{{3, 4}, {5, 6}}, }, @@ -1295,7 +1295,7 @@ func TestMarshalDoc(t *testing.T) { }) } -func encodeExpected(t *testing.T, label string, val interface{}, want string, wantErr error) { +func encodeExpected(t *testing.T, label string, val any, want string, wantErr error) { t.Helper() t.Run(label, func(t *testing.T) { t.Helper() diff --git a/error.go b/error.go index efd68865..b4e9a4bf 100644 --- a/error.go +++ b/error.go @@ -168,8 +168,8 @@ type ( errLexInlineTableNL struct{} errLexStringNL struct{} errParseRange struct { - i interface{} // int or float - size string // "int64", "uint16", etc. + i any // int or float + size string // "int64", "uint16", etc. } errParseDuration struct{ d string } ) diff --git a/error_test.go b/error_test.go index 907f34ba..b7e362fc 100644 --- a/error_test.go +++ b/error_test.go @@ -61,7 +61,7 @@ At line 2, column 4-15: t.Fatal(err) } - var x interface{} + var x any _, err = toml.Decode(string(input), &x) if err == nil { t.Fatal("err is nil") @@ -84,7 +84,7 @@ At line 2, column 4-15: func TestParseError(t *testing.T) { tests := []struct { - in interface{} + in any toml, err string }{ { diff --git a/example_test.go b/example_test.go index eb51b4aa..da992c1d 100644 --- a/example_test.go +++ b/example_test.go @@ -15,7 +15,7 @@ func ExampleEncoder_Encode() { date, _ = time.Parse(time.RFC822, "14 Mar 10 18:00 UTC") buf = new(bytes.Buffer) ) - err := toml.NewEncoder(buf).Encode(map[string]interface{}{ + err := toml.NewEncoder(buf).Encode(map[string]any{ "date": date, "counts": []int{1, 1, 2, 3, 5, 8}, "hash": map[string]string{ @@ -268,21 +268,21 @@ func (c *cable) Name() string { return fmt.Sprintf("CABLE: %s", c.ID) } -func (o *order) UnmarshalTOML(data interface{}) error { +func (o *order) UnmarshalTOML(data any) error { // NOTE the example below contains detailed type casting to show how the // 'data' is retrieved. In operational use, a type cast wrapper may be // preferred e.g. // - // func AsMap(v interface{}) (map[string]interface{}, error) { - // return v.(map[string]interface{}) + // func AsMap(v any) (map[string]any, error) { + // return v.(map[string]any) // } // // resulting in: // d, _ := AsMap(data) // - d, _ := data.(map[string]interface{}) - parts, _ := d["parts"].([]map[string]interface{}) + d, _ := data.(map[string]any) + parts, _ := d["parts"].([]map[string]any) for _, p := range parts { diff --git a/fuzz_test.go b/fuzz_test.go index c0162eb5..4502115b 100644 --- a/fuzz_test.go +++ b/fuzz_test.go @@ -1,6 +1,3 @@ -//go:build go1.18 -// +build go1.18 - package toml import ( @@ -67,7 +64,7 @@ distros = [ key = "This table intentionally left undecoded" `) f.Fuzz(func(t *testing.T, file string) { - var m map[string]interface{} + var m map[string]any _, err := Decode(file, &m) if err != nil { t.Skip() diff --git a/internal/tag/add.go b/internal/tag/add.go index 88f69503..07fc138b 100644 --- a/internal/tag/add.go +++ b/internal/tag/add.go @@ -9,7 +9,7 @@ import ( ) // Add JSON tags to a data structure as expected by toml-test. -func Add(key string, tomlData interface{}) interface{} { +func Add(key string, tomlData any) any { // Switch on the data type. switch orig := tomlData.(type) { default: @@ -17,8 +17,8 @@ func Add(key string, tomlData interface{}) interface{} { // A table: we don't need to add any tags, just recurse for every table // entry. - case map[string]interface{}: - typed := make(map[string]interface{}, len(orig)) + case map[string]any: + typed := make(map[string]any, len(orig)) for k, v := range orig { typed[k] = Add(k, v) } @@ -26,14 +26,14 @@ func Add(key string, tomlData interface{}) interface{} { // An array: we don't need to add any tags, just recurse for every table // entry. - case []map[string]interface{}: - typed := make([]map[string]interface{}, len(orig)) + case []map[string]any: + typed := make([]map[string]any, len(orig)) for i, v := range orig { - typed[i] = Add("", v).(map[string]interface{}) + typed[i] = Add("", v).(map[string]any) } return typed - case []interface{}: - typed := make([]interface{}, len(orig)) + case []any: + typed := make([]any, len(orig)) for i, v := range orig { typed[i] = Add("", v) } @@ -68,8 +68,8 @@ func Add(key string, tomlData interface{}) interface{} { } } -func tag(typeName string, data interface{}) map[string]interface{} { - return map[string]interface{}{ +func tag(typeName string, data any) map[string]any { + return map[string]any{ "type": typeName, "value": data, } diff --git a/internal/tag/rm.go b/internal/tag/rm.go index 2647e64f..7659c19c 100644 --- a/internal/tag/rm.go +++ b/internal/tag/rm.go @@ -9,12 +9,12 @@ import ( ) // Remove JSON tags to a data structure as returned by toml-test. -func Remove(typedJson interface{}) (interface{}, error) { +func Remove(typedJson any) (any, error) { // Switch on the data type. switch v := typedJson.(type) { // Object: this can either be a TOML table or a primitive with tags. - case map[string]interface{}: + case map[string]any: // This value represents a primitive: remove the tags and return just // the primitive value. if len(v) == 2 && in("type", v) && in("value", v) { @@ -26,7 +26,7 @@ func Remove(typedJson interface{}) (interface{}, error) { } // Table: remove tags on all children. - m := make(map[string]interface{}, len(v)) + m := make(map[string]any, len(v)) for k, v2 := range v { var err error m[k], err = Remove(v2) @@ -37,8 +37,8 @@ func Remove(typedJson interface{}) (interface{}, error) { return m, nil // Array: remove tags from all items. - case []interface{}: - a := make([]interface{}, len(v)) + case []any: + a := make([]any, len(v)) for i := range v { var err error a[i], err = Remove(v[i]) @@ -54,13 +54,13 @@ func Remove(typedJson interface{}) (interface{}, error) { } // Check if key is in the table m. -func in(key string, m map[string]interface{}) bool { +func in(key string, m map[string]any) bool { _, ok := m[key] return ok } // Return a primitive: read the "type" and convert the "value" to that. -func untag(typed map[string]interface{}) (interface{}, error) { +func untag(typed map[string]any) (any, error) { t := typed["type"].(string) v := typed["value"].(string) switch t { diff --git a/lex.go b/lex.go index 3545a6ad..07eaa43e 100644 --- a/lex.go +++ b/lex.go @@ -270,7 +270,7 @@ func (lx *lexer) errorPos(start, length int, err error) stateFn { } // errorf is like error, and creates a new error. -func (lx *lexer) errorf(format string, values ...interface{}) stateFn { +func (lx *lexer) errorf(format string, values ...any) stateFn { if lx.atEOF { pos := lx.getPos() pos.Line-- diff --git a/meta.go b/meta.go index 2e78b24e..e2db7fc3 100644 --- a/meta.go +++ b/meta.go @@ -13,7 +13,7 @@ type MetaData struct { context Key // Used only during decoding. keyInfo map[string]keyInfo - mapping map[string]interface{} + mapping map[string]any keys []Key decoded map[string]struct{} data []byte // Input file; for errors. @@ -31,12 +31,12 @@ func (md *MetaData) IsDefined(key ...string) bool { } var ( - hash map[string]interface{} + hash map[string]any ok bool - hashOrVal interface{} = md.mapping + hashOrVal any = md.mapping ) for _, k := range key { - if hash, ok = hashOrVal.(map[string]interface{}); !ok { + if hash, ok = hashOrVal.(map[string]any); !ok { return false } if hashOrVal, ok = hash[k]; !ok { diff --git a/parse.go b/parse.go index 9c191536..3cd5ff51 100644 --- a/parse.go +++ b/parse.go @@ -20,9 +20,9 @@ type parser struct { ordered []Key // List of keys in the order that they appear in the TOML data. - keyInfo map[string]keyInfo // Map keyname → info about the TOML key. - mapping map[string]interface{} // Map keyname → key value. - implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names"). + keyInfo map[string]keyInfo // Map keyname → info about the TOML key. + mapping map[string]any // Map keyname → key value. + implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names"). } type keyInfo struct { @@ -71,7 +71,7 @@ func parse(data string) (p *parser, err error) { p = &parser{ keyInfo: make(map[string]keyInfo), - mapping: make(map[string]interface{}), + mapping: make(map[string]any), lx: lex(data, tomlNext), ordered: make([]Key, 0), implicits: make(map[string]struct{}), @@ -97,7 +97,7 @@ func (p *parser) panicErr(it item, err error) { }) } -func (p *parser) panicItemf(it item, format string, v ...interface{}) { +func (p *parser) panicItemf(it item, format string, v ...any) { panic(ParseError{ Message: fmt.Sprintf(format, v...), Position: it.pos, @@ -106,7 +106,7 @@ func (p *parser) panicItemf(it item, format string, v ...interface{}) { }) } -func (p *parser) panicf(format string, v ...interface{}) { +func (p *parser) panicf(format string, v ...any) { panic(ParseError{ Message: fmt.Sprintf(format, v...), Position: p.pos, @@ -139,7 +139,7 @@ func (p *parser) nextPos() item { return it } -func (p *parser) bug(format string, v ...interface{}) { +func (p *parser) bug(format string, v ...any) { panic(fmt.Sprintf("BUG: "+format+"\n\n", v...)) } @@ -239,7 +239,7 @@ var datetimeRepl = strings.NewReplacer( // value translates an expected value from the lexer into a Go value wrapped // as an empty interface. -func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) { +func (p *parser) value(it item, parentIsArray bool) (any, tomlType) { switch it.typ { case itemString: return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it) @@ -274,7 +274,7 @@ func (p *parser) value(it item, parentIsArray bool) (interface{}, tomlType) { panic("unreachable") } -func (p *parser) valueInteger(it item) (interface{}, tomlType) { +func (p *parser) valueInteger(it item) (any, tomlType) { if !numUnderscoresOK(it.val) { p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val) } @@ -298,7 +298,7 @@ func (p *parser) valueInteger(it item) (interface{}, tomlType) { return num, p.typeOfPrimitive(it) } -func (p *parser) valueFloat(it item) (interface{}, tomlType) { +func (p *parser) valueFloat(it item) (any, tomlType) { parts := strings.FieldsFunc(it.val, func(r rune) bool { switch r { case '.', 'e', 'E': @@ -352,7 +352,7 @@ var dtTypes = []struct { {"15:04", internal.LocalTime, true}, } -func (p *parser) valueDatetime(it item) (interface{}, tomlType) { +func (p *parser) valueDatetime(it item) (any, tomlType) { it.val = datetimeRepl.Replace(it.val) var ( t time.Time @@ -375,7 +375,7 @@ func (p *parser) valueDatetime(it item) (interface{}, tomlType) { return t, p.typeOfPrimitive(it) } -func (p *parser) valueArray(it item) (interface{}, tomlType) { +func (p *parser) valueArray(it item) (any, tomlType) { p.setType(p.currentKey, tomlArray, it.pos) var ( @@ -384,7 +384,7 @@ func (p *parser) valueArray(it item) (interface{}, tomlType) { // Initialize to a non-nil empty slice. This makes it consistent with // how S = [] decodes into a non-nil slice inside something like struct // { S []string }. See #338 - array = []interface{}{} + array = []any{} ) for it = p.next(); it.typ != itemArrayEnd; it = p.next() { if it.typ == itemCommentStart { @@ -406,9 +406,9 @@ func (p *parser) valueArray(it item) (interface{}, tomlType) { return array, tomlArray } -func (p *parser) valueInlineTable(it item, parentIsArray bool) (interface{}, tomlType) { +func (p *parser) valueInlineTable(it item, parentIsArray bool) (any, tomlType) { var ( - hash = make(map[string]interface{}) + hash = make(map[string]any) outerContext = p.context outerKey = p.currentKey ) @@ -525,7 +525,7 @@ func (p *parser) addContext(key Key, array bool) { // No key? Make an implicit hash and move on. if !ok { p.addImplicit(keyContext) - hashContext[k] = make(map[string]interface{}) + hashContext[k] = make(map[string]any) } // If the hash context is actually an array of tables, then set @@ -534,9 +534,9 @@ func (p *parser) addContext(key Key, array bool) { // Otherwise, it better be a table, since this MUST be a key group (by // virtue of it not being the last element in a key). switch t := hashContext[k].(type) { - case []map[string]interface{}: + case []map[string]any: hashContext = t[len(t)-1] - case map[string]interface{}: + case map[string]any: hashContext = t default: p.panicf("Key '%s' was already created as a hash.", keyContext) @@ -549,24 +549,24 @@ func (p *parser) addContext(key Key, array bool) { // list of tables for it. k := key[len(key)-1] if _, ok := hashContext[k]; !ok { - hashContext[k] = make([]map[string]interface{}, 0, 4) + hashContext[k] = make([]map[string]any, 0, 4) } // Add a new table. But make sure the key hasn't already been used // for something else. - if hash, ok := hashContext[k].([]map[string]interface{}); ok { - hashContext[k] = append(hash, make(map[string]interface{})) + if hash, ok := hashContext[k].([]map[string]any); ok { + hashContext[k] = append(hash, make(map[string]any)) } else { p.panicf("Key '%s' was already created and cannot be used as an array.", key) } } else { - p.setValue(key[len(key)-1], make(map[string]interface{})) + p.setValue(key[len(key)-1], make(map[string]any)) } p.context = append(p.context, key[len(key)-1]) } // set calls setValue and setType. -func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) { +func (p *parser) set(key string, val any, typ tomlType, pos Position) { p.setValue(key, val) p.setType(key, typ, pos) } @@ -574,9 +574,9 @@ func (p *parser) set(key string, val interface{}, typ tomlType, pos Position) { // setValue sets the given key to the given value in the current context. // It will make sure that the key hasn't already been defined, account for // implicit key groups. -func (p *parser) setValue(key string, value interface{}) { +func (p *parser) setValue(key string, value any) { var ( - tmpHash interface{} + tmpHash any ok bool hash = p.mapping keyContext Key @@ -587,11 +587,11 @@ func (p *parser) setValue(key string, value interface{}) { p.bug("Context for key '%s' has not been established.", keyContext) } switch t := tmpHash.(type) { - case []map[string]interface{}: + case []map[string]any: // The context is a table of hashes. Pick the most recent table // defined as the current hash. hash = t[len(t)-1] - case map[string]interface{}: + case map[string]any: hash = t default: p.panicf("Key '%s' has already been defined.", keyContext) diff --git a/toml_test.go b/toml_test.go index 24794b52..66a8e8f3 100644 --- a/toml_test.go +++ b/toml_test.go @@ -403,7 +403,7 @@ func testMeta(t *testing.T, test tomltest.Test, includeNext bool) { return } - var s interface{} + var s any meta, err := toml.Decode(test.Input, &s) if err != nil { t.Fatal(err) @@ -466,7 +466,7 @@ func (p parser) Encode(input string) (output string, outputIsError bool, retErr } }() - var tmp interface{} + var tmp any err := json.Unmarshal([]byte(input), &tmp) if err != nil { return "", false, err @@ -498,7 +498,7 @@ func (p parser) Decode(input string) (output string, outputIsError bool, retErr } }() - var d interface{} + var d any if _, err := toml.Decode(input, &d); err != nil { return err.Error(), true, retErr }