Skip to content

Commit

Permalink
add Packer and Unpacker to the field spec
Browse files Browse the repository at this point in the history
  • Loading branch information
alovak committed Jun 7, 2024
1 parent a234a4a commit 6734369
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 171 deletions.
39 changes: 11 additions & 28 deletions field/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (
"github.com/moov-io/iso8583/utils"
)

var _ Field = (*Binary)(nil)
var _ json.Marshaler = (*Binary)(nil)
var _ json.Unmarshaler = (*Binary)(nil)
var (
_ Field = (*Binary)(nil)
_ json.Marshaler = (*Binary)(nil)
_ json.Unmarshaler = (*Binary)(nil)
)

type Binary struct {
value []byte
Expand Down Expand Up @@ -72,43 +74,24 @@ func (f *Binary) SetValue(v []byte) {
func (f *Binary) Pack() ([]byte, error) {
data := f.value

if f.spec.Pad != nil {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(data))
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
packer := f.spec.getPacker()

return append(packedLength, packed...), nil
return packer.Pack(data, f.spec)
}

func (f *Binary) Unpack(data []byte) (int, error) {
dataLen, prefBytes, err := f.spec.Pref.DecodeLength(f.spec.Length, data)
if err != nil {
return 0, fmt.Errorf("failed to decode length: %w", err)
}
unpacker := f.spec.getUnpacker()

raw, read, err := f.spec.Enc.Decode(data[prefBytes:], dataLen)
raw, bytesRead, err := unpacker.Unpack(data, f.spec)
if err != nil {
return 0, fmt.Errorf("failed to decode content: %w", err)
}

if f.spec.Pad != nil {
raw = f.spec.Pad.Unpad(raw)
return 0, err
}

if err := f.SetBytes(raw); err != nil {
return 0, fmt.Errorf("failed to set bytes: %w", err)
}

return read + prefBytes, nil
return bytesRead, nil
}

// Deprecated. Use Marshal instead
Expand Down
8 changes: 5 additions & 3 deletions field/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import (
"github.com/moov-io/iso8583/utils"
)

var _ Field = (*Composite)(nil)
var _ json.Marshaler = (*Composite)(nil)
var _ json.Unmarshaler = (*Composite)(nil)
var (
_ Field = (*Composite)(nil)
_ json.Marshaler = (*Composite)(nil)
_ json.Unmarshaler = (*Composite)(nil)
)

// Composite is a wrapper object designed to hold ISO8583 TLVs, subfields and
// subelements. Because Composite handles both of these usecases generically,
Expand Down
39 changes: 11 additions & 28 deletions field/numeric.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import (
"github.com/moov-io/iso8583/utils"
)

var _ Field = (*Numeric)(nil)
var _ json.Marshaler = (*Numeric)(nil)
var _ json.Unmarshaler = (*Numeric)(nil)
var (
_ Field = (*Numeric)(nil)
_ json.Marshaler = (*Numeric)(nil)
_ json.Unmarshaler = (*Numeric)(nil)
)

type Numeric struct {
value int64
Expand Down Expand Up @@ -84,44 +86,25 @@ func (f *Numeric) SetValue(v int64) {
func (f *Numeric) Pack() ([]byte, error) {
data := []byte(strconv.FormatInt(f.value, 10))

if f.spec.Pad != nil {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(data))
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
packer := f.spec.getPacker()

return append(packedLength, packed...), nil
return packer.Pack(data, f.spec)
}

// returns number of bytes was read
func (f *Numeric) Unpack(data []byte) (int, error) {
dataLen, prefBytes, err := f.spec.Pref.DecodeLength(f.spec.Length, data)
if err != nil {
return 0, fmt.Errorf("failed to decode length: %w", err)
}
unpacker := f.spec.getUnpacker()

raw, read, err := f.spec.Enc.Decode(data[prefBytes:], dataLen)
raw, bytesRead, err := unpacker.Unpack(data, f.spec)
if err != nil {
return 0, fmt.Errorf("failed to decode content: %w", err)
}

if f.spec.Pad != nil {
raw = f.spec.Pad.Unpad(raw)
return 0, err
}

if err := f.SetBytes(raw); err != nil {
return 0, fmt.Errorf("failed to set bytes: %w", err)
}

return read + prefBytes, nil
return bytesRead, nil
}

// Deprecated. Use Marshal instead
Expand Down
43 changes: 43 additions & 0 deletions field/packer_unpacker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package field

import "fmt"

type DefaultPacker struct{}

func (p DefaultPacker) Pack(data []byte, spec *Spec) ([]byte, error) {
if spec.Pad != nil {
data = spec.Pad.Pad(data, spec.Length)
}

packed, err := spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := spec.Pref.EncodeLength(spec.Length, len(data))
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}

return append(packedLength, packed...), nil
}

type DefaultUnpacker struct{}

func (u DefaultUnpacker) Unpack(data []byte, spec *Spec) ([]byte, int, error) {
dataLen, prefBytes, err := spec.Pref.DecodeLength(spec.Length, data)
if err != nil {
return nil, 0, fmt.Errorf("failed to decode length: %w", err)
}

raw, read, err := spec.Enc.Decode(data[prefBytes:], dataLen)
if err != nil {
return nil, 0, fmt.Errorf("failed to decode content: %w", err)
}

if spec.Pad != nil {
raw = spec.Pad.Unpad(raw)
}

return raw, read + prefBytes, nil
}
30 changes: 30 additions & 0 deletions field/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ type Spec struct {
// Bitmap defines a bitmap field that is used only by a composite field type.
// It defines the way that the composite will determine its subflieds existence.
Bitmap *Bitmap
// Packer is the packer used to pack the field. Default is DefaultPacker.
Packer Packer
// Unpacker is the unpacker used to unpack the field. Default is DefaultUnpacker.
Unpacker Unpacker
}

// Packer is the interface that wraps the Pack method.
type Packer interface {
Pack(data []byte, spec *Spec) ([]byte, error)
}

// Unpacker is the interface that wraps the Unpack method.
type Unpacker interface {
// Unpack unpacks the data according to the spec and returns the
// unpacked data and the number of bytes read.
Unpack(data []byte, spec *Spec) ([]byte, int, error)
}

func NewSpec(length int, desc string, enc encoding.Encoder, pref prefix.Prefixer) *Spec {
Expand All @@ -91,6 +107,20 @@ func NewSpec(length int, desc string, enc encoding.Encoder, pref prefix.Prefixer
}
}

func (spec *Spec) getPacker() Packer {
if spec.Packer == nil {
return DefaultPacker{}
}
return spec.Packer
}

func (spec *Spec) getUnpacker() Unpacker {
if spec.Unpacker == nil {
return DefaultUnpacker{}
}
return spec.Unpacker
}

// Validate validates the spec.
func (s *Spec) Validate() error {
if s.Enc != nil {
Expand Down
39 changes: 11 additions & 28 deletions field/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import (
"github.com/moov-io/iso8583/utils"
)

var _ Field = (*String)(nil)
var _ json.Marshaler = (*String)(nil)
var _ json.Unmarshaler = (*String)(nil)
var (
_ Field = (*String)(nil)
_ json.Marshaler = (*String)(nil)
_ json.Unmarshaler = (*String)(nil)
)

type String struct {
value string
Expand Down Expand Up @@ -72,43 +74,24 @@ func (f *String) SetValue(v string) {
func (f *String) Pack() ([]byte, error) {
data := []byte(f.value)

if f.spec.Pad != nil {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(data))
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
packer := f.spec.getPacker()

return append(packedLength, packed...), nil
return packer.Pack(data, f.spec)
}

func (f *String) Unpack(data []byte) (int, error) {
dataLen, prefBytes, err := f.spec.Pref.DecodeLength(f.spec.Length, data)
if err != nil {
return 0, fmt.Errorf("failed to decode length: %w", err)
}
unpacker := f.spec.getUnpacker()

raw, read, err := f.spec.Enc.Decode(data[prefBytes:], dataLen)
raw, bytesRead, err := unpacker.Unpack(data, f.spec)
if err != nil {
return 0, fmt.Errorf("failed to decode content: %w", err)
}

if f.spec.Pad != nil {
raw = f.spec.Pad.Unpad(raw)
return 0, err
}

if err := f.SetBytes(raw); err != nil {
return 0, fmt.Errorf("failed to set bytes: %w", err)
}

return read + prefBytes, nil
return bytesRead, nil
}

// Deprecated. Use Marshal instead
Expand Down
35 changes: 7 additions & 28 deletions field/track1.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ const (
track1Format = `%s%s^%s^%s%s%s`
)

var (
track1Regex = regexp.MustCompile(`^([A-Z]{1})([0-9]{1,19})\^([^\^]{2,26})\^([0-9]{4}|\^)([0-9]{3}|\^)([^\?]+)$`)
)
var track1Regex = regexp.MustCompile(`^([A-Z]{1})([0-9]{1,19})\^([^\^]{2,26})\^([0-9]{4}|\^)([0-9]{3}|\^)([^\?]+)$`)

func NewTrack1(spec *Spec) *Track1 {
return &Track1{
Expand Down Expand Up @@ -68,37 +66,18 @@ func (f *Track1) Pack() ([]byte, error) {
return nil, err
}

if f.spec.Pad != nil {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(data))
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
packer := f.spec.getPacker()

return append(packedLength, packed...), nil
return packer.Pack(data, f.spec)
}

// returns number of bytes was read
func (f *Track1) Unpack(data []byte) (int, error) {
dataLen, prefBytes, err := f.spec.Pref.DecodeLength(f.spec.Length, data)
if err != nil {
return 0, fmt.Errorf("failed to decode length: %w", err)
}
unpacker := f.spec.getUnpacker()

raw, read, err := f.spec.Enc.Decode(data[prefBytes:], dataLen)
raw, bytesRead, err := unpacker.Unpack(data, f.spec)
if err != nil {
return 0, fmt.Errorf("failed to decode content: %w", err)
}

if f.spec.Pad != nil {
raw = f.spec.Pad.Unpad(raw)
return 0, err
}

if len(raw) > 0 {
Expand All @@ -108,7 +87,7 @@ func (f *Track1) Unpack(data []byte) (int, error) {
}
}

return read + prefBytes, nil
return bytesRead, nil
}

// Deprecated. Use Marshal instead
Expand Down
Loading

0 comments on commit 6734369

Please sign in to comment.