diff --git a/depolorizer.go b/depolorizer.go index 7376fa5..9e9fdcf 100644 --- a/depolorizer.go +++ b/depolorizer.go @@ -59,6 +59,15 @@ func newLoadDepolorizer(data readbuffer, config *wireConfig) (*Depolorizer, erro return &Depolorizer{pack: pack, packed: true, cfg: *config}, nil } +// Unpacked attempts to unpack a Depolorizer that contains a WirePack or WireDoc element. +// A new Depolorizer is returned with the unpacked wire and the original Depolorizer consumes one wire element. +// Returns an error if there are no elements left or if the element is not a WirePack or WireDoc. +// +// note: this method is a wrapper around DepolorizePacked for brevity and aesthetics. +func (depolorizer *Depolorizer) Unpacked() (*Depolorizer, error) { + return depolorizer.DepolorizePacked() +} + // Done returns whether all elements in the Depolorizer have been read. func (depolorizer *Depolorizer) Done() bool { // Check if packbuffer is done if in packed mode @@ -70,6 +79,28 @@ func (depolorizer *Depolorizer) Done() bool { return depolorizer.done } +// IsNull returns whether the next element in the Depolorizer is a WireNull without +// consuming it from the buffer. False if there are no elements left in the Depolorizer. +// +// Use DepolorizeNull to consume the WireNull element if further elements are to be read. +func (depolorizer *Depolorizer) IsNull() bool { + // Check if the Depolorizer is in packed mode + if !depolorizer.packed { + // Return the nullity of the atomic buffer + return depolorizer.data.wire.IsNull() + } + + // Peek the next element from the packbuffer. + // Errors if there are no elements left + peek, ok := depolorizer.pack.peek() + if !ok { + return false + } + + // Return the nullity of the peeked element + return peek.IsNull() +} + // Depolorize decodes a value from the Depolorizer. // Decodes the data in the wire into the given object using Go reflection. // Returns an error if the object is not a pointer or if a decode error occurs. @@ -278,8 +309,8 @@ func (depolorizer *Depolorizer) DepolorizeRaw() (Raw, error) { } // DepolorizePacked attempts to decode another Depolorizer from the Depolorizer, consuming one wire element. +// A new Depolorizer is returned with the unpacked wire if the element is WirePack or WireDoc. // Returns an error if there are no elements left or if the element is not WirePack or WireDoc. -// Returns a ErrNullPack if the element is a WireNull. func (depolorizer *Depolorizer) DepolorizePacked() (*Depolorizer, error) { // Read the next element data, err := depolorizer.read() @@ -291,11 +322,8 @@ func (depolorizer *Depolorizer) DepolorizePacked() (*Depolorizer, error) { case WirePack, WireDoc: return newLoadDepolorizer(data, &depolorizer.cfg) - case WireNull: - return nil, ErrNullPack - default: - return nil, IncompatibleWireType(data.wire, WireNull, WirePack, WireDoc) + return nil, IncompatibleWireType(data.wire, WirePack, WireDoc) } } diff --git a/depolorizer_test.go b/depolorizer_test.go index fbb3bb4..ac2855f 100644 --- a/depolorizer_test.go +++ b/depolorizer_test.go @@ -380,7 +380,7 @@ func TestDepolorizer_DepolorizePacked(t *testing.T) { require.Nil(t, err) _, err = depolorizer.DepolorizePacked() - assert.EqualError(t, err, ErrNullPack.Error()) + assert.EqualError(t, err, "incompatible wire: unexpected wiretype 'null'. expected one of: {pack, document}") }) t.Run("Incompatible", func(t *testing.T) { @@ -388,7 +388,7 @@ func TestDepolorizer_DepolorizePacked(t *testing.T) { require.Nil(t, err) _, err = depolorizer.DepolorizePacked() - assert.EqualError(t, err, "incompatible wire: unexpected wiretype 'posint'. expected one of: {null, pack, document}") + assert.EqualError(t, err, "incompatible wire: unexpected wiretype 'posint'. expected one of: {pack, document}") }) } diff --git a/errors.go b/errors.go index 141b492..aa1e6bb 100644 --- a/errors.go +++ b/errors.go @@ -15,8 +15,6 @@ var ( // It acts a signal for error and value handlers. errNilValue = errors.New("nil value") - // ErrNullPack is an error for when a WireNull is attempted to be converted to a Depolorizer - ErrNullPack = errors.New("null pack element") // ErrObjectNotPtr is an error for when a non pointer object is passed to the Depolorize function ErrObjectNotPtr = errors.New("object not a pointer") // ErrObjectNotSettable is an error for when a non-settable pointer is passed to the Depolorize function diff --git a/polo_test.go b/polo_test.go index 3968d7f..f5989fa 100644 --- a/polo_test.go +++ b/polo_test.go @@ -1623,20 +1623,18 @@ func (object CustomEncodeObject) Polorize() (*Polorizer, error) { polorizer.PolorizeString(object.A) polorizer.PolorizeInt(int64(object.B)) - if object.C == nil { - polorizer.PolorizeNull() - } else { + if object.C != nil { C := NewPolorizer() for _, elem := range object.C { C.PolorizeString(elem) } polorizer.PolorizePacked(C) + } else { + polorizer.PolorizeNull() } - if object.D == nil { - polorizer.PolorizeNull() - } else { + if object.D != nil { keys := make([]string, 0, len(object.D)) for key := range object.D { keys = append(keys, key) @@ -1650,6 +1648,8 @@ func (object CustomEncodeObject) Polorize() (*Polorizer, error) { } polorizer.PolorizePacked(D) + } else { + polorizer.PolorizeNull() } polorizer.PolorizeFloat64(object.E) @@ -1658,10 +1658,12 @@ func (object CustomEncodeObject) Polorize() (*Polorizer, error) { } func (object *CustomEncodeObject) Depolorize(depolorizer *Depolorizer) (err error) { - depolorizer, err = depolorizer.DepolorizePacked() - if errors.Is(err, ErrNullPack) { + if depolorizer.IsNull() { return nil - } else if err != nil { + } + + depolorizer, err = depolorizer.Unpacked() + if err != nil { return err } @@ -1670,6 +1672,7 @@ func (object *CustomEncodeObject) Depolorize(depolorizer *Depolorizer) (err erro return err } + // todo: cleanup with extended decode methods B, err := depolorizer.DepolorizeInt() if err != nil { return err @@ -1677,14 +1680,15 @@ func (object *CustomEncodeObject) Depolorize(depolorizer *Depolorizer) (err erro object.B = int32(B) - c, err := depolorizer.DepolorizePacked() - - switch { - case errors.Is(err, ErrNullPack): + if depolorizer.IsNull() { object.C = nil - case err != nil: - return err - default: + _ = depolorizer.DepolorizeNull() + } else { + c, err := depolorizer.DepolorizePacked() + if err != nil { + return err + } + object.C = make([]string, 0, 5) for !c.Done() { @@ -1697,14 +1701,15 @@ func (object *CustomEncodeObject) Depolorize(depolorizer *Depolorizer) (err erro } } - d, err := depolorizer.DepolorizePacked() - - switch { - case errors.Is(err, ErrNullPack): + if depolorizer.IsNull() { object.D = nil - case err != nil: - return err - default: + _ = depolorizer.DepolorizeNull() + } else { + d, err := depolorizer.DepolorizePacked() + if err != nil { + return err + } + object.D = make(map[string]string) for !d.Done() {