otter/codec/string.rs
1//! `Encoder`/`Decoder` for Rust `str`/`String`.
2//!
3//! Asymmetric, matching how strings actually travel in Erlang. Decoding a
4//! `String` accepts either a binary (read as UTF-8) or a charlist (a list of
5//! codepoints); encoding a `str`/`String` always produces a binary, the modern
6//! convention. A binary whose bytes are not valid UTF-8, or a list that is not a
7//! valid string, is rejected with [`CodecError::NotUtf8`]; a term that is neither
8//! a binary nor a list is [`CodecError::WrongType`].
9
10use crate::codec::{CodecError, Decoder, Encoder};
11use crate::types::{AnyTerm, Binary, Env, List};
12
13/// Encodes the UTF-8 bytes as a binary (`enif_make_new_binary`), the modern
14/// convention. Infallible.
15impl<'id> Encoder<'id> for str {
16 fn encode(&self, env: impl Env<'id>) -> Result<AnyTerm<'id>, CodecError> {
17 Binary::from_bytes(env, self.as_bytes()).encode(env)
18 }
19}
20
21/// Encodes as a binary, via [`str`]'s impl. Infallible.
22impl<'id> Encoder<'id> for String {
23 fn encode(&self, env: impl Env<'id>) -> Result<AnyTerm<'id>, CodecError> {
24 self.as_str().encode(env)
25 }
26}
27
28/// Accepts a binary (read as UTF-8) or a charlist (list of codepoints). Invalid
29/// UTF-8 / a non-string list is [`NotUtf8`](CodecError::NotUtf8); a term that is
30/// neither binary nor list is [`WrongType`](CodecError::WrongType).
31impl<'id> Decoder<'id> for String {
32 fn decode(term: AnyTerm<'id>, env: impl Env<'id>) -> Result<Self, CodecError> {
33 if let Ok(bin) = Binary::decode(term, env) {
34 return bin.try_str(env).map(str::to_owned).map_err(|_| CodecError::NotUtf8);
35 }
36 if let Ok(list) = List::decode(term, env) {
37 return list.try_string(env).ok_or(CodecError::NotUtf8);
38 }
39 Err(CodecError::WrongType)
40 }
41}