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