Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f6d0d8be7 | |||
| 3c4b709fed |
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2013 - 2022 Thomas Pelletier, Eric Anderton
|
Copyright (c) 2013 - 2021 Thomas Pelletier, Eric Anderton
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -4,6 +4,17 @@ Go library for the [TOML](https://toml.io/en/) format.
|
|||||||
|
|
||||||
This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0).
|
This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0).
|
||||||
|
|
||||||
|
## Development status
|
||||||
|
|
||||||
|
This is the upcoming major version of go-toml. It is currently in active
|
||||||
|
development. As of release v2.0.0-beta.1, the library has reached feature parity
|
||||||
|
with v1, and fixes a lot known bugs and performance issues along the way.
|
||||||
|
|
||||||
|
If you do not need the advanced document editing features of v1, you are
|
||||||
|
encouraged to try out this version.
|
||||||
|
|
||||||
|
[👉 Roadmap for v2](https://github.com/pelletier/go-toml/discussions/506)
|
||||||
|
|
||||||
[🐞 Bug Reports](https://github.com/pelletier/go-toml/issues)
|
[🐞 Bug Reports](https://github.com/pelletier/go-toml/issues)
|
||||||
|
|
||||||
[💬 Anything else](https://github.com/pelletier/go-toml/discussions)
|
[💬 Anything else](https://github.com/pelletier/go-toml/discussions)
|
||||||
|
|||||||
@@ -11,6 +11,5 @@ func TestEntrySize(t *testing.T) {
|
|||||||
// Validate no regression on the size of entry{}. This is a critical bit for
|
// Validate no regression on the size of entry{}. This is a critical bit for
|
||||||
// performance of unmarshaling documents. Should only be increased with care
|
// performance of unmarshaling documents. Should only be increased with care
|
||||||
// and a very good reason.
|
// and a very good reason.
|
||||||
maxExpectedEntrySize := 48
|
require.LessOrEqual(t, 48, int(unsafe.Sizeof(entry{})))
|
||||||
require.LessOrEqual(t, int(unsafe.Sizeof(entry{})), maxExpectedEntrySize)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+89
-12
@@ -230,15 +230,6 @@ func (d *decoder) fromParser(root reflect.Value) error {
|
|||||||
return d.p.Error()
|
return d.p.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Rules for the unmarshal code:
|
|
||||||
|
|
||||||
- The stack is used to keep track of which values need to be set where.
|
|
||||||
- handle* functions <=> switch on a given ast.Kind.
|
|
||||||
- unmarshalX* functions need to unmarshal a node of kind X.
|
|
||||||
- An "object" is either a struct or a map.
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
|
func (d *decoder) handleRootExpression(expr *ast.Node, v reflect.Value) error {
|
||||||
var x reflect.Value
|
var x reflect.Value
|
||||||
var err error
|
var err error
|
||||||
@@ -400,6 +391,84 @@ func (d *decoder) handleArrayTableCollection(key ast.Iterator, v reflect.Value)
|
|||||||
return d.handleArrayTable(key, v)
|
return d.handleArrayTable(key, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *decoder) handleKeyValuePartMapStringInterface(key ast.Iterator, value *ast.Node, m map[string]interface{}) (reflect.Value, error) {
|
||||||
|
k := string(key.Node().Data)
|
||||||
|
|
||||||
|
newMap := false
|
||||||
|
if m == nil {
|
||||||
|
newMap = true
|
||||||
|
m = make(map[string]interface{}, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
set := false
|
||||||
|
v, ok := m[k]
|
||||||
|
if !ok || key.IsLast() {
|
||||||
|
set = true
|
||||||
|
v = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mv := reflect.ValueOf(&v).Elem()
|
||||||
|
|
||||||
|
x, err := d.handleKeyValueInner(key, value, mv)
|
||||||
|
if err != nil {
|
||||||
|
return reflect.Value{}, err
|
||||||
|
}
|
||||||
|
if x.IsValid() {
|
||||||
|
mv = x
|
||||||
|
set = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if set {
|
||||||
|
m[k] = mv.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
if newMap {
|
||||||
|
return reflect.ValueOf(m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.Value{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) handleKeyPartMapStringInterface(key ast.Iterator, m map[string]interface{}, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
|
||||||
|
newMap := false
|
||||||
|
|
||||||
|
k := string(key.Node().Data)
|
||||||
|
if m == nil {
|
||||||
|
newMap = true
|
||||||
|
m = make(map[string]interface{}, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := m[k]
|
||||||
|
set := false
|
||||||
|
|
||||||
|
if !ok || v == nil {
|
||||||
|
set = true
|
||||||
|
v = makeFn().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
mv := reflect.ValueOf(v)
|
||||||
|
|
||||||
|
x, err := nextFn(key, mv)
|
||||||
|
if err != nil {
|
||||||
|
return reflect.Value{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.IsValid() {
|
||||||
|
mv = x
|
||||||
|
set = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if set {
|
||||||
|
m[k] = mv.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
if newMap {
|
||||||
|
return reflect.ValueOf(m), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.Value{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
|
func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
|
||||||
var rv reflect.Value
|
var rv reflect.Value
|
||||||
|
|
||||||
@@ -416,6 +485,11 @@ func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handle
|
|||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
vt := v.Type()
|
vt := v.Type()
|
||||||
|
|
||||||
|
if vt == mapStringInterfaceType {
|
||||||
|
m := v.Interface().(map[string]interface{})
|
||||||
|
return d.handleKeyPartMapStringInterface(key, m, nextFn, makeFn)
|
||||||
|
}
|
||||||
|
|
||||||
// Create the key for the map element. Convert to key type.
|
// Create the key for the map element. Convert to key type.
|
||||||
mk := reflect.ValueOf(string(key.Node().Data)).Convert(vt.Key())
|
mk := reflect.ValueOf(string(key.Node().Data)).Convert(vt.Key())
|
||||||
|
|
||||||
@@ -999,6 +1073,11 @@ func (d *decoder) handleKeyValuePart(key ast.Iterator, value *ast.Node, v reflec
|
|||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
vt := v.Type()
|
vt := v.Type()
|
||||||
|
|
||||||
|
if vt == mapStringInterfaceType {
|
||||||
|
m := v.Interface().(map[string]interface{})
|
||||||
|
return d.handleKeyValuePartMapStringInterface(key, value, m)
|
||||||
|
}
|
||||||
|
|
||||||
mk := reflect.ValueOf(string(key.Node().Data))
|
mk := reflect.ValueOf(string(key.Node().Data))
|
||||||
mkt := stringType
|
mkt := stringType
|
||||||
|
|
||||||
@@ -1022,13 +1101,11 @@ func (d *decoder) handleKeyValuePart(key ast.Iterator, value *ast.Node, v reflec
|
|||||||
if !mv.IsValid() {
|
if !mv.IsValid() {
|
||||||
set = true
|
set = true
|
||||||
mv = reflect.New(v.Type().Elem()).Elem()
|
mv = reflect.New(v.Type().Elem()).Elem()
|
||||||
} else {
|
} else if key.IsLast() {
|
||||||
if key.IsLast() {
|
|
||||||
var x interface{}
|
var x interface{}
|
||||||
mv = reflect.ValueOf(&x).Elem()
|
mv = reflect.ValueOf(&x).Elem()
|
||||||
set = true
|
set = true
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
nv, err := d.handleKeyValueInner(key, value, mv)
|
nv, err := d.handleKeyValueInner(key, value, mv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user