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    /// Reports the CHARSXP encoding flag recorded in the serialized data.
228    /// R's `Encoding()` normalizes ASCII strings to "unknown" after reading,
229    /// so the two can differ while the decoded string contents agree.
230    pub fn encoding(&self) -> Option<REncoding> {
231        match self {
232            Self::Na => None,
233            Self::Value { encoding, .. } => Some(*encoding),
234        }
235    }
236}
237
238fn is_utf8_native_encoding(encoding: Option<&str>) -> bool {
239    encoding
240        .map(|encoding| {
241            encoding.eq_ignore_ascii_case("UTF-8") || encoding.eq_ignore_ascii_case("UTF8")
242        })
243        .unwrap_or(false)
244}
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq)]
247#[non_exhaustive]
248pub enum REncoding {
249    Native,
250    Utf8,
251    Latin1,
252    Bytes,
253}
254
255#[cfg(test)]
256mod tests {
257    use super::*;
258
259    #[test]
260    fn native_ascii_strings_decode_without_header_encoding() {
261        let value = RStr::new(b"name", REncoding::Native, None);
262        assert_eq!(value.as_str().unwrap().unwrap().as_ref(), "name");
263    }
264
265    #[test]
266    fn native_utf8_strings_decode_when_header_encoding_is_utf8() {
267        let value = RStr::new(
268            "cafe\u{301}".as_bytes(),
269            REncoding::Native,
270            Some(Arc::from("UTF-8")),
271        );
272        assert_eq!(value.as_str().unwrap().unwrap().as_ref(), "cafe\u{301}");
273    }
274
275    #[test]
276    fn native_non_ascii_strings_reject_unknown_native_encoding() {
277        let value = RStr::new("é".as_bytes(), REncoding::Native, None);
278        assert_eq!(
279            value.as_str().unwrap().unwrap_err(),
280            Error::InvalidStringEncoding
281        );
282    }
283}
284
285#[derive(Debug, Clone, Copy)]
286pub struct Limits {
287    max_depth: u32,
288    max_vector_len: usize,
289    max_total_elements: usize,
290}
291
292impl Default for Limits {
293    fn default() -> Self {
294        Self {
295            max_depth: 5_000,
296            max_vector_len: 8_000_000,
297            max_total_elements: 16_000_000,
298        }
299    }
300}
301
302impl Limits {
303    pub fn max_depth(mut self, value: u32) -> Self {
304        self.max_depth = value;
305        self
306    }
307
308    pub fn max_vector_len(mut self, value: usize) -> Self {
309        self.max_vector_len = value;
310        self
311    }
312
313    pub fn max_total_elements(mut self, value: usize) -> Self {
314        self.max_total_elements = value;
315        self
316    }
317
318    pub(crate) fn max_depth_value(self) -> u32 {
319        self.max_depth
320    }
321    pub(crate) fn max_vector_len_value(self) -> usize {
322        self.max_vector_len
323    }
324    pub(crate) fn max_total_elements_value(self) -> usize {
325        self.max_total_elements
326    }
327}
328
329#[derive(Debug, Clone, Copy, PartialEq, Eq)]
330#[non_exhaustive]
331pub enum SexpKind {
332    Nil,
333    Sym,
334    PairList,
335    Env,
336    Char,
337    Logical,
338    Integer,
339    Real,
340    String,
341    List,
342    ExtPtr,
343    WeakRef,
344    Persist,
345    Package,
346    Namespace,
347    Ref,
348    Closure,
349    BuiltIn,
350    Special,
351    Promise,
352    Lang,
353    DotDotDot,
354    ByteCode,
355    S4,
356    Complex,
357    Raw,
358    Other(u8),
359}
360
361impl SexpKind {
362    pub fn from_type_code(type_code: u8) -> Self {
363        match type_code {
364            0 | 254 => Self::Nil,
365            1 => Self::Sym,
366            2 => Self::PairList,
367            3 => Self::Closure,
368            4 => Self::Env,
369            5 => Self::Promise,
370            6 => Self::Lang,
371            7 => Self::Special,
372            8 => Self::BuiltIn,
373            9 => Self::Char,
374            10 => Self::Logical,
375            13 => Self::Integer,
376            14 => Self::Real,
377            15 => Self::Complex,
378            16 => Self::String,
379            17 => Self::DotDotDot,
380            19 => Self::List,
381            21 => Self::ByteCode,
382            22 => Self::ExtPtr,
383            23 => Self::WeakRef,
384            24 => Self::Raw,
385            25 => Self::S4,
386            247 => Self::Persist,
387            248 => Self::Package,
388            249 | 250 => Self::Namespace,
389            255 => Self::Ref,
390            other => Self::Other(other),
391        }
392    }
393}