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}