perf(decode): parse struct destinations without the value tree
Test / test (push) Successful in 1m50s

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-22 15:59:03 +02:00
parent ee32490452
commit a7d0041259
7 changed files with 1971 additions and 6 deletions
+26 -6
View File
@@ -305,14 +305,22 @@ func NewSchema[T any]() {
// UnmarshalContext is the cancellable variant of Unmarshal.
func UnmarshalContext(ctx context.Context, data []byte, v any) error {
dec := newDecoder()
dec.ctx = ctx
if canTargetDecode(v) {
// The targeted parse fills struct destinations without the
// intermediate tree; a document or destination it cannot model falls
// back to the tree path, whose contracts it keeps.
if err := parseIntoTargeted(ctx, data, dec, false, 0, v); err != errTargetFallback {
return err
}
}
// Only a destination that can reach an OrderedMap needs the node tree the
// written key order is read from; every other decode skips building it.
tree, doc, err := parseWithOptions(ctx, data, parseOptions{}, typeWantsOrder(reflect.TypeOf(v)))
if err != nil {
return err
}
dec := newDecoder()
dec.ctx = ctx
dec.nodes = indexNodes(doc.Root())
return dec.decode(tree, v)
}
@@ -390,6 +398,22 @@ 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 {
dec := newDecoder()
dec.disallowUnknown = d.disallowUnknown
dec.ctx = ctx
dec.loc = d.localLoc
if canTargetDecode(v) {
// The targeted parse fills struct destinations without the
// intermediate tree; a document or destination it cannot model falls
// back to the tree path, whose contracts it keeps. The size limit is
// checked here, the targeted parse being the parse itself.
if d.maxInputSize > 0 && len(data) > d.maxInputSize {
return fmt.Errorf("interpres: input is %d bytes, over the limit of %d", len(data), d.maxInputSize)
}
if err := parseIntoTargeted(ctx, data, dec, d.useNumber, d.maxDepth, v); err != errTargetFallback {
return err
}
}
opts := parseOptions{
maxDepth: d.maxDepth,
maxInputSize: d.maxInputSize,
@@ -399,11 +423,7 @@ func (d *Decoder) DecodeContext(ctx context.Context, data []byte, v any) error {
if err != nil {
return err
}
dec := newDecoder()
dec.disallowUnknown = d.disallowUnknown
dec.ctx = ctx
dec.nodes = indexNodes(doc.Root())
dec.loc = d.localLoc
return dec.decode(tree, v)
}