lv2rs_atom/literal.rs
1//! UTF-8-encoded string.
2//!
3//! This string atom corresponds to Rust's normal `str` and `String` types, since it is
4//! UTF-8-encoded. A literal also contains, apart from the string, the URID of it's language.
5//!
6//! When initialized, a literal does not contain any text. Every text has to be appended to the
7//! literal using the [`LiteralWritingFrame`](trait.LiteralWritingFrame.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//! You can aquire a literal's data using the [`lang` method](type.Literal.html#method.lang)
13//! and the [`as_str` method](type.Literal.html#method.as_str).
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<Literal>,
27//! out_port: AtomOutputPort<Literal>,
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(&0, &mut self.urids) }.unwrap();
38//! frame.append_string("Hello World!");
39//! }
40//!
41//! // Reading.
42//! let literal = unsafe { self.in_port.get_atom_body(&mut self.urids) }.unwrap();
43//! let message = literal.as_str().unwrap();
44//! assert_eq!("Hello World!", message);
45//! }
46//! }
47//!
48//! // Getting a debug URID map.
49//! let mut debug_map = DebugMap::new();
50//! let mut urids = unsafe {debug_map.create_cached_map()};
51//!
52//! // Creating the plugin.
53//! let mut plugin = Plugin {
54//! in_port: AtomInputPort::new(),
55//! out_port: AtomOutputPort::new(),
56//! urids: urids,
57//! };
58//!
59//! // Creating the atom space.
60//! let mut atom_space = vec![0u8; 256];
61//! let atom = unsafe { (atom_space.as_mut_ptr() as *mut Atom).as_mut() }.unwrap();
62//! *(atom.mut_size()) = 256 - 8;
63//!
64//! // Connecting the ports.
65//! plugin.in_port.connect_port(atom as &Atom);
66//! plugin.out_port.connect_port(atom);
67//!
68//! // Calling `run`.
69//! plugin.run();
70use crate::atom::{array::*, *};
71use crate::frame::{WritingFrame, WritingFrameExt};
72use crate::uris;
73use std::ffi::CStr;
74use urid::URID;
75
76/// The body header of a literal.
77///
78/// It contains the URID of the datatype (some obscure RDF feature) and of the language. It is also
79/// `repr(C)` and is used to interpret raw atoms.
80#[repr(C)]
81pub struct LiteralHeader {
82 pub datatype: URID,
83 pub lang: URID,
84}
85
86/// UTF-8 encoded string.
87///
88/// See the [module documentation](index.html) for more information.
89pub type Literal = ArrayAtomBody<LiteralHeader, u8>;
90
91impl ArrayAtomHeader for LiteralHeader {
92 type InitializationParameter = URID;
93
94 unsafe fn initialize<'a, W, T>(
95 writer: &mut W,
96 language: &URID,
97 _urids: &mut urid::CachedMap,
98 ) -> Result<(), ()>
99 where
100 T: 'static + Sized + Copy,
101 ArrayAtomBody<Self, T>: AtomBody,
102 W: WritingFrame<'a> + WritingFrameExt<'a, ArrayAtomBody<Self, T>>,
103 {
104 let header = LiteralHeader {
105 datatype: 0,
106 lang: *language,
107 };
108 writer.write_sized(&header)?;
109 Ok(())
110 }
111}
112
113impl AtomBody for Literal {
114 type InitializationParameter = URID;
115
116 fn get_uri() -> &'static CStr {
117 unsafe { CStr::from_bytes_with_nul_unchecked(uris::LITERAL_TYPE_URI) }
118 }
119
120 unsafe fn initialize_body<'a, W>(
121 writer: &mut W,
122 language: &URID,
123 urids: &mut urid::CachedMap,
124 ) -> Result<(), ()>
125 where
126 W: WritingFrame<'a> + WritingFrameExt<'a, Self>,
127 {
128 Self::__initialize_body(writer, language, urids)
129 }
130
131 fn create_ref<'a>(raw_data: &'a [u8]) -> Result<&'a Self, ()> {
132 Self::__create_ref(raw_data)
133 }
134}
135
136impl Literal {
137 /// Try to parse the literal data as a `&str`
138 ///
139 /// Parsing errors are forwarded.
140 pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
141 let bytes = &self.data;
142 std::str::from_utf8(bytes)
143 }
144
145 /// Return the language of the literal.
146 pub fn lang(&self) -> URID {
147 self.header.lang
148 }
149}
150
151/// Extension for [`WritingFrame`](../frame/trait.WritingFrame.html) and
152/// [`WritingFrameExt`](../frame/trait.WritingFrameExt.html) for vectors.
153///
154/// See the [module documentation](index.html) for more information.
155pub trait LiteralWritingFrame<'a>: WritingFrame<'a> + WritingFrameExt<'a, Literal> {
156 /// Append a string to the literal.
157 ///
158 /// In case of insufficient memory, `Err` is returned.
159 fn append_string(&mut self, string: &str) -> Result<(), ()> {
160 unsafe { Literal::append(self, string.as_bytes()) }
161 }
162}
163
164impl<'a, W> LiteralWritingFrame<'a> for W where W: WritingFrame<'a> + WritingFrameExt<'a, Literal> {}