Skip to main content

rd_rds/
value.rs

1use std::{borrow::Cow, sync::Arc};
2
3use crate::Error;
4
5#[derive(Debug, Clone, PartialEq)]
6#[non_exhaustive]
7pub struct RObject {
8    value: RValue,
9    attributes: Attributes,
10}
11
12#[derive(Debug, Clone, PartialEq)]
13#[non_exhaustive]
14pub enum RValue {
15    Null,
16    Logical(Vec<Option<bool>>),
17    Integer(Vec<Option<i32>>),
18    Real(Vec<Option<f64>>),
19    Character(Vec<RStr>),
20    List(Vec<RObject>),
21    Symbol(Symbol),
22    Persisted(Persisted),
23    Environment(EnvHandle),
24}
25
26/// An opaque handle to an environment.
27///
28/// `rd-rds` never models environment frames or enclosures: it only consumes
29/// the wire bytes correctly and keeps the reference table aligned. All
30/// non-singleton environments collapse to [`EnvHandle::Other`].
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum EnvHandle {
34    /// `R_GlobalEnv`.
35    Global,
36    /// `R_BaseEnv` / `R_BaseNamespace`.
37    Base,
38    /// `R_EmptyEnv`.
39    Empty,
40    /// Any other environment/package/namespace. Its wire fields were
41    /// decoded (to keep the stream and reference table in sync) and then
42    /// discarded.
43    Other,
44}
45
46#[derive(Debug, Clone, PartialEq)]
47pub struct Attribute {
48    name: Symbol,
49    value: RObject,
50}
51
52impl Attribute {
53    pub fn new(name: Symbol, value: RObject) -> Self {
54        Self { name, value }
55    }
56
57    pub fn name(&self) -> &Symbol {
58        &self.name
59    }
60
61    pub fn value(&self) -> &RObject {
62        &self.value
63    }
64}
65
66#[derive(Debug, Clone, PartialEq, Default)]
67pub struct Attributes(Vec<Attribute>);
68
69impl Attributes {
70    /// Constructs an attribute collection from decoded attributes.
71    pub fn new(values: Vec<Attribute>) -> Self {
72        Self(values)
73    }
74
75    pub fn is_empty(&self) -> bool {
76        self.0.is_empty()
77    }
78
79    pub fn len(&self) -> usize {
80        self.0.len()
81    }
82
83    pub fn iter(&self) -> impl Iterator<Item = &Attribute> {
84        self.0.iter()
85    }
86
87    pub fn get(&self, name: &str) -> Option<&RObject> {
88        self.0
89            .iter()
90            .find(|attribute| attribute.name().as_str() == name)
91            .map(|attribute| attribute.value())
92    }
93}
94
95impl RObject {
96    pub fn from_parts(value: RValue, attributes: Attributes) -> Self {
97        Self { value, attributes }
98    }
99
100    pub fn value(&self) -> &RValue {
101        &self.value
102    }
103
104    pub fn attributes(&self) -> &Attributes {
105        &self.attributes
106    }
107
108    pub fn into_parts(self) -> (RValue, Attributes) {
109        (self.value, self.attributes)
110    }
111
112    pub fn class(&self) -> Option<&[RStr]> {
113        match self.attributes.get("class")?.value() {
114            RValue::Character(values) => Some(values),
115            _ => None,
116        }
117    }
118
119    pub fn names(&self) -> Option<&[RStr]> {
120        match self.attributes.get("names")?.value() {
121            RValue::Character(values) => Some(values),
122            _ => None,
123        }
124    }
125
126    pub fn get_named(&self, name: &str) -> Option<&RObject> {
127        let RValue::List(items) = self.value() else {
128            return None;
129        };
130        let names = self.names()?;
131        names
132            .iter()
133            .position(|value| value.as_str().and_then(Result::ok).as_deref() == Some(name))
134            .and_then(|index| items.get(index))
135    }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct Symbol(Arc<str>);
140
141impl Symbol {
142    pub fn new(value: impl Into<Arc<str>>) -> Self {
143        Self(value.into())
144    }
145
146    pub fn as_str(&self) -> &str {
147        &self.0
148    }
149}
150
151impl From<&str> for Symbol {
152    fn from(value: &str) -> Self {
153        Self::new(value)
154    }
155}
156
157#[derive(Debug, Clone, PartialEq)]
158pub struct Persisted(Arc<[RStr]>);
159
160impl Persisted {
161    pub(crate) fn new(values: Vec<RStr>) -> Self {
162        Self(values.into())
163    }
164
165    #[cfg(test)]
166    pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
167        Arc::ptr_eq(&self.0, &other.0)
168    }
169
170    pub fn as_slice(&self) -> &[RStr] {
171        &self.0
172    }
173}
174
175#[derive(Debug, Clone, PartialEq, Eq)]
176#[non_exhaustive]
177pub enum RStr {
178    Na,
179    Value {
180        bytes: Arc<[u8]>,
181        encoding: REncoding,
182        native_encoding: Option<Arc<str>>,
183    },
184}
185
186impl RStr {
187    pub(crate) fn new(
188        bytes: &[u8],
189        encoding: REncoding,
190        native_encoding: Option<Arc<str>>,
191    ) -> Self {
192        Self::Value {
193            bytes: Arc::from(bytes),
194            encoding,
195            native_encoding,
196        }
197    }
198
199    pub fn as_str(&self) -> Option<Result<Cow<'_, str>, Error>> {
200        match self {
201            Self::Na => None,
202            Self::Value {
203                bytes,
204                encoding,
205                native_encoding,
206            } => Some(match encoding {
207                REncoding::Native => {
208                    if bytes.is_ascii() || is_utf8_native_encoding(native_encoding.as_deref()) {
209                        std::str::from_utf8(bytes)
210                            .map(Cow::Borrowed)
211                            .map_err(|_| Error::InvalidStringEncoding)
212                    } else {
213                        Err(Error::InvalidStringEncoding)
214                    }
215                }
216                REncoding::Utf8 => std::str::from_utf8(bytes)
217                    .map(Cow::Borrowed)
218                    .map_err(|_| Error::InvalidStringEncoding),
219                REncoding::Latin1 => {
220                    Ok(Cow::Owned(bytes.iter().map(|&byte| byte as char).collect()))
221                }
222                REncoding::Bytes => Err(Error::InvalidStringEncoding),
223            }),
224        }
225    }
226
227    pub fn encoding(&self) -> Option<REncoding> {
228        match self {
229            Self::Na => None,
230            Self::Value { encoding, .. } => Some(*encoding),
231        }
232    }
233}
234
235fn is_utf8_native_encoding(encoding: Option<&str>) -> bool {
236    encoding
237        .map(|encoding| {
238            encoding.eq_ignore_ascii_case("UTF-8") || encoding.eq_ignore_ascii_case("UTF8")
239        })
240        .unwrap_or(false)
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244#[non_exhaustive]
245pub enum REncoding {
246    Native,
247    Utf8,
248    Latin1,
249    Bytes,
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255
256    #[test]
257    fn native_ascii_strings_decode_without_header_encoding() {
258        let value = RStr::new(b"name", REncoding::Native, None);
259        assert_eq!(value.as_str().unwrap().unwrap().as_ref(), "name");
260    }
261
262    #[test]
263    fn native_utf8_strings_decode_when_header_encoding_is_utf8() {
264        let value = RStr::new(
265            "cafe\u{301}".as_bytes(),
266            REncoding::Native,
267            Some(Arc::from("UTF-8")),
268        );
269        assert_eq!(value.as_str().unwrap().unwrap().as_ref(), "cafe\u{301}");
270    }
271
272    #[test]
273    fn native_non_ascii_strings_reject_unknown_native_encoding() {
274        let value = RStr::new("é".as_bytes(), REncoding::Native, None);
275        assert_eq!(
276            value.as_str().unwrap().unwrap_err(),
277            Error::InvalidStringEncoding
278        );
279    }
280}
281
282#[derive(Debug, Clone, Copy)]
283pub struct Limits {
284    max_depth: u32,
285    max_vector_len: usize,
286    max_total_elements: usize,
287}
288
289impl Default for Limits {
290    fn default() -> Self {
291        Self {
292            max_depth: 5_000,
293            max_vector_len: 8_000_000,
294            max_total_elements: 16_000_000,
295        }
296    }
297}
298
299impl Limits {
300    pub fn max_depth(mut self, value: u32) -> Self {
301        self.max_depth = value;
302        self
303    }
304
305    pub fn max_vector_len(mut self, value: usize) -> Self {
306        self.max_vector_len = value;
307        self
308    }
309
310    pub fn max_total_elements(mut self, value: usize) -> Self {
311        self.max_total_elements = value;
312        self
313    }
314
315    pub(crate) fn max_depth_value(self) -> u32 {
316        self.max_depth
317    }
318    pub(crate) fn max_vector_len_value(self) -> usize {
319        self.max_vector_len
320    }
321    pub(crate) fn max_total_elements_value(self) -> usize {
322        self.max_total_elements
323    }
324}
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq)]
327#[non_exhaustive]
328pub enum SexpKind {
329    Nil,
330    Sym,
331    PairList,
332    Env,
333    Char,
334    Logical,
335    Integer,
336    Real,
337    String,
338    List,
339    ExtPtr,
340    WeakRef,
341    Persist,
342    Package,
343    Namespace,
344    Ref,
345    Closure,
346    BuiltIn,
347    Special,
348    Promise,
349    Lang,
350    DotDotDot,
351    ByteCode,
352    S4,
353    Complex,
354    Raw,
355    Other(u8),
356}
357
358impl SexpKind {
359    pub fn from_type_code(type_code: u8) -> Self {
360        match type_code {
361            0 | 254 => Self::Nil,
362            1 => Self::Sym,
363            2 => Self::PairList,
364            3 => Self::Closure,
365            4 => Self::Env,
366            5 => Self::Promise,
367            6 => Self::Lang,
368            7 => Self::Special,
369            8 => Self::BuiltIn,
370            9 => Self::Char,
371            10 => Self::Logical,
372            13 => Self::Integer,
373            14 => Self::Real,
374            15 => Self::Complex,
375            16 => Self::String,
376            17 => Self::DotDotDot,
377            19 => Self::List,
378            21 => Self::ByteCode,
379            22 => Self::ExtPtr,
380            23 => Self::WeakRef,
381            24 => Self::Raw,
382            25 => Self::S4,
383            247 => Self::Persist,
384            248 => Self::Package,
385            249 | 250 => Self::Namespace,
386            255 => Self::Ref,
387            other => Self::Other(other),
388        }
389    }
390}