lv2rs_atom/tuple.rs
1//! Heterogenous array of sized and unsized atoms.
2//!
3//! A tuple is a pretty simple collection of different atoms: It basically a chunk containing an
4//! arbitrary amount of atoms, aligned to 64-bit.
5//!
6//! When initialized, a tuple does not contain any atoms. These have to be pushed to the tuple using
7//! the [`TupleWritingFrame`](trait.TupleWritingFrame.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 atoms is done by iterating through all atoms one by one. Iterators are produced by the
13//! [`iter`](type.Tuple.html#method.iter) method.
14//!
15//! An example:
16//!
17//! extern crate lv2rs_atom as atom;
18//! extern crate lv2rs_urid as urid;
19//!
20//! use atom::prelude::*;
21//! use atom::ports::*;
22//! use urid::{CachedMap, debug::DebugMap};
23//! use std::ffi::CStr;
24//!
25//! pub struct Plugin {
26//! in_port: AtomInputPort<Tuple>,
27//! out_port: AtomOutputPort<Tuple>,
28//! urids: CachedMap,
29//! }
30//!
31//! impl Plugin {
32//! /// Simulated `run` method.
33//! fn run(&mut self) {
34//! // Writing
35//! {
36//! let mut frame =
37//! unsafe { self.out_port.write_atom_body(&(), &mut self.urids) }.unwrap();
38//! frame.push_atom::<i32>(&42, &mut self.urids).unwrap();
39//! frame.push_atom::<f32>(&17.0, &mut self.urids).unwrap();
40//! }
41//!
42//! let i32_urid = self.urids.map(<i32 as AtomBody>::get_uri());
43//! let f32_urid = self.urids.map(<f32 as AtomBody>::get_uri());
44//!
45//! // Reading.
46//! let tuple = unsafe { self.in_port.get_atom_body(&mut self.urids) }.unwrap();
47//! for sub_atom in tuple.iter() {
48//! match unsafe { sub_atom.get_body::<i32>(&mut self.urids) } {
49//! Ok(integer) => {
50//! assert_eq!(42, *integer);
51//! continue
52//! }
53//! Err(_) => (),
54//! }
55//! match unsafe { sub_atom.get_body::<f32>(&mut self.urids) } {
56//! Ok(float) => {
57//! assert_eq!(17.0, *float);
58//! continue
59//! }
60//! Err(_) => (),
61//! }
62//! panic!("Unknown property in object!");
63//! }
64//! }
65//! }
66//!
67//! // Getting a debug URID map.
68//! let mut debug_map = DebugMap::new();
69//! let mut urids = unsafe {debug_map.create_cached_map()};
70//!
71//! // Creating the plugin.
72//! let mut plugin = Plugin {
73//! in_port: AtomInputPort::new(),
74//! out_port: AtomOutputPort::new(),
75//! urids: urids,
76//! };
77//!
78//! // Creating the atom space.
79//! let mut atom_space = vec![0u8; 256];
80//! let atom = unsafe { (atom_space.as_mut_ptr() as *mut Atom).as_mut() }.unwrap();
81//! *(atom.mut_size()) = 256 - 8;
82//!
83//! // Connecting the ports.
84//! plugin.in_port.connect_port(atom as &Atom);
85//! plugin.out_port.connect_port(atom);
86//!
87//! // Calling `run`.
88//! plugin.run();
89use crate::atom::{array::*, *};
90use crate::frame::{NestedFrame, WritingFrame, WritingFrameExt};
91use crate::uris;
92use std::ffi::CStr;
93
94/// Heterogenous array of sized and unsized atoms.
95///
96/// See the [module documentation](index.html) for more information.
97pub type Tuple = ArrayAtomBody<(), u8>;
98
99impl AtomBody for Tuple {
100 type InitializationParameter = ();
101
102 fn get_uri() -> &'static CStr {
103 unsafe { CStr::from_bytes_with_nul_unchecked(uris::TUPLE_TYPE_URI) }
104 }
105
106 unsafe fn initialize_body<'a, W>(
107 writer: &mut W,
108 parameter: &(),
109 urids: &mut urid::CachedMap,
110 ) -> Result<(), ()>
111 where
112 W: WritingFrame<'a> + WritingFrameExt<'a, Self>,
113 {
114 Self::__initialize_body(writer, parameter, urids)
115 }
116
117 fn create_ref<'a>(raw_data: &'a [u8]) -> Result<&'a Self, ()> {
118 Self::__create_ref(raw_data)
119 }
120}
121
122impl Tuple {
123 /// Create an iterator over all properties of the object.
124 ///
125 /// This iterator is based on the [`AtomIterator`](../atom/struct.AtomIterator.html).
126 pub fn iter(&self) -> impl Iterator<Item = &Atom> {
127 AtomIterator::<()>::new(&self.data).map(|(_, chunk): (&(), &Atom)| chunk)
128 }
129}
130
131/// Extension for [`WritingFrame`](../frame/trait.WritingFrame.html) and
132/// [`WritingFrameExt`](../frame/trait.WritingFrameExt.html) for vectors.
133///
134/// See the [module documentation](index.html) for more information.
135pub trait TupleWritingFrame<'a>: WritingFrame<'a> + WritingFrameExt<'a, Tuple> {
136 /// Add a new atom to the tuple.
137 ///
138 /// This method acts just like an output port's
139 /// [`write_atom_body`](../ports/struct.AtomOutputPort.html#method.write_atom_body): It receives the
140 /// initialization parameter of a atom, creates a new writing frame, initializes the atom and
141 /// returns the frame.
142 fn push_atom<'b, A: AtomBody + ?Sized>(
143 &'b mut self,
144 parameter: &A::InitializationParameter,
145 urids: &mut urid::CachedMap,
146 ) -> Result<NestedFrame<'b, 'a, A>, ()> {
147 unsafe {
148 let mut frame = self.create_nested_frame::<A>(urids)?;
149 A::initialize_body(&mut frame, parameter, urids)?;
150 Ok(frame)
151 }
152 }
153}
154
155impl<'a, W> TupleWritingFrame<'a> for W where W: WritingFrame<'a> + WritingFrameExt<'a, Tuple> {}