lv2rs_atom/ports.rs
1//! Wrappers for raw atom IO.
2//!
3//! The wrappers provided by this module increase the safety and usability of atom IO.
4use crate::atom::*;
5use crate::frame::RootFrame;
6use std::marker::PhantomData;
7use std::ptr::{null, null_mut};
8
9/// Wrapper for atom writing operations.
10pub struct AtomOutputPort<A: AtomBody + ?Sized> {
11 atom: *mut Atom,
12 phantom: PhantomData<A>,
13}
14
15/// Errors that may occur when calling
16/// [`AtomOutputPort::write_atom_body`](struct.AtomOuputPort.html#method.write_atom_body)
17#[derive(Debug)]
18pub enum WriteAtomError {
19 /// The internal pointer points to zero.
20 ///
21 /// Maybe `connect_port` is not implemented correctly?
22 NullPointer,
23 /// The host hasn't allocated enough memory to initialize the atom.
24 InsufficientSpace,
25}
26
27#[derive(Debug)]
28/// Error that may occur when calling [`AtomInputPort::get_atom_body`](struct.AtomInputPort.html#method.get_atom_body).
29pub enum GetAtomError {
30 /// The internal pointer points to zero.
31 ///
32 /// Maybe `connect_port` is not implemented correctly?
33 NullPointer,
34 /// Widening the atom header failed.
35 GetBody(GetBodyError),
36}
37
38impl<A: AtomBody + ?Sized> AtomOutputPort<A> {
39 /// Create a new port.
40 ///
41 /// Please note that the newly created port wil point to null and therefore,
42 /// [`write_atom_body`](#method.write_atom_body) will yield undefined behaviour.
43 pub fn new() -> Self {
44 Self {
45 atom: null_mut(),
46 phantom: PhantomData,
47 }
48 }
49
50 /// Set the internal atom pointer.
51 ///
52 /// As implied by the name, this method should be called by an atom's `connect_port`. However,
53 /// you have to cast the passed pointer to the correct type!
54 pub fn connect_port(&mut self, atom: *mut Atom) {
55 self.atom = atom;
56 }
57
58 /// Write an atom to the internal atom pointer.
59 ///
60 /// This method will create a [`RootFrame`](../frame/struct.RootFrame.html) and initialize the
61 /// body. For [scalar atoms](../scalar/index.html), this is all you can and need to
62 /// do. For all other atoms, you can write additional data using the `RootFrame`.
63 ///
64 /// This method is unsafe since it dereferences the raw, internal pointer and therefore could
65 /// yield undefined behaviour. Make sure that your plugin's `connect_port` method calls this
66 /// port's [`connect_port`](#method.connect_port) method correctly!
67 pub unsafe fn write_atom_body<'a>(
68 &'a mut self,
69 parameter: &A::InitializationParameter,
70 urids: &mut urid::CachedMap,
71 ) -> Result<RootFrame<'a, A>, WriteAtomError> {
72 let header = match self.atom.as_mut() {
73 Some(header) => header,
74 None => return Err(WriteAtomError::NullPointer),
75 };
76 let data = std::slice::from_raw_parts_mut(self.atom as *mut u8, header.size() as usize);
77 let mut frame =
78 RootFrame::new(data, urids).map_err(|_| WriteAtomError::InsufficientSpace)?;
79 A::initialize_body(&mut frame, parameter, urids)
80 .map_err(|_| WriteAtomError::InsufficientSpace)?;
81 Ok(frame)
82 }
83}
84
85/// Wrapper for atom reading operations.
86pub struct AtomInputPort<A: AtomBody + ?Sized> {
87 atom: *const Atom,
88 phantom: PhantomData<A>,
89}
90
91impl<A: AtomBody + ?Sized> AtomInputPort<A> {
92 /// Create a new port.
93 ///
94 /// Please note that the newly created port wil point to null and therefore,
95 /// [`write_atom_body`](#method.write_atom_body) will yield undefined behaviour.
96 pub fn new() -> Self {
97 Self {
98 atom: null(),
99 phantom: PhantomData,
100 }
101 }
102
103 /// Set the internal atom pointer.
104 ///
105 /// As implied by the name, this method should be called by an atom's `connect_port`. However,
106 /// you have to cast the passed pointer to the correct type!
107 pub fn connect_port(&mut self, atom: *const Atom) {
108 self.atom = atom;
109 }
110
111 /// Dereference the internal raw pointer to an atom body reference.
112 ///
113 /// This method is unsafe since it dereferences the raw, internal pointer and therefore could
114 /// yield undefined behaviour. Make sure that your plugin's `connect_port` method calls this
115 /// port's [`connect_port`](#method.connect_port) method correctly!
116 pub unsafe fn get_atom_body(&self, urids: &mut urid::CachedMap) -> Result<&A, GetAtomError> {
117 let atom = match self.atom.as_ref() {
118 Some(atom) => atom,
119 None => return Err(GetAtomError::NullPointer),
120 };
121 atom.get_body(urids)
122 .map_err(|err| GetAtomError::GetBody(err))
123 }
124}