lv2_atom/
vector.rs

1//! An atom containg an array of scalar atom bodies.
2//!
3//! This atom is able to handle arrays (aka slices) of the internal types of scalar atoms.
4//!
5//! Reading a vector requires the URID fo the scalar that's been used and the reading process fails if the vector does not contain the requested scalar atom. The return value of the reading process is a slice of the internal type.
6//!
7//! Writing a vector is done with a writer that appends slices to the atom.
8//!
9//! # Example
10//! ```
11//! use lv2_core::prelude::*;
12//! use lv2_atom::prelude::*;
13//! use lv2_atom::vector::VectorWriter;
14//!
15//! #[derive(PortCollection)]
16//! struct MyPorts {
17//!     input: InputPort<AtomPort>,
18//!     output: OutputPort<AtomPort>,
19//! }
20//!
21//! fn run(ports: &mut MyPorts, urids: &AtomURIDCollection) {
22//!     let input: &[i32] = ports.input.read(urids.vector(), urids.int).unwrap();
23//!     let mut output: VectorWriter<Int> = ports.output.init(urids.vector(), urids.int).unwrap();
24//!     output.append(input).unwrap();
25//! }
26//! ```
27//!
28//! You may note that, unlike other atoms, the vector's URID is retrieved by calling the `vector` method. This is because two vectors with a different item type are considered two different types, and therefore would have the different URIDs. In reality, however, all vectors have the same URID and the `vector` method returns it with the fitting type.
29//!
30//! # Specification
31//!
32//! [http://lv2plug.in/ns/ext/atom/atom.html#Vector](http://lv2plug.in/ns/ext/atom/atom.html#Vector)
33use crate::scalar::ScalarAtom;
34use crate::space::*;
35use crate::*;
36use std::marker::PhantomData;
37use std::mem::size_of;
38use urid::*;
39
40/// An atom containg an array of scalar atom bodies.
41///
42/// [See also the module documentation.](index.html)
43pub struct Vector<C: ScalarAtom> {
44    child: PhantomData<C>,
45}
46
47unsafe impl<C: ScalarAtom> UriBound for Vector<C> {
48    const URI: &'static [u8] = sys::LV2_ATOM__Vector;
49}
50
51impl<'a, 'b, C: ScalarAtom> Atom<'a, 'b> for Vector<C>
52where
53    'a: 'b,
54    C: 'b,
55{
56    type ReadParameter = URID<C>;
57    type ReadHandle = &'a [C::InternalType];
58    type WriteParameter = URID<C>;
59    type WriteHandle = VectorWriter<'a, 'b, C>;
60
61    fn read(body: Space<'a>, child_urid: URID<C>) -> Option<&'a [C::InternalType]> {
62        let (header, body) = body.split_type::<sys::LV2_Atom_Vector_Body>()?;
63
64        if header.child_type != child_urid
65            || header.child_size as usize != size_of::<C::InternalType>()
66        {
67            return None;
68        }
69
70        let data = body.data()?;
71
72        assert_eq!(data.len() % size_of::<C::InternalType>(), 0);
73        let children_count = data.len() / size_of::<C::InternalType>();
74
75        let children = unsafe {
76            std::slice::from_raw_parts(data.as_ptr() as *const C::InternalType, children_count)
77        };
78        Some(children)
79    }
80
81    fn init(
82        mut frame: FramedMutSpace<'a, 'b>,
83        child_urid: URID<C>,
84    ) -> Option<VectorWriter<'a, 'b, C>> {
85        let body = sys::LV2_Atom_Vector_Body {
86            child_type: child_urid.get(),
87            child_size: size_of::<C::InternalType>() as u32,
88        };
89        (&mut frame as &mut dyn MutSpace).write(&body, false)?;
90
91        Some(VectorWriter {
92            frame,
93            type_: PhantomData,
94        })
95    }
96}
97
98/// Handle to append elements to a vector.
99///
100/// This works by allocating a slice of memory behind the vector and then writing your data to it.
101pub struct VectorWriter<'a, 'b, A: ScalarAtom> {
102    frame: FramedMutSpace<'a, 'b>,
103    type_: PhantomData<A>,
104}
105
106impl<'a, 'b, A: ScalarAtom> VectorWriter<'a, 'b, A> {
107    /// Push a single value to the vector.
108    pub fn push(&mut self, child: A::InternalType) -> Option<&mut A::InternalType> {
109        (&mut self.frame as &mut dyn MutSpace).write(&child, false)
110    }
111
112    /// Append a slice of undefined memory to the vector.
113    ///
114    /// Using this method, you don't need to have the elements in memory before you can write them.
115    pub fn allocate(&mut self, size: usize) -> Option<&mut [A::InternalType]> {
116        self.frame
117            .allocate(size_of::<A::InternalType>() * size, false)
118            .map(|(_, data)| unsafe {
119                std::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut A::InternalType, size)
120            })
121    }
122
123    /// Append multiple elements to the vector.
124    pub fn append(&mut self, data: &[A::InternalType]) -> Option<&mut [A::InternalType]> {
125        let raw_data = unsafe {
126            std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data))
127        };
128        self.frame
129            .allocate(raw_data.len(), false)
130            .map(|(_, space)| unsafe {
131                space.copy_from_slice(raw_data);
132                std::slice::from_raw_parts_mut(
133                    space.as_mut_ptr() as *mut A::InternalType,
134                    data.len(),
135                )
136            })
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use crate::prelude::*;
143    use crate::space::*;
144    use std::mem::size_of;
145    use urid::*;
146
147    #[test]
148    fn test_vector() {
149        const CHILD_COUNT: usize = 17;
150
151        let map = HashURIDMapper::new();
152        let urids = crate::AtomURIDCollection::from_map(&map).unwrap();
153
154        let mut raw_space: Box<[u8]> = Box::new([0; 256]);
155
156        // writing
157        {
158            let mut space = RootMutSpace::new(raw_space.as_mut());
159            let mut writer = (&mut space as &mut dyn MutSpace)
160                .init(urids.vector(), urids.int)
161                .unwrap();
162            writer.append(&[42; CHILD_COUNT - 1]);
163            writer.push(1);
164        }
165
166        // verifying
167        {
168            let (vector, children) = raw_space.split_at(size_of::<sys::LV2_Atom_Vector>());
169
170            let vector = unsafe { &*(vector.as_ptr() as *const sys::LV2_Atom_Vector) };
171            assert_eq!(vector.atom.type_, urids.vector.get());
172            assert_eq!(
173                vector.atom.size as usize,
174                size_of::<sys::LV2_Atom_Vector_Body>() + size_of::<i32>() * CHILD_COUNT
175            );
176            assert_eq!(vector.body.child_size as usize, size_of::<i32>());
177            assert_eq!(vector.body.child_type, urids.int.get());
178
179            let children =
180                unsafe { std::slice::from_raw_parts(children.as_ptr() as *const i32, CHILD_COUNT) };
181            for value in &children[0..children.len() - 1] {
182                assert_eq!(*value, 42);
183            }
184            assert_eq!(children[children.len() - 1], 1);
185        }
186
187        // reading
188        {
189            let space = Space::from_slice(raw_space.as_ref());
190            let (body, _) = space.split_atom_body(urids.vector).unwrap();
191            let children: &[i32] = Vector::<Int>::read(body, urids.int).unwrap();
192
193            assert_eq!(children.len(), CHILD_COUNT);
194            for i in 0..children.len() - 1 {
195                assert_eq!(children[i], 42);
196            }
197            assert_eq!(children[children.len() - 1], 1);
198        }
199    }
200}