lv2rs_atom/
string.rs

1//! ASCII string.
2//!
3//! This module contains the [`AtomString`](type.AtomString.html), an atom representing standard
4//! ASCII strings.
5//!
6//! Atom strings can only be written once: The `write_atom_body` call expects a CStr from which it can
7//! copy the data and after that call, the string can't be modified.
8//!
9//! An example:
10//!
11//!     extern crate lv2rs_atom as atom;
12//!     extern crate lv2rs_urid as urid;
13//!
14//!     use atom::prelude::*;
15//!     use atom::ports::*;
16//!     use urid::{CachedMap, debug::DebugMap};
17//!     use std::ffi::CStr;
18//!
19//!     pub struct Plugin {
20//!         in_port: AtomInputPort<AtomString>,
21//!         out_port: AtomOutputPort<AtomString>,
22//!         urids: CachedMap,
23//!     }
24//!
25//!     impl Plugin {
26//!         /// Simulated `run` method.
27//!         fn run(&mut self) {
28//!             let message: &str = "Hello World!\0";
29//!             let c_message = CStr::from_bytes_with_nul(message.as_bytes()).unwrap();
30//!
31//!             // Writing.
32//!             unsafe { self.out_port.write_atom_body(c_message, &mut self.urids).unwrap() };
33//!
34//!             // Reading.
35//!             let string = unsafe { self.in_port.get_atom_body(&mut self.urids) }.unwrap();
36//!             let str = string.as_cstr().unwrap().to_str().unwrap();
37//!             assert_eq!("Hello World!", str);
38//!         }
39//!     }
40//!
41//!     // Getting a debug URID map.
42//!     let mut debug_map = DebugMap::new();
43//!     let mut urids = unsafe {debug_map.create_cached_map()};
44//!
45//!     // Creating the plugin.
46//!     let mut plugin = Plugin {
47//!         in_port: AtomInputPort::new(),
48//!         out_port: AtomOutputPort::new(),
49//!         urids: urids,
50//!     };
51//!
52//!     // Creating the atom space.
53//!     let mut atom_space = vec![0u8; 256];
54//!     let atom = unsafe { (atom_space.as_mut_ptr() as *mut Atom).as_mut() }.unwrap();
55//!     *(atom.mut_size()) = 256 - 8;
56//!
57//!     // Connecting the ports.
58//!     plugin.in_port.connect_port(atom as &Atom);
59//!     plugin.out_port.connect_port(atom);
60//!
61//!     // Calling `run`.
62//!     plugin.run();
63use crate::atom::{array::*, *};
64use crate::frame::{WritingFrame, WritingFrameExt};
65use crate::uris;
66use std::ffi::CStr;
67
68/// ASCII String.
69///
70/// See the [module documentation](index.html) for more information.
71pub type AtomString = ArrayAtomBody<(), i8>;
72
73impl AtomBody for AtomString {
74    type InitializationParameter = CStr;
75
76    fn get_uri() -> &'static CStr {
77        unsafe { CStr::from_bytes_with_nul_unchecked(uris::STRING_TYPE_URI) }
78    }
79
80    unsafe fn initialize_body<'a, W>(
81        writer: &mut W,
82        string: &CStr,
83        urids: &mut urid::CachedMap,
84    ) -> Result<(), ()>
85    where
86        W: WritingFrame<'a> + WritingFrameExt<'a, Self>,
87    {
88        Self::__initialize_body(writer, &(), urids)?;
89
90        writer.write_raw(string.to_bytes())?;
91        // Write the null terminator since `string.to_bytes()` will never contain one.
92        writer.write_sized(&0u8)?;
93
94        Ok(())
95    }
96
97    fn create_ref<'a>(raw_data: &'a [u8]) -> Result<&'a Self, ()> {
98        Self::__create_ref(raw_data)
99    }
100}
101
102impl AtomString {
103    /// Try to wrap the string into a `CStr` reference.
104    ///
105    /// This function returns an error if the internal conversion fails.
106    pub fn as_cstr(&self) -> Result<&CStr, std::ffi::FromBytesWithNulError> {
107        CStr::from_bytes_with_nul(unsafe { std::mem::transmute::<&[i8], &[u8]>(&self.data) })
108    }
109}