lv2_atom/
tuple.rs

1//! An atom containg a series of other atoms.
2//!
3//! This atom is just like a [sequence](../sequence/index.html), only without time stamps: It contains multiple arbitrary atoms which you can either iterate through or write in sequence.
4//!
5//! # Example
6//! ```
7//! use lv2_core::prelude::*;
8//! use lv2_atom::prelude::*;
9//! use lv2_atom::tuple::{TupleIterator, TupleWriter};
10//!
11//! #[derive(PortCollection)]
12//! struct MyPorts {
13//!     input: InputPort<AtomPort>,
14//!     output: OutputPort<AtomPort>,
15//! }
16//!
17//! fn run(ports: &mut MyPorts, urids: &AtomURIDCollection) {
18//!     let input: TupleIterator = ports.input.read(urids.tuple, ()).unwrap();
19//!     let mut output: TupleWriter = ports.output.init(urids.tuple, ()).unwrap();
20//!     for atom in input {
21//!         if let Some(integer) = atom.read(urids.int, ()) {
22//!             output.init(urids.int, integer * 2).unwrap();
23//!         } else {
24//!             output.init(urids.int, -1).unwrap();
25//!         }
26//!     }
27//! }
28//! ```
29//!
30//! # Specification
31//!
32//! [http://lv2plug.in/ns/ext/atom/atom.html#Tuple](http://lv2plug.in/ns/ext/atom/atom.html#Tuple)
33use crate::space::*;
34use crate::*;
35use urid::*;
36
37/// An atom  containing a series of other atoms.
38///
39/// [See also the module documentation.](index.html)
40pub struct Tuple;
41
42unsafe impl UriBound for Tuple {
43    const URI: &'static [u8] = sys::LV2_ATOM__Tuple;
44}
45
46impl<'a, 'b> Atom<'a, 'b> for Tuple
47where
48    'a: 'b,
49{
50    type ReadParameter = ();
51    type ReadHandle = TupleIterator<'a>;
52    type WriteParameter = ();
53    type WriteHandle = TupleWriter<'a, 'b>;
54
55    fn read(body: Space<'a>, _: ()) -> Option<TupleIterator<'a>> {
56        Some(TupleIterator { space: body })
57    }
58
59    fn init(frame: FramedMutSpace<'a, 'b>, _: ()) -> Option<TupleWriter<'a, 'b>> {
60        Some(TupleWriter { frame })
61    }
62}
63
64/// An iterator over all atoms in a tuple.
65///
66/// The item of this iterator is simply the space a single atom occupies.
67pub struct TupleIterator<'a> {
68    space: Space<'a>,
69}
70
71impl<'a> Iterator for TupleIterator<'a> {
72    type Item = UnidentifiedAtom<'a>;
73
74    fn next(&mut self) -> Option<UnidentifiedAtom<'a>> {
75        let (atom, space) = self.space.split_atom()?;
76        self.space = space;
77        Some(UnidentifiedAtom::new(atom))
78    }
79}
80
81/// The writing handle to add atoms to a tuple.
82pub struct TupleWriter<'a, 'b> {
83    frame: FramedMutSpace<'a, 'b>,
84}
85
86impl<'a, 'b> TupleWriter<'a, 'b> {
87    /// Initialize a new tuple element.
88    pub fn init<'c, A: Atom<'a, 'c>>(
89        &'c mut self,
90        child_urid: URID<A>,
91        child_parameter: A::WriteParameter,
92    ) -> Option<A::WriteHandle> {
93        (&mut self.frame as &mut dyn MutSpace).init(child_urid, child_parameter)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use crate::prelude::*;
100    use crate::space::*;
101    use std::mem::size_of;
102    use urid::*;
103
104    #[test]
105    fn test_tuple() {
106        let map = HashURIDMapper::new();
107        let urids = crate::AtomURIDCollection::from_map(&map).unwrap();
108
109        let mut raw_space: Box<[u8]> = Box::new([0; 256]);
110
111        // writing
112        {
113            let mut space = RootMutSpace::new(raw_space.as_mut());
114            let mut writer = (&mut space as &mut dyn MutSpace)
115                .init(urids.tuple, ())
116                .unwrap();
117            {
118                let mut vector_writer =
119                    writer.init::<Vector<Int>>(urids.vector, urids.int).unwrap();
120                vector_writer.append(&[17; 9]).unwrap();
121            }
122            writer.init::<Int>(urids.int, 42).unwrap();
123        }
124
125        // verifying
126        {
127            let (atom, space) = raw_space.split_at(size_of::<sys::LV2_Atom>());
128            let atom = unsafe { &*(atom.as_ptr() as *const sys::LV2_Atom) };
129            assert_eq!(atom.type_, urids.tuple);
130            assert_eq!(
131                atom.size as usize,
132                size_of::<sys::LV2_Atom_Vector>()
133                    + size_of::<i32>() * 9
134                    + 4
135                    + size_of::<sys::LV2_Atom_Int>()
136            );
137
138            let (vector, space) = space.split_at(size_of::<sys::LV2_Atom_Vector>());
139            let vector = unsafe { &*(vector.as_ptr() as *const sys::LV2_Atom_Vector) };
140            assert_eq!(vector.atom.type_, urids.vector);
141            assert_eq!(
142                vector.atom.size as usize,
143                size_of::<sys::LV2_Atom_Vector_Body>() + size_of::<i32>() * 9
144            );
145            assert_eq!(vector.body.child_size as usize, size_of::<i32>());
146            assert_eq!(vector.body.child_type, urids.int);
147
148            let (vector_items, space) = space.split_at(size_of::<i32>() * 9);
149            let vector_items =
150                unsafe { std::slice::from_raw_parts(vector_items.as_ptr() as *const i32, 9) };
151            assert_eq!(vector_items, &[17; 9]);
152            let (_, space) = space.split_at(4);
153
154            let (int, _) = space.split_at(size_of::<sys::LV2_Atom_Int>());
155            let int = unsafe { &*(int.as_ptr() as *const sys::LV2_Atom_Int) };
156            assert_eq!(int.atom.type_, urids.int);
157            assert_eq!(int.atom.size as usize, size_of::<i32>());
158            assert_eq!(int.body, 42);
159        }
160
161        // reading
162        {
163            let space = Space::from_slice(raw_space.as_ref());
164            let (body, _) = space.split_atom_body(urids.tuple).unwrap();
165            let items: Vec<UnidentifiedAtom> = Tuple::read(body, ()).unwrap().collect();
166            assert_eq!(items[0].read(urids.vector, urids.int).unwrap(), [17; 9]);
167            assert_eq!(items[1].read(urids.int, ()).unwrap(), 42);
168        }
169    }
170}