Assisted-by: DeepSeek V4.1 Flash
This commit is contained in:
+49
-20
@@ -11,9 +11,10 @@
|
||||
//
|
||||
// out, err := interpres.Marshal(cfg)
|
||||
//
|
||||
// or, for an untyped tree:
|
||||
// or, for the document with its key order and comments:
|
||||
//
|
||||
// tree, err := interpres.Parse(data)
|
||||
// doc, err := interpres.Parse(data)
|
||||
// tree := doc.Map()
|
||||
//
|
||||
// A Decoder allows strict decoding that rejects keys without a matching
|
||||
// struct field, mirroring (*json.Decoder).DisallowUnknownFields.
|
||||
@@ -89,22 +90,41 @@ func (e *EncodeError) Error() string { return "interpres: " + e.Path + ": " + e.
|
||||
// Unwrap returns the failure the path points at.
|
||||
func (e *EncodeError) Unwrap() error { return e.Err }
|
||||
|
||||
// Parse decodes a TOML document into a nested map[string]any.
|
||||
// Parse decodes a TOML document into a Document: the values, the order the
|
||||
// keys were written in, whether a table was written inline, and the comments.
|
||||
// ParseMap gives the plain value tree instead.
|
||||
//
|
||||
// Values are mapped to Go types as follows: strings to string, integers to
|
||||
// int64, floats to float64, booleans to bool, date-times to time.Time, arrays
|
||||
// to []any, and tables (including inline tables) to map[string]any.
|
||||
// int64, floats to float64, booleans to bool, offset date-times to
|
||||
// OffsetDateTime, the local date-time kinds to their wrappers, arrays to
|
||||
// []any, and tables (including inline tables) to map[string]any.
|
||||
//
|
||||
// Parse is equivalent to ParseContext with context.Background.
|
||||
func Parse(data []byte) (map[string]any, error) {
|
||||
func Parse(data []byte) (*Document, error) {
|
||||
return ParseContext(context.Background(), data)
|
||||
}
|
||||
|
||||
// ParseContext decodes a TOML document into a nested map[string]any, obeying
|
||||
// ctx. The context is checked between top-level statements so cancellation is
|
||||
// honoured before the parser has done substantial work.
|
||||
func ParseContext(ctx context.Context, data []byte) (map[string]any, error) {
|
||||
return parseWithOptions(ctx, data, parseOptions{})
|
||||
// ParseContext decodes a TOML document into a Document, obeying ctx. The
|
||||
// context is checked between top-level statements so cancellation is honoured
|
||||
// before the parser has done substantial work.
|
||||
func ParseContext(ctx context.Context, data []byte) (*Document, error) {
|
||||
_, doc, err := parseWithOptions(ctx, data, parseOptions{}, true)
|
||||
return doc, err
|
||||
}
|
||||
|
||||
// ParseMap decodes a TOML document into a nested map[string]any, the value
|
||||
// tree without the order and the comments a Document carries. It is the shape
|
||||
// this package parsed into before [Document] existed.
|
||||
//
|
||||
// ParseMap is equivalent to ParseMapContext with context.Background.
|
||||
func ParseMap(data []byte) (map[string]any, error) {
|
||||
return ParseMapContext(context.Background(), data)
|
||||
}
|
||||
|
||||
// ParseMapContext is the cancellable variant of ParseMap.
|
||||
func ParseMapContext(ctx context.Context, data []byte) (map[string]any, error) {
|
||||
tree, _, err := parseWithOptions(ctx, data, parseOptions{}, false)
|
||||
return tree, err
|
||||
}
|
||||
|
||||
// parseOptions bound the work one parse may do. A zero field takes the
|
||||
@@ -114,15 +134,17 @@ type parseOptions struct {
|
||||
maxInputSize int
|
||||
}
|
||||
|
||||
func parseWithOptions(ctx context.Context, data []byte, opts parseOptions) (map[string]any, error) {
|
||||
// parseWithOptions parses data, building the node tree of a Document when
|
||||
// wantDoc asks for it, and returns both the value tree and that document.
|
||||
func parseWithOptions(ctx context.Context, data []byte, opts parseOptions, wantDoc bool) (map[string]any, *Document, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if opts.maxInputSize > 0 && len(data) > opts.maxInputSize {
|
||||
return nil, fmt.Errorf("interpres: input is %d bytes, over the limit of %d", len(data), opts.maxInputSize)
|
||||
return nil, nil, fmt.Errorf("interpres: input is %d bytes, over the limit of %d", len(data), opts.maxInputSize)
|
||||
}
|
||||
if !utf8.Valid(data) {
|
||||
return nil, &SyntaxError{Line: 1, Msg: "input is not valid UTF-8"}
|
||||
return nil, nil, &SyntaxError{Line: 1, Msg: "input is not valid UTF-8"}
|
||||
}
|
||||
maxDepth := opts.maxDepth
|
||||
if maxDepth <= 0 {
|
||||
@@ -130,8 +152,15 @@ func parseWithOptions(ctx context.Context, data []byte, opts parseOptions) (map[
|
||||
}
|
||||
// The parser scans data in place; it only reads the buffer, and every
|
||||
// string it stores in the tree is copied out of it.
|
||||
p := &parser{src: data, line: 1, ctx: ctx, maxDepth: maxDepth}
|
||||
return p.parse()
|
||||
p := &parser{src: data, line: 1, ctx: ctx, maxDepth: maxDepth, wantDoc: wantDoc}
|
||||
tree, err := p.parse()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !wantDoc {
|
||||
return tree, nil, nil
|
||||
}
|
||||
return tree, &Document{root: p.doc, footer: p.footer}, nil
|
||||
}
|
||||
|
||||
// Unmarshal parses a TOML document and stores the result in the value pointed
|
||||
@@ -153,7 +182,7 @@ func Unmarshal(data []byte, v any) error {
|
||||
|
||||
// UnmarshalContext is the cancellable variant of Unmarshal.
|
||||
func UnmarshalContext(ctx context.Context, data []byte, v any) error {
|
||||
tree, err := ParseContext(ctx, data)
|
||||
tree, err := ParseMapContext(ctx, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -210,10 +239,10 @@ func (d *Decoder) Decode(data []byte, v any) error {
|
||||
|
||||
// DecodeContext is the cancellable variant of Decode.
|
||||
func (d *Decoder) DecodeContext(ctx context.Context, data []byte, v any) error {
|
||||
tree, err := parseWithOptions(ctx, data, parseOptions{
|
||||
tree, _, err := parseWithOptions(ctx, data, parseOptions{
|
||||
maxDepth: d.maxDepth,
|
||||
maxInputSize: d.maxInputSize,
|
||||
})
|
||||
}, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user