Implement bytes-based Unmarshaler interface for tables and arrays (#873)

This change brings back support for the unstable.Unmarshaler interface
for tables and array tables, addressing issue #873.

Key changes:
- Changed UnmarshalTOML signature from (*Node) to ([]byte) to provide
  raw TOML bytes instead of AST nodes
- Added RawMessage type (similar to json.RawMessage) for capturing raw
  TOML bytes for later processing
- Updated handleKeyValuesUnmarshaler to reconstruct key-value lines
  from the parsed keys and raw value bytes
- Added support for slice types implementing Unmarshaler (e.g., RawMessage)
- Removed unused AST helper functions from unstable/ast.go

The bytes-based interface allows users to:
- Get raw TOML bytes for custom parsing
- Delay TOML decoding using RawMessage
- Implement custom unmarshaling logic for complex types

Tests added for:
- Table unmarshaler with various scenarios
- Array table unmarshaler
- Split tables (same parent defined in multiple places)
- RawMessage usage
- Nested tables and mixed regular fields
This commit is contained in:
Claude
2026-01-15 12:13:14 +00:00
parent 5b6828661c
commit 2762e24a9c
4 changed files with 202 additions and 189 deletions
-46
View File
@@ -143,49 +143,3 @@ func (n *Node) Value() *Node {
func (n *Node) Children() Iterator {
return Iterator{nodes: n.nodes, idx: n.child}
}
// SetNodeSlice sets the backing nodes slice for a node.
// This is used when building synthetic nodes.
func SetNodeSlice(n *Node, nodes *[]Node) {
n.nodes = nodes
}
// SetNodeChild sets the child index for a node.
// This is used when building synthetic nodes.
func SetNodeChild(n *Node, child int32) {
n.child = child
}
// SetNodeNext sets the next sibling index for a node.
// This is used when building synthetic nodes.
func SetNodeNext(n *Node, next int32) {
n.next = next
}
// GetNodeChild returns the child index for a node.
// This is used when copying nodes.
func GetNodeChild(n *Node) int32 {
return n.child
}
// GetNodeNext returns the next sibling index for a node.
// This is used when copying nodes.
func GetNodeNext(n *Node) int32 {
return n.next
}
// GetNodeIndex returns the index of node n in the backing slice,
// using relativeTo's nodes slice as reference.
// Returns -1 if n is not in the slice.
func GetNodeIndex(n *Node, relativeTo *Node) int32 {
if relativeTo.nodes == nil || n == nil {
return -1
}
nodes := *relativeTo.nodes
for i := range nodes {
if &nodes[i] == n {
return int32(i)
}
}
return -1
}