use std::{
convert::TryInto,
ffi::CString,
io::{Seek, SeekFrom, Write},
marker::PhantomData,
};
pub use cookie_factory::GenError;
use cookie_factory::{
bytes::{ne_u32, ne_u64, ne_u8},
combinator::slice,
gen,
multi::all,
sequence::{pair, tuple},
SerializeFn,
};
use crate::{
pod::ChoiceValue,
utils::{Choice, ChoiceEnum},
};
use super::{CanonicalFixedSizedPod, FixedSizedPod, PropertyFlags, Value, ValueArray};
pub trait PodSerialize {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError>;
}
impl PodSerialize for str {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
serializer.serialize_string(self)
}
}
impl PodSerialize for [u8] {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
serializer.serialize_bytes(self)
}
}
impl PodSerialize for Value {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
fn serialize_array<E: FixedSizedPod, O: Write + Seek>(
array: &[E],
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
let mut arr_serializer = serializer.serialize_array(array.len() as u32)?;
for e in array.iter() {
arr_serializer.serialize_element(e)?;
}
arr_serializer.end()
}
match self {
Value::None => serializer.serialized_fixed_sized_pod(&()),
Value::Bool(b) => serializer.serialized_fixed_sized_pod(b),
Value::Id(id) => serializer.serialized_fixed_sized_pod(id),
Value::Int(i) => serializer.serialized_fixed_sized_pod(i),
Value::Long(l) => serializer.serialized_fixed_sized_pod(l),
Value::Float(f) => serializer.serialized_fixed_sized_pod(f),
Value::Double(d) => serializer.serialized_fixed_sized_pod(d),
Value::String(s) => serializer.serialize_string(s.as_str()),
Value::Bytes(b) => serializer.serialize_bytes(b.as_slice()),
Value::Rectangle(rect) => serializer.serialized_fixed_sized_pod(rect),
Value::Fraction(frac) => serializer.serialized_fixed_sized_pod(frac),
Value::Fd(fd) => serializer.serialized_fixed_sized_pod(fd),
Value::ValueArray(array) => match array {
ValueArray::None(arr) => serialize_array(arr, serializer),
ValueArray::Bool(arr) => serialize_array(arr, serializer),
ValueArray::Id(arr) => serialize_array(arr, serializer),
ValueArray::Int(arr) => serialize_array(arr, serializer),
ValueArray::Long(arr) => serialize_array(arr, serializer),
ValueArray::Float(arr) => serialize_array(arr, serializer),
ValueArray::Double(arr) => serialize_array(arr, serializer),
ValueArray::Rectangle(arr) => serialize_array(arr, serializer),
ValueArray::Fraction(arr) => serialize_array(arr, serializer),
ValueArray::Fd(arr) => serialize_array(arr, serializer),
},
Value::Struct(array) => {
let mut struct_serializer = serializer.serialize_struct()?;
for elem in array.iter() {
struct_serializer.serialize_field(elem)?;
}
struct_serializer.end()
}
Value::Object(object) => {
let mut object_serializer = serializer.serialize_object(object.type_, object.id)?;
for prop in object.properties.iter() {
object_serializer.serialize_property(prop.key, &prop.value, prop.flags)?;
}
object_serializer.end()
}
Value::Choice(choice) => match choice {
ChoiceValue::Int(choice) => serializer.serialize_choice(choice),
ChoiceValue::Long(choice) => serializer.serialize_choice(choice),
ChoiceValue::Float(choice) => serializer.serialize_choice(choice),
ChoiceValue::Double(choice) => serializer.serialize_choice(choice),
ChoiceValue::Id(choice) => serializer.serialize_choice(choice),
ChoiceValue::Rectangle(choice) => serializer.serialize_choice(choice),
ChoiceValue::Fraction(choice) => serializer.serialize_choice(choice),
ChoiceValue::Fd(choice) => serializer.serialize_choice(choice),
},
Value::Pointer(type_, pointer) => serializer.serialize_pointer(*type_, *pointer),
}
}
}
impl<P: FixedSizedPod> PodSerialize for [P] {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
let mut arr_serializer = serializer.serialize_array(
self.len()
.try_into()
.expect("Array length does not fit in a u32"),
)?;
for element in self.iter() {
arr_serializer.serialize_element(element)?;
}
arr_serializer.end()
}
}
impl<T> PodSerialize for (u32, *const T) {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
serializer.serialize_pointer(self.0, self.1)
}
}
pub struct SerializeSuccess<O: Write + Seek> {
serializer: PodSerializer<O>,
len: u64,
}
pub struct PodSerializer<O: Write + Seek> {
out: Option<O>,
}
impl<O: Write + Seek> PodSerializer<O> {
pub fn serialize<P>(out: O, pod: &P) -> Result<(O, u64), GenError>
where
P: PodSerialize + ?Sized,
{
let serializer = Self { out: Some(out) };
pod.serialize(serializer).map(|success| {
(
success
.serializer
.out
.expect("Serializer does not contain a writer"),
success.len,
)
})
}
fn header(size: usize, ty: u32) -> impl SerializeFn<O> {
pair(ne_u32(size as u32), ne_u32(ty))
}
fn padding(len: usize) -> impl SerializeFn<O> {
let zeroes = std::iter::repeat(0u8);
all(zeroes.take(len).map(ne_u8))
}
fn gen(&mut self, f: impl SerializeFn<O>) -> Result<u64, GenError> {
gen(
f,
self.out
.take()
.expect("PodSerializer does not contain a writer"),
)
.map(|(writer, len)| {
self.out = Some(writer);
len
})
}
fn write_pod(
mut self,
size: usize,
type_: u32,
f: impl SerializeFn<O>,
) -> Result<SerializeSuccess<O>, GenError> {
let padding = if size % 8 == 0 { 0 } else { 8 - (size % 8) };
let written = self.gen(tuple((
Self::header(size, type_),
f,
Self::padding(padding),
)))?;
Ok(SerializeSuccess {
serializer: self,
len: written,
})
}
pub fn serialized_fixed_sized_pod<P>(self, pod: &P) -> Result<SerializeSuccess<O>, GenError>
where
P: FixedSizedPod + ?Sized,
{
self.write_pod(
P::CanonicalType::SIZE as usize,
P::CanonicalType::TYPE,
|out| pod.as_canonical_type().serialize_body(out),
)
}
pub fn serialize_string(self, string: &str) -> Result<SerializeSuccess<O>, GenError> {
let cstr = CString::new(string)
.expect("Pod::String contains string with '\0' byte")
.into_bytes_with_nul();
self.write_pod(cstr.len(), spa_sys::SPA_TYPE_String, slice(cstr))
}
pub fn serialize_bytes(self, bytes: &[u8]) -> Result<SerializeSuccess<O>, GenError> {
self.write_pod(bytes.len(), spa_sys::SPA_TYPE_Bytes, slice(bytes))
}
pub fn serialize_array<P: FixedSizedPod>(
mut self,
length: u32,
) -> Result<ArrayPodSerializer<O, P>, GenError> {
self.gen(pair(
Self::header(
(8 + length * P::CanonicalType::SIZE) as usize,
spa_sys::SPA_TYPE_Array,
),
Self::header(P::CanonicalType::SIZE as usize, P::CanonicalType::TYPE),
))?;
Ok(ArrayPodSerializer {
serializer: self,
length,
written: 0,
_phantom: PhantomData,
})
}
pub fn serialize_struct(mut self) -> Result<StructPodSerializer<O>, GenError> {
let header_position = self
.out
.as_mut()
.expect("PodSerializer does not contain a writer")
.stream_position()
.expect("Could not get current position in writer");
self.gen(Self::header(0, spa_sys::SPA_TYPE_Struct))?;
Ok(StructPodSerializer {
serializer: Some(self),
header_position,
written: 0,
})
}
pub fn serialize_object(
mut self,
object_type: u32,
object_id: u32,
) -> Result<ObjectPodSerializer<O>, GenError> {
let header_position = self
.out
.as_mut()
.expect("PodSerializer does not contain a writer")
.stream_position()
.expect("Could not get current position in writer");
self.gen(Self::header(0, spa_sys::SPA_TYPE_Object))?;
self.gen(pair(ne_u32(object_type), ne_u32(object_id)))?;
Ok(ObjectPodSerializer {
serializer: Some(self),
header_position,
written: 0,
})
}
pub fn serialize_choice<T: CanonicalFixedSizedPod>(
mut self,
choice: &Choice<T>,
) -> Result<SerializeSuccess<O>, GenError> {
let flags = choice.0;
let (choice_type, values) = match &choice.1 {
ChoiceEnum::None(value) => (spa_sys::spa_choice_type_SPA_CHOICE_None, vec![value]),
ChoiceEnum::Range { default, min, max } => (
spa_sys::spa_choice_type_SPA_CHOICE_Range,
vec![default, min, max],
),
ChoiceEnum::Step {
default,
min,
max,
step,
} => (
spa_sys::spa_choice_type_SPA_CHOICE_Step,
vec![default, min, max, step],
),
ChoiceEnum::Enum {
default,
alternatives,
} => {
let mut values = vec![default];
values.extend(alternatives);
(spa_sys::spa_choice_type_SPA_CHOICE_Enum, values)
}
ChoiceEnum::Flags { default, flags } => {
let mut values = vec![default];
values.extend(flags);
(spa_sys::spa_choice_type_SPA_CHOICE_Flags, values)
}
};
let len: usize = 2 * 8 + values.len() * (T::SIZE as usize);
self.gen(Self::header(len, spa_sys::SPA_TYPE_Choice))?;
self.gen(pair(ne_u32(choice_type), ne_u32(flags.bits())))?;
self.gen(pair(ne_u32(T::SIZE), ne_u32(T::TYPE)))?;
for v in values {
self.gen(|out| v.serialize_body(out))?;
}
let padding = if len % 8 == 0 {
0
} else {
8 - (len as usize % 8)
};
let pad_bytes = self.gen(PodSerializer::padding(padding))?;
Ok(SerializeSuccess {
serializer: self,
len: len as u64 + pad_bytes,
})
}
pub fn serialize_pointer<T>(
mut self,
type_: u32,
ptr: *const T,
) -> Result<SerializeSuccess<O>, GenError> {
let ptr_size = std::mem::size_of::<usize>();
let len = 8 + ptr_size;
let mut written = self.gen(Self::header(len, spa_sys::SPA_TYPE_Pointer))?;
written += self.gen(pair(ne_u32(type_), ne_u32(0)))?;
written += match ptr_size {
4 => self.gen(ne_u32(ptr as u32))?,
8 => self.gen(ne_u64(ptr as u64))?,
_ => panic!("unsupported pointer size {}", ptr_size),
};
Ok(SerializeSuccess {
serializer: self,
len: written,
})
}
}
pub struct ArrayPodSerializer<O: Write + Seek, P: FixedSizedPod> {
serializer: PodSerializer<O>,
length: u32,
written: u32,
_phantom: PhantomData<P>,
}
impl<O: Write + Seek, P: FixedSizedPod> ArrayPodSerializer<O, P> {
pub fn serialize_element(&mut self, elem: &P) -> Result<u64, GenError> {
if !self.written < self.length {
panic!("More elements than specified were serialized into the array POD");
}
let result = self
.serializer
.gen(|out| elem.as_canonical_type().serialize_body(out));
self.written += 1;
result
}
pub fn end(mut self) -> Result<SerializeSuccess<O>, GenError> {
assert_eq!(
self.length, self.written,
"Array POD was not serialized with the specified amount of elements"
);
let bytes_written = self.written * P::CanonicalType::SIZE;
let padding = if bytes_written % 8 == 0 {
0
} else {
8 - (bytes_written as usize % 8)
};
let pad_bytes = self.serializer.gen(PodSerializer::padding(padding))?;
Ok(SerializeSuccess {
serializer: self.serializer,
len: 16 + u64::from(self.written * P::CanonicalType::SIZE) + pad_bytes,
})
}
}
pub struct StructPodSerializer<O: Write + Seek> {
serializer: Option<PodSerializer<O>>,
header_position: u64,
written: usize,
}
impl<O: Write + Seek> StructPodSerializer<O> {
pub fn serialize_field<P>(&mut self, field: &P) -> Result<u64, GenError>
where
P: PodSerialize + ?Sized,
{
let success = field.serialize(
self.serializer
.take()
.expect("StructSerializer does not contain a serializer"),
)?;
self.written += success.len as usize;
self.serializer = Some(success.serializer);
Ok(success.len)
}
pub fn end(self) -> Result<SerializeSuccess<O>, GenError> {
let mut serializer = self
.serializer
.expect("StructSerializer does not contain a serializer");
serializer
.out
.as_mut()
.expect("Serializer does not contain a writer")
.seek(SeekFrom::Start(self.header_position))
.expect("Failed to seek to header position");
serializer.gen(PodSerializer::header(
self.written,
spa_sys::SPA_TYPE_Struct,
))?;
serializer
.out
.as_mut()
.expect("Serializer does not contain a writer")
.seek(SeekFrom::End(0))
.expect("Failed to seek to end");
Ok(SerializeSuccess {
serializer,
len: self.written as u64 + 8,
})
}
}
pub struct ObjectPodSerializer<O: Write + Seek> {
serializer: Option<PodSerializer<O>>,
header_position: u64,
written: usize,
}
impl<O: Write + Seek> ObjectPodSerializer<O> {
pub fn serialize_property<P>(
&mut self,
key: u32,
value: &P,
flags: PropertyFlags,
) -> Result<u64, GenError>
where
P: PodSerialize + ?Sized,
{
let mut serializer = self
.serializer
.take()
.expect("ObjectPodSerializer does not contain a serializer");
serializer.gen(pair(ne_u32(key), ne_u32(flags.bits())))?;
let mut success = value.serialize(serializer)?;
success.len += 8;
self.written += success.len as usize;
self.serializer = Some(success.serializer);
Ok(success.len)
}
pub fn end(self) -> Result<SerializeSuccess<O>, GenError> {
let mut serializer = self
.serializer
.expect("ObjectSerializer does not contain a serializer");
serializer
.out
.as_mut()
.expect("Serializer does not contain a writer")
.seek(SeekFrom::Start(self.header_position))
.expect("Failed to seek to header position");
let written = self.written + 8;
serializer.gen(PodSerializer::header(written, spa_sys::SPA_TYPE_Object))?;
serializer
.out
.as_mut()
.expect("Serializer does not contain a writer")
.seek(SeekFrom::End(0))
.expect("Failed to seek to end");
Ok(SerializeSuccess {
serializer,
len: written as u64,
})
}
}
impl<T: CanonicalFixedSizedPod + FixedSizedPod> PodSerialize for Choice<T> {
fn serialize<O: Write + Seek>(
&self,
serializer: PodSerializer<O>,
) -> Result<SerializeSuccess<O>, GenError> {
serializer.serialize_choice(self)
}
}