yvbolt/sqliteclidriver/orderedkv.go
2024-06-30 13:11:54 +12:00

86 lines
1.5 KiB
Go

package sqliteclidriver
import (
"bytes"
"encoding/json"
"fmt"
)
type Pair struct {
Key string
Value any
}
type OrderedKV []Pair
func (o *OrderedKV) UnmarshalJSON(data []byte) error {
// Rough estimate malloc size based on number of `:`
// This is a lower bound since there might be nested elements
var elCount int64
for _, c := range data {
if c == ':' {
elCount += 1
}
}
*o = make([]Pair, 0, elCount)
// Parse the initial opening { delimiter from the JSON stream
reader := bytes.NewReader(data)
dec := json.NewDecoder(reader)
tok, err := dec.Token()
if err != nil {
return fmt.Errorf("expected '{': %w", err)
}
if d, ok := tok.(json.Delim); !ok || (rune(d) != '{') {
return fmt.Errorf("expected '{', got %v", tok)
}
// Read remaining content
for dec.More() {
var p Pair
// Parse key: either string or Delim('}')
tok, err := dec.Token()
if err != nil {
return fmt.Errorf("expected '{': %w", err)
}
switch tok := tok.(type) {
case json.Delim:
if rune(tok) == '}' {
// Finished
break
}
// Something else
return fmt.Errorf("expected string or }, got %v", tok)
case string:
// Valid key
p.Key = tok
default:
return fmt.Errorf("expected string or }, got %v", tok)
}
// Parse value (any)
err = dec.Decode(&p.Value)
if err != nil {
return err
}
*o = append(*o, p)
}
// Assert that there is no remaining content
if reader.Len() != 0 {
return fmt.Errorf("Unexpected trailing data (%d bytes remaining)", reader.Len())
}
// Done
return nil
}