Update to new struct layout
Also cleanup the code so it's a bit more linear.
This commit is contained in:
parent
2bc40b4a39
commit
dddbd36969
@ -17,14 +17,13 @@ func main() {
|
|||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
output := []common.Foo{}
|
output, err := decoder.DecodeFooArray(f)
|
||||||
|
if err != nil {
|
||||||
if err := decoder.DecodeArray(f, &output); err != nil {
|
|
||||||
fmt.Printf("Error decoding input: %v\n", err)
|
fmt.Printf("Error decoding input: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common.PrintMemUsage()
|
common.PrintMemUsage()
|
||||||
|
|
||||||
fmt.Printf("got array with %d items\n", len(output))
|
fmt.Printf("got array with %d items\n", len(output.Entries))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,46 +6,111 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/cmd/jsondebug/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
arrayOpen = "["
|
objectOpen = "{"
|
||||||
arrayClose = "]"
|
objectClose = "}"
|
||||||
|
arrayOpen = "["
|
||||||
|
arrayClose = "]"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DecodeArray[T any](r io.Reader, output *[]T) error {
|
var errEOF = clues.New("unexpected end of input")
|
||||||
dec := json.NewDecoder(r)
|
|
||||||
arrayStarted := false
|
|
||||||
|
|
||||||
for {
|
func expectDelimToken(dec *json.Decoder, expectedToken string) error {
|
||||||
|
t, err := dec.Token()
|
||||||
|
if err == io.EOF {
|
||||||
|
return clues.Wrap(errEOF, "")
|
||||||
|
} else if err != nil {
|
||||||
|
return clues.Wrap(err, "reading JSON token")
|
||||||
|
}
|
||||||
|
|
||||||
|
d, ok := t.(json.Delim)
|
||||||
|
if !ok {
|
||||||
|
return clues.New(fmt.Sprintf("unexpected token: (%T) %v", t, t))
|
||||||
|
} else if d.String() != expectedToken {
|
||||||
|
return clues.New(fmt.Sprintf(
|
||||||
|
"unexpected token; wanted %s, got %s",
|
||||||
|
expectedToken,
|
||||||
|
d,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeFooArray(r io.Reader) (common.FooArray, error) {
|
||||||
|
var (
|
||||||
|
dec = json.NewDecoder(r)
|
||||||
|
res = common.FooArray{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := expectDelimToken(dec, objectOpen); err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to manually decode fields here since we can't reuse the stdlib
|
||||||
|
// decoder due to memory issues.
|
||||||
|
if err := parseFields(dec, &res); err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consumes closing object curly brace after we're done. Don't need to check
|
||||||
|
// for EOF because json.Decode only guarantees decoding the next JSON item in
|
||||||
|
// the stream so this follows that.
|
||||||
|
return res, expectDelimToken(dec, objectClose)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFields(dec *json.Decoder, res *common.FooArray) error {
|
||||||
|
for dec.More() {
|
||||||
t, err := dec.Token()
|
t, err := dec.Token()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
// Done processing input.
|
return clues.Wrap(errEOF, "")
|
||||||
break
|
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return clues.Wrap(err, "reading JSON token")
|
return clues.Wrap(err, "reading JSON token")
|
||||||
}
|
}
|
||||||
|
|
||||||
d, ok := t.(json.Delim)
|
l, ok := t.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return clues.New(fmt.Sprintf("unexpected token: (%T) %v", t, t))
|
return clues.New(fmt.Sprintf(
|
||||||
} else if arrayStarted && d.String() == arrayClose {
|
"unexpected token (%T) %v; wanted field name",
|
||||||
break
|
t,
|
||||||
} else if d.String() != arrayOpen {
|
t,
|
||||||
return clues.New(fmt.Sprintf("expected array start but found %s", d))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayStarted = true
|
// Only have `entries` field right now. Needs to match the JSON tag for the
|
||||||
|
// struct.
|
||||||
|
if l != "entries" {
|
||||||
|
return clues.New(fmt.Sprintf("unexpected field name %s", l))
|
||||||
|
}
|
||||||
|
|
||||||
for dec.More() {
|
if err = decodeArray(dec, &res.Entries); err != nil {
|
||||||
tmp := *new(T)
|
return err
|
||||||
if err := dec.Decode(&tmp); err != nil {
|
|
||||||
return clues.Wrap(err, "decoding array element")
|
|
||||||
}
|
|
||||||
|
|
||||||
*output = append(*output, tmp)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeArray[T any](dec *json.Decoder, output *[]T) error {
|
||||||
|
// Consume starting bracket.
|
||||||
|
if err := expectDelimToken(dec, arrayOpen); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read elements.
|
||||||
|
for dec.More() {
|
||||||
|
tmp := *new(T)
|
||||||
|
if err := dec.Decode(&tmp); err != nil {
|
||||||
|
return clues.Wrap(err, "decoding array element")
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = append(*output, tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume ending bracket.
|
||||||
|
return expectDelimToken(dec, arrayClose)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user