lv2rs_atom/vector.rs
1//! Homogenous array of sized atoms.
2//!
3//! A [vector](type.Vector.html) is the LV2 equivalent of a slice: It has a variable length, but it
4//! does only contain one type of item, which has to be sized.
5//!
6//! When initialized, a vector does not contain any items. These items have to be pushed or appended
7//! to the vector using the [`VectorWritingFrame`](trait.VectorWritingFrame.html) trait. Every
8//! writing frame implements this trait via a blanket implementation and the trait is included in
9//! the crate's prelude. You can, therefore, act as if the extended methods were normal methods of a
10//! writing frame.
11//!
12//! Reading the vector is done using these methods:
13//! * [`child_body_size`](type.Vector.html#method.child_body_size)
14//! * [`child_body_type`](type.Vector.html#method.child_body_type)
15//! * [`as_slice`](type.Vector.html#method.as_slice)
16//!
17//! An example:
18//!
19//! extern crate lv2rs_atom as atom;
20//! extern crate lv2rs_urid as urid;
21//!
22//! use atom::prelude::*;
23//! use atom::ports::*;
24//! use urid::{CachedMap, debug::DebugMap};
25//! use std::ffi::CStr;
26//!
27//! pub struct Plugin {
28//! in_port: AtomInputPort<Vector<f32>>,
29//! out_port: AtomOutputPort<Vector<f32>>,
30//! urids: CachedMap,
31//! }
32//!
33//! impl Plugin {
34//! /// Simulated `run` method.
35//! fn run(&mut self) {
36//! // Writing
37//! {
38//! let mut frame =
39//! unsafe { self.out_port.write_atom_body(&(), &mut self.urids) }.unwrap();
40//! frame.push(0.0).unwrap();
41//! frame.append(&[1.0, 2.0, 3.0, 4.0]).unwrap();
42//! }
43//!
44//! // Reading.
45//! let vector = unsafe { self.in_port.get_atom_body(&mut self.urids) }.unwrap();
46//! assert_eq!([0.0, 1.0, 2.0, 3.0, 4.0], vector.as_slice());
47//! }
48//! }
49//!
50//! // Getting a debug URID map.
51//! let mut debug_map = DebugMap::new();
52//! let mut urids = unsafe {debug_map.create_cached_map()};
53//!
54//! // Creating the plugin.
55//! let mut plugin = Plugin {
56//! in_port: AtomInputPort::new(),
57//! out_port: AtomOutputPort::new(),
58//! urids: urids,
59//! };
60//!
61//! // Creating the atom space.
62//! let mut atom_space = vec![0u8; 256];
63//! let atom = unsafe { (atom_space.as_mut_ptr() as *mut Atom).as_mut() }.unwrap();
64//! *(atom.mut_size()) = 256 - 8;
65//!
66//! // Connecting the ports.
67//! plugin.in_port.connect_port(atom as &Atom);
68//! plugin.out_port.connect_port(atom);
69//!
70//! // Calling `run`.
71//! plugin.run();
72use crate::atom::{array::*, *};
73use crate::frame::{WritingFrame, WritingFrameExt};
74use crate::uris;
75use std::ffi::CStr;
76use std::mem::size_of;
77use std::os::raw::*;
78use urid::URID;
79
80/// The body header of a vector.
81///
82/// It contains the size of the child type (which has to be static) and the child type itself.
83/// This struct is also `repr(C)` and is used to interpret raw atom data.
84#[repr(C)]
85pub struct VectorHeader {
86 pub child_size: c_uint,
87 pub child_type: c_uint,
88}
89
90/// A homogenous array of sized atoms.
91///
92/// See the [module documentation](index.html) for more information.
93pub type Vector<T> = ArrayAtomBody<VectorHeader, T>;
94
95impl ArrayAtomHeader for VectorHeader {
96 type InitializationParameter = URID;
97
98 unsafe fn initialize<'a, W, T>(
99 writer: &mut W,
100 child_type: &URID,
101 _urids: &mut urid::CachedMap,
102 ) -> Result<(), ()>
103 where
104 T: 'static + Sized + Copy,
105 ArrayAtomBody<Self, T>: AtomBody,
106 W: WritingFrame<'a> + WritingFrameExt<'a, ArrayAtomBody<Self, T>>,
107 {
108 let header = VectorHeader {
109 child_size: size_of::<T>() as u32,
110 child_type: *child_type,
111 };
112 writer.write_sized(&header)?;
113 Ok(())
114 }
115}
116
117impl<T> AtomBody for Vector<T>
118where
119 T: 'static + AtomBody + Sized + Copy,
120{
121 type InitializationParameter = ();
122
123 fn get_uri() -> &'static CStr {
124 unsafe { CStr::from_bytes_with_nul_unchecked(uris::VECTOR_TYPE_URI) }
125 }
126
127 unsafe fn initialize_body<'a, W>(
128 writer: &mut W,
129 _: &(),
130 urids: &mut urid::CachedMap,
131 ) -> Result<(), ()>
132 where
133 W: WritingFrame<'a> + WritingFrameExt<'a, Self>,
134 {
135 Self::__initialize_body(writer, &urids.map(T::get_uri()), urids)
136 }
137
138 fn create_ref<'a>(raw_data: &'a [u8]) -> Result<&'a Self, ()> {
139 Self::__create_ref(raw_data)
140 }
141}
142
143impl<T> Vector<T>
144where
145 T: 'static + AtomBody + Sized + Copy,
146{
147 /// Return the size of the child type, according to the vector's body header.
148 pub fn child_body_size(&self) -> usize {
149 self.header.child_size as usize
150 }
151
152 /// Return the type of the child, according to the vector's body header.
153 pub fn child_body_type(&self) -> URID {
154 self.header.child_type
155 }
156
157 /// Return a slice containing all items in the vector.
158 ///
159 /// No allocation is done; This method simply borrows the data of the vector.
160 pub fn as_slice(&self) -> &[T] {
161 &self.data
162 }
163}
164
165/// Extension for [`WritingFrame`](../frame/trait.WritingFrame.html) and
166/// [`WritingFrameExt`](../frame/trait.WritingFrameExt.html) for vectors.
167///
168/// See the [module documentation](index.html) for more information.
169pub trait VectorWritingFrame<'a, T>
170where
171 T: 'static + AtomBody + Sized + Copy,
172 Self: WritingFrame<'a> + WritingFrameExt<'a, Vector<T>>,
173{
174 /// Push a value to the end of the vector.
175 fn push(&mut self, value: T) -> Result<(), ()> {
176 unsafe { Vector::<T>::push(self, value) }
177 }
178
179 /// Append a slice of values to the end of the vector.
180 fn append(&mut self, slice: &[T]) -> Result<(), ()> {
181 unsafe { Vector::<T>::append(self, slice) }
182 }
183}
184
185impl<'a, T, F> VectorWritingFrame<'a, T> for F
186where
187 T: 'static + AtomBody + Sized + Copy,
188 F: WritingFrame<'a> + WritingFrameExt<'a, Vector<T>>,
189{
190}