internal/pipewire: define size constants
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 2m26s
Test / Hakurei (push) Successful in 3m17s
Test / Hpkg (push) Successful in 4m13s
Test / Sandbox (race detector) (push) Successful in 4m23s
Test / Hakurei (race detector) (push) Successful in 5m11s
Test / Flake checks (push) Successful in 1m26s

This gets rid of magic numbers in marshal/unmarshal.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-11-27 00:54:56 +09:00
parent 2698ca00e8
commit 2edcfe1e68
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
2 changed files with 44 additions and 25 deletions

View File

@ -6,8 +6,8 @@ import (
)
const (
// HeaderSize is the fixed size of [Header].
HeaderSize = 16
// SizeHeader is the fixed size of [Header].
SizeHeader = 16
// SizeMax is the largest value of [Header.Size] that can be represented in its 3-byte segment.
SizeMax = 0x00ffffff
)
@ -50,11 +50,11 @@ func (h *Header) MarshalBinary() (data []byte, err error) {
if h.Size&^SizeMax != 0 {
return nil, ErrSizeRange
}
return h.append(make([]byte, 0, HeaderSize)), nil
return h.append(make([]byte, 0, SizeHeader)), nil
}
// unmarshalBinary decodes the protocol native message header.
func (h *Header) unmarshalBinary(data [HeaderSize]byte) {
func (h *Header) unmarshalBinary(data [SizeHeader]byte) {
h.ID = binary.NativeEndian.Uint32(data[0:4])
h.Size = binary.NativeEndian.Uint32(data[4:8])
h.Opcode = byte(h.Size >> 24)
@ -65,9 +65,9 @@ func (h *Header) unmarshalBinary(data [HeaderSize]byte) {
// UnmarshalBinary decodes the protocol native message header.
func (h *Header) UnmarshalBinary(data []byte) error {
if len(data) != HeaderSize {
if len(data) != SizeHeader {
return ErrBadHeader
}
h.unmarshalBinary(([HeaderSize]byte)(data))
h.unmarshalBinary(([SizeHeader]byte)(data))
return nil
}

View File

@ -32,6 +32,25 @@ type (
Bytes = []byte
)
const (
// SizeAlign is the boundary which POD starts are always aligned to.
SizeAlign = 8
// SizeSPrefix is the fixed, unpadded size of the fixed-size prefix encoding POD wire size.
SizeSPrefix = 4
// SizeTPrefix is the fixed, unpadded size of the fixed-size prefix encoding POD value type.
SizeTPrefix = 4
// SizePrefix is the fixed, unpadded size of the fixed-size POD prefix.
SizePrefix = SizeSPrefix + SizeTPrefix
// SizeId is the fixed, unpadded size of a [SPA_TYPE_Id] value.
SizeId = 4
// SizeInt is the fixed, unpadded size of a [SPA_TYPE_Int] value.
SizeInt = 4
// SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value.
SizeLong = 8
)
/* Basic types */
const (
/* POD's can contain a number of basic SPA types: */
@ -98,21 +117,21 @@ func MarshalAppend(data []byte, v any) ([]byte, error) {
// appendInner calls f and handles size prefix and padding around the appended data.
// f must only append to data.
func appendInner(data []byte, f func(data []byte) ([]byte, error)) ([]byte, error) {
data = append(data, make([]byte, 4)...)
data = append(data, make([]byte, SizeSPrefix)...)
rData, err := f(data)
if err != nil {
return data, err
}
size := len(rData) - len(data) + 4
paddingSize := (8 - (size)%8) % 8
size := len(rData) - len(data) + SizeSPrefix
paddingSize := (SizeAlign - (size)%SizeAlign) % SizeAlign
// compensated for size and type prefix
wireSize := size - 8
wireSize := size - SizePrefix
if wireSize > math.MaxUint32 {
return data, UnsupportedSizeError(wireSize)
}
binary.NativeEndian.PutUint32(rData[len(data)-4:len(data)], Word(wireSize))
binary.NativeEndian.PutUint32(rData[len(data)-SizeSPrefix:len(data)], Word(wireSize))
rData = append(rData, make([]byte, paddingSize)...)
return rData, nil
@ -223,7 +242,7 @@ func UnmarshalNext(data []byte, v any) (size Word, err error) {
}
err = unmarshalValue(data, rv.Elem(), &size)
// prefix and padding size
size += 8 + (8-(size)%8)%8
size += SizePrefix + (SizeAlign-(size)%SizeAlign)%SizeAlign
return
}
@ -238,10 +257,10 @@ func (u *UnmarshalSetError) Error() string { return "cannot set: " + u.Type.Stri
type TrailingGarbageError struct{ Data []byte }
func (e *TrailingGarbageError) Error() string {
if len(e.Data) < 8 {
if len(e.Data) < SizePrefix {
return "got " + strconv.Itoa(len(e.Data)) + " bytes of trailing garbage"
}
return "data has extra values starting with type " + strconv.Itoa(int(binary.NativeEndian.Uint32(e.Data[4:])))
return "data has extra values starting with type " + strconv.Itoa(int(binary.NativeEndian.Uint32(e.Data[SizeSPrefix:])))
}
// A StringTerminationError describes an incorrectly terminated string
@ -272,7 +291,7 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
switch v.Kind() {
case reflect.Uint32:
*wireSizeP = 4
*wireSizeP = SizeId
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Id, wireSizeP); err != nil {
return err
}
@ -280,7 +299,7 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
return nil
case reflect.Int32:
*wireSizeP = 4
*wireSizeP = SizeInt
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, wireSizeP); err != nil {
return err
}
@ -288,7 +307,7 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
return nil
case reflect.Int64:
*wireSizeP = 8
*wireSizeP = SizeLong
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Long, wireSizeP); err != nil {
return err
}
@ -306,9 +325,9 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
if err := unmarshalValue(data, v.Field(i), &fieldWireSize); err != nil {
return err
}
paddingSize := (8 - (fieldWireSize)%8) % 8
paddingSize := (SizeAlign - (fieldWireSize)%SizeAlign) % SizeAlign
// bounds check completed in successful call to unmarshalValue
data = data[8+fieldWireSize+paddingSize:]
data = data[SizePrefix+fieldWireSize+paddingSize:]
}
if len(data) != 0 {
@ -317,10 +336,10 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
return nil
case reflect.Pointer:
if len(data) < 8 {
if len(data) < SizePrefix {
return io.ErrUnexpectedEOF
}
switch binary.NativeEndian.Uint32(data[4:]) {
switch binary.NativeEndian.Uint32(data[SizeSPrefix:]) {
case SPA_TYPE_None:
v.SetZero()
return nil
@ -374,7 +393,7 @@ func (u *UnexpectedTypeError) Error() string {
// unmarshalCheckTypeBounds performs bounds checks on data and validates the type and size prefixes.
// An expected size of zero skips further bounds checks.
func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
if len(*data) < 8 {
if len(*data) < SizePrefix {
return io.ErrUnexpectedEOF
}
@ -385,16 +404,16 @@ func unmarshalCheckTypeBounds(data *[]byte, t Word, sizeP *Word) error {
if wantSize != 0 && gotSize != wantSize {
return &InconsistentSizeError{gotSize, wantSize}
}
if len(*data)-8 < int(gotSize) {
if len(*data)-SizePrefix < int(gotSize) {
return io.ErrUnexpectedEOF
}
gotType := binary.NativeEndian.Uint32((*data)[4:])
gotType := binary.NativeEndian.Uint32((*data)[SizeSPrefix:])
if gotType != t {
return &UnexpectedTypeError{gotType, t}
}
*data = (*data)[8 : gotSize+8]
*data = (*data)[SizePrefix : gotSize+SizePrefix]
return nil
}