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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum EnvHandle {
34 Global,
36 Base,
38 Empty,
40 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 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}