aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pipewire/pod.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-11-27 02:15:44 +0900
committerOphestra <cat@gensokyo.uk>2025-11-27 02:17:38 +0900
commit73987be7d4c850f8b95babb8f68e6ccb6cafcee4 (patch)
treec46e77b552fe508b7970be199699b07ae86cb288 /internal/pipewire/pod.go
parent563b5e66fc0dfe0abc4a4b8c96f0f89ef71c3422 (diff)
internal/pipewire: size without serialisation
This is required to achieve zero allocation (other than reflect). Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pipewire/pod.go')
-rw-r--r--internal/pipewire/pod.go43
1 files changed, 35 insertions, 8 deletions
diff --git a/internal/pipewire/pod.go b/internal/pipewire/pod.go
index 97ba4d07..80c798e8 100644
--- a/internal/pipewire/pod.go
+++ b/internal/pipewire/pod.go
@@ -44,11 +44,11 @@ const (
SizePrefix = SizeSPrefix + SizeTPrefix
// SizeId is the fixed, unpadded size of a [SPA_TYPE_Id] value.
- SizeId = 4
+ SizeId Word = 4
// SizeInt is the fixed, unpadded size of a [SPA_TYPE_Int] value.
- SizeInt = 4
+ SizeInt Word = 4
// SizeLong is the fixed, unpadded size of a [SPA_TYPE_Long] value.
- SizeLong = 8
+ SizeLong Word = 8
)
/* Basic types */
@@ -86,6 +86,24 @@ const (
_SPA_TYPE_LAST // not part of ABI
)
+// A KnownSize value has known POD encoded size before serialisation.
+type KnownSize interface {
+ // Size returns the POD encoded size of the receiver.
+ Size() Word
+}
+
+// PaddingSize returns the padding size corresponding to a wire size.
+func PaddingSize[W Word | int](wireSize W) W { return (SizeAlign - (wireSize)%SizeAlign) % SizeAlign }
+
+// PaddedSize returns the padded size corresponding to a wire size.
+func PaddedSize[W Word | int](wireSize W) W { return wireSize + PaddingSize(wireSize) }
+
+// Size returns prefixed and padded size corresponding to a wire size.
+func Size[W Word | int](wireSize W) W { return SizePrefix + PaddedSize(wireSize) }
+
+// SizeString returns prefixed and padded size corresponding to a string.
+func SizeString[W Word | int](s string) W { return Size(W(len(s)) + 1) }
+
// PODMarshaler is the interface implemented by an object that can
// marshal itself into PipeWire POD encoding.
type PODMarshaler interface {
@@ -125,14 +143,13 @@ func appendInner(data []byte, f func(data []byte) ([]byte, error)) ([]byte, erro
}
size := len(rData) - len(data) + SizeSPrefix
- paddingSize := (SizeAlign - (size)%SizeAlign) % SizeAlign
// compensated for size and type prefix
wireSize := size - SizePrefix
if wireSize > math.MaxUint32 {
return data, UnsupportedSizeError(wireSize)
}
binary.NativeEndian.PutUint32(rData[len(data)-SizeSPrefix:len(data)], Word(wireSize))
- rData = append(rData, make([]byte, paddingSize)...)
+ rData = append(rData, make([]byte, PaddingSize(size))...)
return rData, nil
}
@@ -242,7 +259,7 @@ func UnmarshalNext(data []byte, v any) (size Word, err error) {
}
err = unmarshalValue(data, rv.Elem(), &size)
// prefix and padding size
- size += SizePrefix + (SizeAlign-(size)%SizeAlign)%SizeAlign
+ size = Size(size)
return
}
@@ -325,9 +342,8 @@ func unmarshalValue(data []byte, v reflect.Value, wireSizeP *Word) error {
if err := unmarshalValue(data, v.Field(i), &fieldWireSize); err != nil {
return err
}
- paddingSize := (SizeAlign - (fieldWireSize)%SizeAlign) % SizeAlign
// bounds check completed in successful call to unmarshalValue
- data = data[SizePrefix+fieldWireSize+paddingSize:]
+ data = data[Size(fieldWireSize):]
}
if len(data) != 0 {
@@ -441,6 +457,17 @@ type SPADict struct {
Items []SPADictItem
}
+// Size satisfies [KnownSize] with a value computed at runtime.
+func (d *SPADict) Size() Word {
+ // struct prefix, NItems value
+ size := SizePrefix + int(Size(SizeInt))
+ for i := range d.Items {
+ size += SizeString[int](d.Items[i].Key)
+ size += SizeString[int](d.Items[i].Value)
+ }
+ return Word(size)
+}
+
// MarshalPOD satisfies [PODMarshaler] as [SPADict] violates the POD type system.
func (d *SPADict) MarshalPOD() ([]byte, error) {
return appendInner(nil, func(dataPrefix []byte) (data []byte, err error) {