use crate::space::*;
use crate::*;
use std::convert::TryFrom;
use std::iter::Iterator;
use urid::UriBound;
use urid::URID;
pub struct Object;
unsafe impl UriBound for Object {
const URI: &'static [u8] = sys::LV2_ATOM__Object;
}
pub struct ObjectHeader {
pub id: Option<URID>,
pub otype: URID,
}
impl<'a, 'b> Atom<'a, 'b> for Object
where
'a: 'b,
{
type ReadParameter = ();
type ReadHandle = (ObjectHeader, ObjectReader<'a>);
type WriteParameter = ObjectHeader;
type WriteHandle = ObjectWriter<'a, 'b>;
fn read(body: Space<'a>, _: ()) -> Option<(ObjectHeader, ObjectReader<'a>)> {
let (header, body) = body.split_type::<sys::LV2_Atom_Object_Body>()?;
let header = ObjectHeader {
id: URID::try_from(header.id).ok(),
otype: URID::try_from(header.otype).ok()?,
};
let reader = ObjectReader { space: body };
Some((header, reader))
}
fn init(
mut frame: FramedMutSpace<'a, 'b>,
header: ObjectHeader,
) -> Option<ObjectWriter<'a, 'b>> {
{
let frame = &mut frame as &mut dyn MutSpace;
frame.write(
&sys::LV2_Atom_Object_Body {
id: header.id.map(|urid| urid.get()).unwrap_or(0),
otype: header.otype.get(),
},
true,
);
}
Some(ObjectWriter { frame })
}
}
#[deprecated]
pub struct Blank;
#[allow(deprecated)]
unsafe impl UriBound for Blank {
const URI: &'static [u8] = sys::LV2_ATOM__Blank;
}
#[allow(deprecated)]
impl<'a, 'b> Atom<'a, 'b> for Blank
where
'a: 'b,
{
type ReadParameter = <Object as Atom<'a, 'b>>::ReadParameter;
type ReadHandle = <Object as Atom<'a, 'b>>::ReadHandle;
type WriteParameter = <Object as Atom<'a, 'b>>::WriteParameter;
type WriteHandle = <Object as Atom<'a, 'b>>::WriteHandle;
#[allow(clippy::unit_arg)]
fn read(body: Space<'a>, parameter: Self::ReadParameter) -> Option<Self::ReadHandle> {
Object::read(body, parameter)
}
fn init(
frame: FramedMutSpace<'a, 'b>,
parameter: Self::WriteParameter,
) -> Option<Self::WriteHandle> {
Object::init(frame, parameter)
}
}
pub struct ObjectReader<'a> {
space: Space<'a>,
}
impl<'a> Iterator for ObjectReader<'a> {
type Item = (PropertyHeader, UnidentifiedAtom<'a>);
fn next(&mut self) -> Option<(PropertyHeader, UnidentifiedAtom<'a>)> {
let (header, value, space) = Property::read_body(self.space)?;
self.space = space;
Some((header, UnidentifiedAtom::new(value)))
}
}
pub struct ObjectWriter<'a, 'b> {
frame: FramedMutSpace<'a, 'b>,
}
impl<'a, 'b> ObjectWriter<'a, 'b> {
pub fn init<'c, G: ?Sized, A: Atom<'a, 'c>>(
&'c mut self,
key: URID<G>,
context: Option<URID>,
child_urid: URID<A>,
parameter: A::WriteParameter,
) -> Option<A::WriteHandle> {
Property::write_header(&mut self.frame, key.into_general(), context)?;
(&mut self.frame as &mut dyn MutSpace).init(child_urid, parameter)
}
}
pub struct Property;
unsafe impl UriBound for Property {
const URI: &'static [u8] = sys::LV2_ATOM__Property;
}
#[derive(Clone, Copy)]
pub struct PropertyHeader {
pub key: URID,
pub context: Option<URID>,
}
impl Property {
fn read_body(space: Space) -> Option<(PropertyHeader, Space, Space)> {
#[repr(C)]
#[derive(Clone, Copy)]
struct StrippedPropertyBody {
key: u32,
context: u32,
}
let (header, space) = space.split_type::<StrippedPropertyBody>()?;
let header = PropertyHeader {
key: URID::try_from(header.key).ok()?,
context: URID::try_from(header.context).ok(),
};
let (atom, space) = space.split_atom()?;
Some((header, atom, space))
}
fn write_header(space: &mut dyn MutSpace, key: URID, context: Option<URID>) -> Option<()> {
space.write(&key.get(), true)?;
space.write(&context.map(|urid| urid.get()).unwrap_or(0), false)?;
Some(())
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::space::*;
use std::mem::size_of;
use urid::*;
#[test]
fn test_object() {
let map = HashURIDMapper::new();
let urids = AtomURIDCollection::from_map(&map).unwrap();
let object_type = map
.map_uri(Uri::from_bytes_with_nul(b"urn:my-type\0").unwrap())
.unwrap();
let first_key = map
.map_uri(Uri::from_bytes_with_nul(b"urn:value-a\0").unwrap())
.unwrap();
let first_value: i32 = 17;
let second_key = map
.map_uri(Uri::from_bytes_with_nul(b"urn:value-b\0").unwrap())
.unwrap();
let second_value: f32 = 42.0;
let mut raw_space: Box<[u8]> = Box::new([0; 256]);
{
let mut space = RootMutSpace::new(raw_space.as_mut());
let frame = FramedMutSpace::new(&mut space as &mut dyn MutSpace, urids.object).unwrap();
let mut writer = Object::init(
frame,
ObjectHeader {
id: None,
otype: object_type,
},
)
.unwrap();
{
writer
.init(first_key, None, urids.int, first_value)
.unwrap();
}
{
writer
.init(second_key, None, urids.float, second_value)
.unwrap();
}
}
{
let (atom, space) = raw_space.split_at(size_of::<sys::LV2_Atom>());
let atom = unsafe { &*(atom.as_ptr() as *const sys::LV2_Atom) };
assert_eq!(atom.type_, urids.object);
assert_eq!(
atom.size as usize,
size_of::<sys::LV2_Atom_Object_Body>()
+ size_of::<sys::LV2_Atom_Property_Body>()
+ 2 * size_of::<i32>()
+ size_of::<sys::LV2_Atom_Property_Body>()
+ size_of::<f32>()
);
let (object, space) = space.split_at(size_of::<sys::LV2_Atom_Object_Body>());
let object = unsafe { &*(object.as_ptr() as *const sys::LV2_Atom_Object_Body) };
assert_eq!(object.id, 0);
assert_eq!(object.otype, object_type);
let (property, space) = space.split_at(size_of::<sys::LV2_Atom_Property_Body>());
let property = unsafe { &*(property.as_ptr() as *const sys::LV2_Atom_Property_Body) };
assert_eq!(property.key, first_key);
assert_eq!(property.context, 0);
assert_eq!(property.value.type_, urids.int);
assert_eq!(property.value.size as usize, size_of::<i32>());
let (value, space) = space.split_at(size_of::<i32>());
let value = unsafe { *(value.as_ptr() as *const i32) };
assert_eq!(value, first_value);
let (_, space) = space.split_at(size_of::<i32>());
let (property, space) = space.split_at(size_of::<sys::LV2_Atom_Property_Body>());
let property = unsafe { &*(property.as_ptr() as *const sys::LV2_Atom_Property_Body) };
assert_eq!(property.key, second_key);
assert_eq!(property.context, 0);
assert_eq!(property.value.type_, urids.float);
assert_eq!(property.value.size as usize, size_of::<f32>());
let (value, _) = space.split_at(size_of::<f32>());
let value = unsafe { *(value.as_ptr() as *const f32) };
assert_eq!(value, second_value);
}
{
let space = Space::from_slice(raw_space.as_ref());
let (body, _) = space.split_atom_body(urids.object).unwrap();
let (header, iter) = Object::read(body, ()).unwrap();
assert_eq!(header.otype, object_type);
assert_eq!(header.id, None);
let properties: Vec<(PropertyHeader, UnidentifiedAtom)> = iter.collect();
let (header, atom) = properties[0];
assert_eq!(header.key, first_key);
assert_eq!(atom.read::<Int>(urids.int, ()).unwrap(), first_value);
let (header, atom) = properties[1];
assert_eq!(header.key, second_key);
assert_eq!(atom.read::<Float>(urids.float, ()).unwrap(), second_value);
}
}
}