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