86 lines
1.5 KiB
Go
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
|
|
}
|