bin

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2023 License: MIT Imports: 5 Imported by: 1

README

Binmap

I've found that using the stdlib binary interface to read and write data is a little cumbersome and tedious, since any operation can result in an error. While this makes sense given the problem domain, the API leaves something to be desired.

I'd love to have a way to batch operations, so I don't have so much if err != nil. If an error occurs at any point, then I'm able to handle one error at the end.

I'd also like to work easily with io.Readers rather than having to read everything into memory first. While this can be accomplished with binary.Read, I still have the issue of too much error handling cluttering normal code.

Goals

  • I'd like to have an easier to use interface for reading/writing binary data.
  • I'd like to declare binary IO operations, execute them, and handle a single error at the end.
  • I'd like to be able to reuse binary IO operations, and even pass them into more complex pipelines.
  • I'd like to be able to declare dynamic behavior, like when the size of the next read is determined by the current field.
  • I'd like to declare a read loop based on a read field value, and pass the loop construct to a larger pipeline.
  • Struct tag field binding would be fantastic, but reflection is... fraught. I'll see how this goes, and I'll probably take some hints from how the stdlib is handling this.
    • There's too much possibility of dynamic or dependent logic with a lot of binary payloads, and the number of edge cases for implementing this is more than I want to deal with.
    • I'm pretty happy with the API for mapping definition so far, and I'd rather simplify that than get into reflection with struct field tags. I feel like it's much more understandable (and thus maintainable) code.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNilReadWrite = errors.New("nil read source or write target")
)

Functions

This section is empty.

Types

type AnyFloat

type AnyFloat interface {
	float32 | float64
}

type AnyInt

type AnyInt interface {
	int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64
}

type Mapper

type Mapper interface {
	// Read data from a binary source.
	Read(r io.Reader, endian binary.ByteOrder) error
	// Write data to a binary target.
	Write(w io.Writer, endian binary.ByteOrder) error
}

Mapper is any procedure that knows how to read from and write to binary data, given an endianness policy.

func Any

func Any[T any](target *T, read ReadFunc, write WriteFunc) Mapper

Any is provided to make it easy to create a custom Mapper for any given type.

func Bool

func Bool(b *bool) Mapper

Bool will map a single boolean.

func Byte

func Byte(b *byte) Mapper

Byte will map a single byte.

func DynamicSlice

func DynamicSlice[E any](target *[]E, mapVal func(*E) Mapper) Mapper

DynamicSlice tries to accomplish a happy medium between LenSlice and Slice. A uint32 will be used to store the size of the given slice, but it's not necessary to read this from a field, rather it will be discovered at write time. This means that the size will be available at read time by first reading the uint32 with LenSlice, without requiring a caller provided field. In a scenario where a slice in a struct is used, this makes it easier to read and write because the struct doesn't need to store the size in a field.

func FixedBytes

func FixedBytes[S SizeType](buf *[]byte, length S) Mapper

FixedBytes maps a byte slice of a known length.

func FixedString

func FixedString(s *string, length int) Mapper

FixedString will map a string with a max length that is known ahead of time. The target string will not contain any zero bytes if the encoded string is less than the space allowed.

func Float

func Float[T AnyFloat](f *T) Mapper

Float will map any floating point value.

func Int

func Int[T AnyInt](i *T) Mapper

Int will map any integer, excluding int.

func LenBytes

func LenBytes[S SizeType](buf *[]byte, length *S) Mapper

LenBytes is used for situations where an arbitrarily sized byte slice is encoded after its length. This mapper will read the length, and then length number of bytes into a byte slice. The mapper will write the length and bytes in the same order.

func LenSlice

func LenSlice[E any, S SizeType](target *[]E, count *S, mapVal func(*E) Mapper) Mapper

LenSlice is for situations where a slice is encoded with its length prepended. Otherwise, this behaves exactly like Slice.

func MapSequence

func MapSequence(mappings ...Mapper) Mapper

MapSequence creates a Mapper that uses each given Mapper in order.

func NullTermString

func NullTermString(s *string) Mapper

NullTermString will read and write null-byte terminated string. The string provided doesn't have to contain a null terminator, since one will be added on write.

func Size

func Size[S SizeType](size *S) Mapper

Size maps any value that can reasonably be used to express a size.

func Slice

func Slice[E any, S SizeType](target *[]E, count S, mapVal func(*E) Mapper) Mapper

Slice will produce a mapper informed from the given function to use a slice of values. The slice length must be known ahead of time. The mapVal function will be used to create a Mapper that relates to the type returned from allocNext. The returned Mapper will orchestrate the array construction according to the given function.

type ReadFunc

type ReadFunc func(r io.Reader, endian binary.ByteOrder) error

ReadFunc is a function that reads data from a binary source.

type SizeType

type SizeType interface {
	uint8 | uint16 | uint32 | uint64
}

type WriteFunc

type WriteFunc func(w io.Writer, endian binary.ByteOrder) error

WriteFunc is a function that writes data to a binary target.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL