Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -46,6 +46,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
(10000 levels, which no hand-written document approaches): a document that
|
||||
nests arrays or inline tables deeper used to run the stack out and is now
|
||||
rejected with a `SyntaxError` naming the limit.
|
||||
- `ParseAs[T](data)`, the generic one-line decode, and `NewSchema[T]()`,
|
||||
which precompiles the struct schema and the interface flags for a hot path
|
||||
before the first document arrives.
|
||||
- `OrderedMap`, the string-keyed table that remembers the order its keys were
|
||||
set in: decoding into one fills it in the order the document wrote the
|
||||
keys, and `Marshal` writes one back in that order, where a map carries no
|
||||
|
||||
+17
@@ -80,6 +80,23 @@ The one-shot form of a configured `Decoder`: the same options as
|
||||
The zero value takes the defaults: unknown keys ignored, numbers evaluated
|
||||
as `int64` and `float64`, no size limit and the 10000-level nesting default.
|
||||
|
||||
### `func ParseAs[T any](data []byte) (T, error)`
|
||||
|
||||
The generic shorthand for `Unmarshal` with a destination variable:
|
||||
|
||||
```go
|
||||
cfg, err := interpres.ParseAs[Config](data)
|
||||
```
|
||||
|
||||
The zero `T` comes back with the error.
|
||||
|
||||
### `func NewSchema[T any]()`
|
||||
|
||||
Precompiles the codec for `T`: the struct schema both directions walk and the
|
||||
interface flags the decoder and encoder resolve through are built once and
|
||||
cached, so the first document pays the cost instead of the hot path. A `T`
|
||||
that is not a struct warms nothing.
|
||||
|
||||
## Documents
|
||||
|
||||
`Parse` returns a `Document`: the value tree together with what a map cannot
|
||||
|
||||
@@ -270,6 +270,36 @@ func Unmarshal(data []byte, v any) error {
|
||||
return UnmarshalContext(context.Background(), data, v)
|
||||
}
|
||||
|
||||
// ParseAs decodes a TOML document into T in one call, the generic shorthand
|
||||
// for Unmarshal with a destination variable:
|
||||
//
|
||||
// cfg, err := interpres.ParseAs[Config](data)
|
||||
//
|
||||
// The zero T comes back with the error.
|
||||
func ParseAs[T any](data []byte) (T, error) {
|
||||
var v T
|
||||
err := Unmarshal(data, &v)
|
||||
return v, err
|
||||
}
|
||||
|
||||
// NewSchema precompiles the codec for T: the struct schema both directions
|
||||
// walk and the interface flags the decoder and the encoder resolve through
|
||||
// are built once and cached, so the first document pays the cost instead of
|
||||
// the hot path. A T that is not a struct warms nothing; there is nothing to
|
||||
// precompute for a map or a slice.
|
||||
func NewSchema[T any]() {
|
||||
t := reflect.TypeFor[T]()
|
||||
if t.Kind() != reflect.Struct {
|
||||
return
|
||||
}
|
||||
cachedStructSchema(t)
|
||||
_ = typeFlags(t)
|
||||
_ = encTypeFlags(t)
|
||||
pt := reflect.PointerTo(t)
|
||||
_ = typeFlags(pt)
|
||||
_ = encTypeFlags(pt)
|
||||
}
|
||||
|
||||
// UnmarshalContext is the cancellable variant of Unmarshal.
|
||||
func UnmarshalContext(ctx context.Context, data []byte, v any) error {
|
||||
// Only a destination that can reach an OrderedMap needs the node tree the
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -773,3 +774,25 @@ func TestValid(t *testing.T) {
|
||||
t.Errorf("Valid(invalid) = %v, want a SyntaxError", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseAsAndNewSchema(t *testing.T) {
|
||||
type Config struct {
|
||||
Host string `toml:"host"`
|
||||
Port int `toml:"port"`
|
||||
}
|
||||
cfg, err := ParseAs[Config]([]byte("host = \"db\"\nport = 5432\n"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cfg.Host != "db" || cfg.Port != 5432 {
|
||||
t.Errorf("decoded %+v", cfg)
|
||||
}
|
||||
if _, err := ParseAs[Config]([]byte("port =\n")); err == nil {
|
||||
t.Error("ParseAs(invalid) succeeded, want an error and the zero value")
|
||||
}
|
||||
NewSchema[Config]()
|
||||
if _, ok := structSchemaCache.Load(reflect.TypeFor[Config]()); !ok {
|
||||
t.Error("NewSchema left no schema in the cache")
|
||||
}
|
||||
NewSchema[map[string]any]() // must not panic
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user