From a047b135ca416584178a6adde64cc156ab637431 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 27 Jan 2020 19:35:32 -0500 Subject: Have RRD.UnmarshalBinary() avoid parsing things repeatedly --- rrdformat/format.go | 1 - rrdformat/rrdbinary/decode.go | 319 +++++++++++++++++++++++++++++++++++++++ rrdformat/rrdbinary/unmarshal.go | 305 ------------------------------------- rrdformat/unmarshal_binary.go | 79 ++++++---- 4 files changed, 369 insertions(+), 335 deletions(-) create mode 100644 rrdformat/rrdbinary/decode.go delete mode 100644 rrdformat/rrdbinary/unmarshal.go diff --git a/rrdformat/format.go b/rrdformat/format.go index f9b8504..2900ce8 100644 --- a/rrdformat/format.go +++ b/rrdformat/format.go @@ -70,7 +70,6 @@ type TimeWithUsec struct { type TimeWithoutUsec struct { Sec rrdbinary.Time - Usec rrdbinary.Int `rrdbinary:"-"` } type PDPPrep struct { diff --git a/rrdformat/rrdbinary/decode.go b/rrdformat/rrdbinary/decode.go new file mode 100644 index 0000000..f3ae80e --- /dev/null +++ b/rrdformat/rrdbinary/decode.go @@ -0,0 +1,319 @@ +package rrdbinary + +import ( + "bytes" + "fmt" + "math" + "reflect" + "strconv" + "strings" +) + +type Decoder struct { + arch Architecture + pos int + data []byte +} + +func NewDecoder(arch Architecture, data []byte) *Decoder { + return &Decoder{ + arch: arch, + pos: 0, + data: data, + } +} + +type unmarshaler interface { + unmarshalRRD(d *Decoder, tag string) error +} + +func Unmarshal(arch Architecture, data []byte, ptr interface{}) error { + decoder := NewDecoder(arch, data) + if err := decoder.Decode(ptr, ""); err != nil { + return err + } + if err := decoder.Decode(&EOF{}, ""); err != nil { + return err + } + return nil +} + +func (d *Decoder) binError(ctxLen int, msg string) error { + return NewBinError(msg, d.data, d.pos, ctxLen) +} + +func (d *Decoder) binErrorf(ctxLen int, format string, a ...interface{}) error { + return d.binError(ctxLen, fmt.Sprintf(format, a...)) +} + +func (d *Decoder) Decode(ptr interface{}, tag string) error { + ptrValue := reflect.ValueOf(ptr) + if ptrValue.Kind() != reflect.Ptr { + return typeErrorf("ptr is a %v, not a pointer", ptrValue.Kind()) + } + return d.decode(ptrValue, tag) +} + +func (d *Decoder) decode(v reflect.Value, tag string) error { + if v.CanInterface() { + if u, ok := v.Interface().(unmarshaler); ok { + return u.unmarshalRRD(d, tag) + } + } + switch v.Type().Kind() { + case reflect.Struct: + return d.decodeStruct(v, tag) + case reflect.Array, reflect.Slice: + return d.decodeList(v, tag) + default: + return typeErrorf("invalid type for rrdbinary.Decoder: %v", v.Type()) + } +} + +func (d *Decoder) decodeStruct(v reflect.Value, tag string) error { + panicUnless(v.Kind() == reflect.Struct) + panicUnless(v.CanSet()) + + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for struct: %q", tag) + } + + for i := 0; i < v.NumField(); i++ { + fieldInfo := v.Type().Field(i) + tag := fieldInfo.Tag.Get("rrdbinary") + if tag == "-" { + continue + } + if err := d.decode(v.Field(i), tag); err != nil { + return fmt.Errorf("field %s: %w", fieldInfo.Name, err) + } + } + return nil +} + +func (d *Decoder) decodeList(v reflect.Value, tag string) error { + panicUnless(v.Kind() == reflect.Array || v.Kind() == reflect.Slice) + panicUnless(v.CanSet()) + + for i := 0; i < v.Len(); i++ { + if err := d.decode(v.Index(i), tag); err != nil { + return fmt.Errorf("index %d: %w", i, err) + } + } + return nil +} + +func (obj *String) unmarshalRRD(d *Decoder, tag string) error { + size := 0 + switch { + case tag == "": + // do nothing + case strings.HasPrefix(tag, "size="): + var err error + size, err = strconv.Atoi(strings.TrimPrefix(tag, "size=")) + if err != nil { + return typeErrorf("invalid rrdbinary struct tag for string: %q", tag) + } + default: + return typeErrorf("invalid rrdbinary struct tag for string: %q", tag) + } + + data := d.data[d.pos:] + if size > 0 { + if len(data) < size { + return d.binErrorf(size, "unexpected end-of-file in %d-byte string", size) + } + data = data[:size] + } + + nul := bytes.IndexByte(data, 0) + if nul < 0 { + if size > 0 { + return d.binErrorf(size, "missing null-terminator on %d-byte string", size) + } else { + return d.binErrorf(16, "unexpected end-of-file looking for null-terminator on string") + } + } + + if size > 0 { + for _, byte := range data[nul:] { + if byte != 0 { + return d.binErrorf(size, "garbage data after null-terminator on fixed %d-byte string", size) + } + } + } else { + size = nul + 1 + } + + *obj = String(data[:nul]) + d.pos += size + return nil +} + +func (obj *Float) unmarshalRRD(d *Decoder, tag string) error { + if d.arch.FloatWidth != 8 { + return archErrorf("rrdbinary does not support FloatWidth=%d; only supports 8", d.arch.FloatWidth) + } + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for float: %q", tag) + } + + data := d.data[d.pos:] + + padding := 0 + if d.pos%d.arch.FloatAlign != 0 { + padding = d.arch.FloatAlign - (d.pos % d.arch.FloatAlign) + } + if len(data) < padding { + return d.binErrorf(padding+d.arch.FloatWidth, "unexpected end-of-file in %d-byte padding-before-float", padding) + } + data = data[padding:] + + if len(data) < d.arch.FloatWidth { + return d.binErrorf(d.arch.FloatWidth, "unexpected end-of-file in %d-byte float", d.arch.FloatWidth) + } + + *obj = Float(math.Float64frombits(d.arch.ByteOrder.Uint64(data))) + d.pos += padding + d.arch.FloatWidth + return nil +} + +func (obj *Uint) unmarshalRRD(d *Decoder, tag string) error { + if d.arch.IntWidth != 4 && d.arch.IntWidth != 8 { + return archErrorf("rrdbinary does not support IntWidth=%d; only supports 4 or 8", d.arch.IntWidth) + } + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for uint: %q", tag) + } + + data := d.data[d.pos:] + + padding := 0 + if d.pos%d.arch.IntAlign != 0 { + padding = d.arch.IntAlign - (d.pos % d.arch.IntAlign) + } + if len(data) < padding { + return d.binErrorf(padding+d.arch.IntWidth, "unexpected end-of-file in %d-byte padding-before-uint", padding) + } + data = data[padding:] + + if len(data) < d.arch.IntWidth { + return d.binErrorf(d.arch.IntWidth, "unexpected end-of-file in %d-byte uint", d.arch.IntWidth) + } + + switch d.arch.IntWidth { + case 4: + *obj = Uint(d.arch.ByteOrder.Uint32(data)) + case 8: + *obj = Uint(d.arch.ByteOrder.Uint64(data)) + } + d.pos += padding + d.arch.IntWidth + return nil +} + +func (obj *Int) unmarshalRRD(d *Decoder, tag string) error { + if d.arch.IntWidth != 4 && d.arch.IntWidth != 8 { + return archErrorf("rrdbinary does not support IntWidth=%d; only supports 4 or 8", d.arch.IntWidth) + } + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for int: %q", tag) + } + + data := d.data[d.pos:] + + padding := 0 + if d.pos%d.arch.IntAlign != 0 { + padding = d.arch.IntAlign - (d.pos % d.arch.IntAlign) + } + if len(data) < padding { + return d.binErrorf(padding+d.arch.IntWidth, "unexpected end-of-file in %d-byte padding-before-int", padding) + } + data = data[padding:] + + if len(data) < d.arch.IntWidth { + return d.binErrorf(d.arch.IntWidth, "unexpected end-of-file in %d-byte int", d.arch.IntWidth) + } + + switch d.arch.IntWidth { + case 4: + *obj = Int(int32(d.arch.ByteOrder.Uint32(data))) + case 8: + *obj = Int(d.arch.ByteOrder.Uint64(data)) + } + d.pos += padding + d.arch.IntWidth + return nil +} + +func (obj *Unival) unmarshalRRD(d *Decoder, tag string) error { + if d.arch.UnivalWidth != 8 { + return archErrorf("rrdbinary does not support UnivalWidth=%d; only supports 8", d.arch.UnivalWidth) + } + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for unival: %q", tag) + } + + data := d.data[d.pos:] + + padding := 0 + if d.pos%d.arch.UnivalAlign != 0 { + padding = d.arch.UnivalAlign - (d.pos % d.arch.UnivalAlign) + } + if len(data) < padding { + return d.binErrorf(padding+d.arch.UnivalWidth, "unexpected end-of-file in %d-byte padding-before-unival", padding) + } + data = data[padding:] + + if len(data) < d.arch.UnivalWidth { + return d.binErrorf(d.arch.UnivalWidth, "unexpected end-of-file in %d-byte unival", d.arch.UnivalWidth) + } + + *obj = Unival(d.arch.ByteOrder.Uint64(data)) + d.pos += padding + d.arch.UnivalWidth + return nil +} + +func (obj *Time) unmarshalRRD(d *Decoder, tag string) error { + if d.arch.TimeWidth != 4 && d.arch.TimeWidth != 8 { + return archErrorf("rrdbinary does not support TimeWidth=%d; only supports 4 or 8", d.arch.TimeWidth) + } + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for time: %q", tag) + } + + data := d.data[d.pos:] + + padding := 0 + if d.pos%d.arch.TimeAlign != 0 { + padding = d.arch.TimeAlign - (d.pos % d.arch.TimeAlign) + } + if len(data) < padding { + return d.binErrorf(padding+d.arch.TimeWidth, "unexpected end-of-file in %d-byte padding-before-time", padding) + } + data = data[padding:] + + if len(data) < d.arch.TimeWidth { + return d.binErrorf(d.arch.TimeWidth, "unexpected end-of-file in %d-byte time", d.arch.TimeWidth) + } + + switch d.arch.TimeWidth { + case 4: + *obj = Time(int32(d.arch.ByteOrder.Uint32(data))) + case 8: + *obj = Time(d.arch.ByteOrder.Uint64(data)) + } + d.pos += padding + d.arch.TimeWidth + return nil +} + +func (_ *EOF) unmarshalRRD(d *Decoder, tag string) error { + if tag != "" { + return typeErrorf("invalid rrdbinary struct tag for eof: %q", tag) + } + + data := d.data[d.pos:] + if len(data) > 0 { + return d.binErrorf(16, "extra %d bytes of data after expected end-of-file", len(data)) + } + + return nil +} diff --git a/rrdformat/rrdbinary/unmarshal.go b/rrdformat/rrdbinary/unmarshal.go deleted file mode 100644 index 00f1222..0000000 --- a/rrdformat/rrdbinary/unmarshal.go +++ /dev/null @@ -1,305 +0,0 @@ -package rrdbinary - -import ( - "bytes" - "fmt" - "math" - "reflect" - "strconv" - "strings" -) - -type Decoder struct { - arch Architecture - pos int - data []byte -} - -type unmarshaler interface { - unmarshalRRD(d *Decoder, tag string) error -} - -func Unmarshal(arch Architecture, data []byte, ptr interface{}) error { - ptrValue := reflect.ValueOf(ptr) - if ptrValue.Kind() != reflect.Ptr { - return typeErrorf("ptr is a %v, not a pointer", ptrValue.Kind()) - } - decoder := &Decoder{ - arch: arch, - pos: 0, - data: data, - } - return decoder.Decode(ptrValue, "") -} - -func (d *Decoder) binError(ctxLen int, msg string) error { - return NewBinError(msg, d.data, d.pos, ctxLen) -} - -func (d *Decoder) binErrorf(ctxLen int, format string, a ...interface{}) error { - return d.binError(ctxLen, fmt.Sprintf(format, a...)) -} - -func (d *Decoder) Decode(v reflect.Value, tag string) error { - if v.CanInterface() { - if u, ok := v.Interface().(unmarshaler); ok { - return u.unmarshalRRD(d, tag) - } - } - switch v.Type().Kind() { - case reflect.Struct: - return d.decodeStruct(v, tag) - case reflect.Array, reflect.Slice: - return d.decodeList(v, tag) - default: - return typeErrorf("invalid type for rrdbinary.Decoder.Decode: %v", v.Type()) - } -} - -func (d *Decoder) decodeStruct(v reflect.Value, tag string) error { - panicUnless(v.Kind() == reflect.Struct) - panicUnless(v.CanSet()) - - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for struct: %q", tag) - } - - for i := 0; i < v.NumField(); i++ { - fieldInfo := v.Type().Field(i) - tag := fieldInfo.Tag.Get("rrdbinary") - if tag == "-" { - continue - } - if err := d.Decode(v.Field(i), tag); err != nil { - return fmt.Errorf("field %s: %w", fieldInfo.Name, err) - } - } - return nil -} - -func (d *Decoder) decodeList(v reflect.Value, tag string) error { - panicUnless(v.Kind() == reflect.Array || v.Kind() == reflect.Slice) - panicUnless(v.CanSet()) - - for i := 0; i < v.Len(); i++ { - if err := d.Decode(v.Index(i), tag); err != nil { - return fmt.Errorf("index %d: %w", i, err) - } - } - return nil -} - -func (obj *String) unmarshalRRD(d *Decoder, tag string) error { - size := 0 - switch { - case tag == "": - // do nothing - case strings.HasPrefix(tag, "size="): - var err error - size, err = strconv.Atoi(strings.TrimPrefix(tag, "size=")) - if err != nil { - return typeErrorf("invalid rrdbinary struct tag for string: %q", tag) - } - default: - return typeErrorf("invalid rrdbinary struct tag for string: %q", tag) - } - - data := d.data[d.pos:] - if size > 0 { - if len(data) < size { - return d.binErrorf(size, "unexpected end-of-file in %d-byte string", size) - } - data = data[:size] - } - - nul := bytes.IndexByte(data, 0) - if nul < 0 { - if size > 0 { - return d.binErrorf(size, "missing null-terminator on %d-byte string", size) - } else { - return d.binErrorf(16, "unexpected end-of-file looking for null-terminator on string") - } - } - - if size > 0 { - for _, byte := range data[nul:] { - if byte != 0 { - return d.binErrorf(size, "garbage data after null-terminator on fixed %d-byte string", size) - } - } - } else { - size = nul + 1 - } - - *obj = String(data[:nul]) - d.pos += size - return nil -} - -func (obj *Float) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.FloatWidth != 8 { - return archErrorf("rrdbinary does not support FloatWidth=%d; only supports 8", d.arch.FloatWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for float: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.FloatAlign != 0 { - padding = d.arch.FloatAlign - (d.pos % d.arch.FloatAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.FloatWidth, "unexpected end-of-file in %d-byte padding-before-float", padding) - } - data = data[padding:] - - if len(data) < d.arch.FloatWidth { - return d.binErrorf(d.arch.FloatWidth, "unexpected end-of-file in %d-byte float", d.arch.FloatWidth) - } - - *obj = Float(math.Float64frombits(d.arch.ByteOrder.Uint64(data))) - d.pos += padding + d.arch.FloatWidth - return nil -} - -func (obj *Uint) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.IntWidth != 4 && d.arch.IntWidth != 8 { - return archErrorf("rrdbinary does not support IntWidth=%d; only supports 4 or 8", d.arch.IntWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for uint: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.IntAlign != 0 { - padding = d.arch.IntAlign - (d.pos % d.arch.IntAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.IntWidth, "unexpected end-of-file in %d-byte padding-before-uint", padding) - } - data = data[padding:] - - if len(data) < d.arch.IntWidth { - return d.binErrorf(d.arch.IntWidth, "unexpected end-of-file in %d-byte uint", d.arch.IntWidth) - } - - switch d.arch.IntWidth { - case 4: - *obj = Uint(d.arch.ByteOrder.Uint32(data)) - case 8: - *obj = Uint(d.arch.ByteOrder.Uint64(data)) - } - d.pos += padding + d.arch.IntWidth - return nil -} - -func (obj *Int) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.IntWidth != 4 && d.arch.IntWidth != 8 { - return archErrorf("rrdbinary does not support IntWidth=%d; only supports 4 or 8", d.arch.IntWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for int: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.IntAlign != 0 { - padding = d.arch.IntAlign - (d.pos % d.arch.IntAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.IntWidth, "unexpected end-of-file in %d-byte padding-before-int", padding) - } - data = data[padding:] - - if len(data) < d.arch.IntWidth { - return d.binErrorf(d.arch.IntWidth, "unexpected end-of-file in %d-byte int", d.arch.IntWidth) - } - - switch d.arch.IntWidth { - case 4: - *obj = Int(int32(d.arch.ByteOrder.Uint32(data))) - case 8: - *obj = Int(d.arch.ByteOrder.Uint64(data)) - } - d.pos += padding + d.arch.IntWidth - return nil -} - -func (obj *Unival) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.UnivalWidth != 8 { - return archErrorf("rrdbinary does not support UnivalWidth=%d; only supports 8", d.arch.UnivalWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for unival: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.UnivalAlign != 0 { - padding = d.arch.UnivalAlign - (d.pos % d.arch.UnivalAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.UnivalWidth, "unexpected end-of-file in %d-byte padding-before-unival", padding) - } - data = data[padding:] - - if len(data) < d.arch.UnivalWidth { - return d.binErrorf(d.arch.UnivalWidth, "unexpected end-of-file in %d-byte unival", d.arch.UnivalWidth) - } - - *obj = Unival(d.arch.ByteOrder.Uint64(data)) - d.pos += padding + d.arch.UnivalWidth - return nil -} - -func (obj *Time) unmarshalRRD(d *Decoder, tag string) error { - if d.arch.TimeWidth != 4 && d.arch.TimeWidth != 8 { - return archErrorf("rrdbinary does not support TimeWidth=%d; only supports 4 or 8", d.arch.TimeWidth) - } - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for time: %q", tag) - } - - data := d.data[d.pos:] - - padding := 0 - if d.pos%d.arch.TimeAlign != 0 { - padding = d.arch.TimeAlign - (d.pos % d.arch.TimeAlign) - } - if len(data) < padding { - return d.binErrorf(padding+d.arch.TimeWidth, "unexpected end-of-file in %d-byte padding-before-time", padding) - } - data = data[padding:] - - if len(data) < d.arch.TimeWidth { - return d.binErrorf(d.arch.TimeWidth, "unexpected end-of-file in %d-byte time", d.arch.TimeWidth) - } - - switch d.arch.TimeWidth { - case 4: - *obj = Time(int32(d.arch.ByteOrder.Uint32(data))) - case 8: - *obj = Time(d.arch.ByteOrder.Uint64(data)) - } - d.pos += padding + d.arch.TimeWidth - return nil -} - -func (_ *EOF) unmarshalRRD(d *Decoder, tag string) error { - if tag != "" { - return typeErrorf("invalid rrdbinary struct tag for eof: %q", tag) - } - - data := d.data[d.pos:] - if len(data) > 0 { - return d.binErrorf(16, "extra %d bytes of data after expected end-of-file", len(data)) - } - - return nil -} diff --git a/rrdformat/unmarshal_binary.go b/rrdformat/unmarshal_binary.go index b9bafde..70c06b7 100644 --- a/rrdformat/unmarshal_binary.go +++ b/rrdformat/unmarshal_binary.go @@ -2,6 +2,7 @@ package rrdformat import ( "encoding" + "fmt" "git.lukeshu.com/go/librrd/rrdformat/rrdbinary" ) @@ -16,44 +17,64 @@ func (rrd *RRD) UnmarshalBinary(data []byte) error { if err != nil { return err } - var header Header - if err := rrdbinary.Unmarshal(arch, data, &header); err != nil { - return err - } + decoder := rrdbinary.NewDecoder(arch, data) var parsed RRDv0005 - parsed.DSDefs = make([]DSDef, header.DSCnt) - parsed.DSDefs = make([]DSDef, header.DSCnt) - parsed.RRADefs = make([]RRADef, header.RRACnt) - //LastUpdated - parsed.PDPPreps = make([]PDPPrep, header.DSCnt) - parsed.CDPPreps = make([]CDPPrep, header.DSCnt*header.RRACnt) - parsed.RRAPtrs = make([]RRAPtr, header.RRACnt) - //Values - switch header.Version { + if err := decoder.Decode(&parsed.Header, ""); err != nil { + return fmt.Errorf("field %s: %w", "Header", err) + } + // allocate memory based on .Header values + parsed.DSDefs = make([]DSDef, parsed.Header.DSCnt) + parsed.DSDefs = make([]DSDef, parsed.Header.DSCnt) + parsed.RRADefs = make([]RRADef, parsed.Header.RRACnt) + parsed.PDPPreps = make([]PDPPrep, parsed.Header.DSCnt) + parsed.CDPPreps = make([]CDPPrep, parsed.Header.DSCnt*parsed.Header.RRACnt) + parsed.RRAPtrs = make([]RRAPtr, parsed.Header.RRACnt) + // resume decoding + if err := decoder.Decode(&parsed.DSDefs, ""); err != nil { + return fmt.Errorf("field %s: %w", "DSDefs", err) + } + if err := decoder.Decode(&parsed.RRADefs, ""); err != nil { + return fmt.Errorf("field %s: %w", "RRADefs", err) + } + // allocate memory based on .RRADefs + val_cnt := 0 + for i := range parsed.RRADefs { + val_cnt += int(parsed.RRADefs[i].RowCnt * parsed.Header.DSCnt) + } + parsed.Values = make([]RRDValue, val_cnt) + // resume decoding + var lastUpdatedPtr interface{} + switch parsed.Header.Version { case "0001", "0002": - _parsed := &RRDv0001{} //(*RRDv0001)(&parsed) - if err := rrdbinary.Unmarshal(arch, data, _parsed); err != nil { - return err - } + lastUpdatedPtr = &parsed.LastUpdated.Sec case "0003", "0004", "0005": - if err := rrdbinary.Unmarshal(arch, data, &parsed); err != nil { - return err - } + lastUpdatedPtr = &parsed.LastUpdated default: - // version number already validated by - // SniffArchitecture + // version number already validated by SniffArchitecture panic("should not happen") } - - val_cnt := 0 - for i := range parsed.RRADefs { - val_cnt += int(parsed.RRADefs[i].RowCnt * header.DSCnt) + if err := decoder.Decode(lastUpdatedPtr, ""); err != nil { + return fmt.Errorf("field %s: %w", "LastUpdated", err) } - parsed.Values = make([]RRDValue, val_cnt) - if err := rrdbinary.Unmarshal(arch, data, &parsed.Values); err != nil { - return err + if err := decoder.Decode(&parsed.LastUpdated, ""); err != nil { + return fmt.Errorf("field %s: %w", "LastUpdated", err) + } + if err := decoder.Decode(&parsed.PDPPreps, ""); err != nil { + return fmt.Errorf("field %s: %w", "PDPPreps", err) + } + if err := decoder.Decode(&parsed.CDPPreps, ""); err != nil { + return fmt.Errorf("field %s: %w", "CDPPreps", err) + } + if err := decoder.Decode(&parsed.RRAPtrs, ""); err != nil { + return fmt.Errorf("field %s: %w", "RRAPtrs", err) + } + if err := decoder.Decode(&parsed.Values, ""); err != nil { + return fmt.Errorf("field %s: %w", "Values", err) + } + if err := decoder.Decode(&rrdbinary.EOF{}, ""); err != nil { + return fmt.Errorf("field %s: %w", "EOF", err) } *rrd = RRD{ -- cgit v1.1-4-g5e80