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> {}