internal/pipewire: use custom marshaler when available
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 45s
Test / Sandbox (race detector) (push) Successful in 2m19s
Test / Hakurei (push) Successful in 2m27s
Test / Hakurei (race detector) (push) Successful in 3m12s
Test / Hpkg (push) Successful in 3m31s
Test / Flake checks (push) Successful in 1m34s
All checks were successful
Test / Create distribution (push) Successful in 37s
Test / Sandbox (push) Successful in 45s
Test / Sandbox (race detector) (push) Successful in 2m19s
Test / Hakurei (push) Successful in 2m27s
Test / Hakurei (race detector) (push) Successful in 3m12s
Test / Hpkg (push) Successful in 3m31s
Test / Flake checks (push) Successful in 1m34s
This reduces special cases. This change also exposes unmarshalled message size on the wire. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
827dc9e1ba
commit
8f4a3bcf9f
@ -76,4 +76,7 @@ type CoreHello struct {
|
|||||||
func (c *CoreHello) MarshalBinary() ([]byte, error) { return MarshalAppend(make([]byte, 0, 24), c) }
|
func (c *CoreHello) MarshalBinary() ([]byte, error) { return MarshalAppend(make([]byte, 0, 24), c) }
|
||||||
|
|
||||||
// UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal].
|
// UnmarshalBinary satisfies [encoding.BinaryUnmarshaler] via [Unmarshal].
|
||||||
func (c *CoreHello) UnmarshalBinary(data []byte) error { return Unmarshal(data, c) }
|
func (c *CoreHello) UnmarshalBinary(data []byte) error {
|
||||||
|
_, err := Unmarshal(data, c)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@ -65,6 +65,13 @@ const (
|
|||||||
_SPA_TYPE_LAST // not part of ABI
|
_SPA_TYPE_LAST // not part of ABI
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PODMarshaler is the interface implemented by an object that can
|
||||||
|
// marshal itself into PipeWire POD encoding.
|
||||||
|
type PODMarshaler interface {
|
||||||
|
// MarshalPOD encodes the receiver into PipeWire POD encoding and returns the result.
|
||||||
|
MarshalPOD() ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
// An UnsupportedTypeError is returned by [Marshal] when attempting
|
// An UnsupportedTypeError is returned by [Marshal] when attempting
|
||||||
// to encode an unsupported value type.
|
// to encode an unsupported value type.
|
||||||
type UnsupportedTypeError struct{ Type reflect.Type }
|
type UnsupportedTypeError struct{ Type reflect.Type }
|
||||||
@ -86,11 +93,12 @@ func MarshalAppend(data []byte, v any) ([]byte, error) {
|
|||||||
return marshalValueAppend(data, reflect.ValueOf(v))
|
return marshalValueAppend(data, reflect.ValueOf(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value].
|
// appendInner calls f and handles size prefix and padding around the appended data.
|
||||||
func marshalValueAppend(data []byte, v reflect.Value) ([]byte, error) {
|
// 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, 4)...)
|
||||||
|
|
||||||
rData, err := marshalValueAppendRaw(data, v)
|
rData, err := f(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
@ -108,6 +116,18 @@ func marshalValueAppend(data []byte, v reflect.Value) ([]byte, error) {
|
|||||||
return rData, nil
|
return rData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value].
|
||||||
|
func marshalValueAppend(data []byte, v reflect.Value) ([]byte, error) {
|
||||||
|
if v.CanInterface() {
|
||||||
|
if m, ok := v.Interface().(PODMarshaler); ok {
|
||||||
|
extraData, err := m.MarshalPOD()
|
||||||
|
return append(data, extraData...), err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return appendInner(data, func(data []byte) ([]byte, error) { return marshalValueAppendRaw(data, v) })
|
||||||
|
}
|
||||||
|
|
||||||
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value] without the size prefix.
|
// marshalValueAppendRaw implements [MarshalAppend] on [reflect.Value] without the size prefix.
|
||||||
func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) {
|
func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) {
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
@ -146,6 +166,15 @@ func marshalValueAppendRaw(data []byte, v reflect.Value) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PODUnmarshaler is the interface implemented by an object that can
|
||||||
|
// unmarshal a PipeWire POD encoding representation of itself.
|
||||||
|
type PODUnmarshaler interface {
|
||||||
|
// UnmarshalPOD must be able to decode the form generated by MarshalPOD.
|
||||||
|
// UnmarshalPOD must copy the data if it wishes to retain the data
|
||||||
|
// after returning.
|
||||||
|
UnmarshalPOD(data []byte) (Word, error)
|
||||||
|
}
|
||||||
|
|
||||||
// An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal].
|
// An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal].
|
||||||
// (The argument to [Unmarshal] must be a non-nil pointer.)
|
// (The argument to [Unmarshal] must be a non-nil pointer.)
|
||||||
type InvalidUnmarshalError struct{ Type reflect.Type }
|
type InvalidUnmarshalError struct{ Type reflect.Type }
|
||||||
@ -164,12 +193,17 @@ func (e *InvalidUnmarshalError) Error() string {
|
|||||||
// Unmarshal parses the JSON-encoded data and stores the result
|
// Unmarshal parses the JSON-encoded data and stores the result
|
||||||
// in the value pointed to by v. If v is nil or not a pointer,
|
// in the value pointed to by v. If v is nil or not a pointer,
|
||||||
// Unmarshal returns an [InvalidUnmarshalError].
|
// Unmarshal returns an [InvalidUnmarshalError].
|
||||||
func Unmarshal(data []byte, v any) error {
|
func Unmarshal(data []byte, v any) (size Word, err error) {
|
||||||
rv := reflect.ValueOf(v)
|
rv := reflect.ValueOf(v)
|
||||||
if rv.Kind() != reflect.Pointer || rv.IsNil() {
|
if rv.Kind() != reflect.Pointer || rv.IsNil() {
|
||||||
return &InvalidUnmarshalError{reflect.TypeOf(v)}
|
return 0, &InvalidUnmarshalError{reflect.TypeOf(v)}
|
||||||
}
|
}
|
||||||
return unmarshalValue(data, rv.Elem(), new(Word))
|
err = unmarshalValue(data, rv.Elem(), &size)
|
||||||
|
// size and type prefix
|
||||||
|
size += 8
|
||||||
|
// padding
|
||||||
|
size += (8 - (size)%8) % 8
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalSetError describes a value that cannot be set during [Unmarshal].
|
// UnmarshalSetError describes a value that cannot be set during [Unmarshal].
|
||||||
@ -199,6 +233,22 @@ func (e StringTerminationError) Error() string {
|
|||||||
|
|
||||||
// unmarshalValue implements [Unmarshal] on [reflect.Value].
|
// unmarshalValue implements [Unmarshal] on [reflect.Value].
|
||||||
func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
|
func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
|
||||||
|
if !v.CanSet() {
|
||||||
|
return &UnmarshalSetError{v.Type()}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.CanInterface() {
|
||||||
|
if v.Kind() == reflect.Pointer {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if u, ok := v.Interface().(PODUnmarshaler); ok {
|
||||||
|
var err error
|
||||||
|
*sizeP, err = u.UnmarshalPOD(data)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
|
|
||||||
case reflect.Int32:
|
case reflect.Int32:
|
||||||
@ -206,9 +256,6 @@ func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
|
|||||||
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, sizeP); err != nil {
|
if err := unmarshalCheckTypeBounds(&data, SPA_TYPE_Int, sizeP); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !v.CanSet() {
|
|
||||||
return &UnmarshalSetError{v.Type()}
|
|
||||||
}
|
|
||||||
v.SetInt(int64(binary.NativeEndian.Uint32(data)))
|
v.SetInt(int64(binary.NativeEndian.Uint32(data)))
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
@ -223,7 +270,7 @@ func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
paddingSize := (8 - (fieldWireSize)%8) % 8
|
paddingSize := (8 - (fieldWireSize)%8) % 8
|
||||||
// already bounds checked by the successful unmarshalValue call
|
// bounds check completed in successful call to unmarshalValue
|
||||||
data = data[8+fieldWireSize+paddingSize:]
|
data = data[8+fieldWireSize+paddingSize:]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,10 +280,6 @@ func unmarshalValue(data []byte, v reflect.Value, sizeP *Word) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
case reflect.Pointer:
|
case reflect.Pointer:
|
||||||
if !v.CanSet() {
|
|
||||||
return &UnmarshalSetError{v.Type()}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(data) < 8 {
|
if len(data) < 8 {
|
||||||
return io.ErrUnexpectedEOF
|
return io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user