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)]
141pub struct Symbol(Arc<str>);
142
143impl Symbol {
144 pub fn new(value: impl Into<Arc<str>>) -> Self {
145 Self(value.into())
146 }
147
148 pub fn as_str(&self) -> &str {
149 &self.0
150 }
151}
152
153impl From<&str> for Symbol {
154 fn from(value: &str) -> Self {
155 Self::new(value)
156 }
157}
158
159#[derive(Debug, Clone, PartialEq)]
160pub struct Persisted(Arc<[RStr]>);
161
162impl Persisted {
163 pub(crate) fn new(values: Vec<RStr>) -> Self {
164 Self(values.into())
165 }
166
167 #[cfg(test)]
168 pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
169 Arc::ptr_eq(&self.0, &other.0)
170 }
171
172 pub fn as_slice(&self) -> &[RStr] {
173 &self.0
174 }
175}
176
177#[derive(Debug, Clone, PartialEq, Eq)]
178#[non_exhaustive]
179pub enum RStr {
180 Na,
181 Value(RStrValue),
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
186#[non_exhaustive]
187pub enum NativeEncodingSource {
188 Header(Arc<str>),
190 AssumedUtf8,
193 Unknown,
196}
197
198impl NativeEncodingSource {
199 pub(crate) fn decodes_as_utf8(&self) -> bool {
200 match self {
201 Self::Header(name) => is_utf8_native_encoding(Some(name)),
202 Self::AssumedUtf8 => true,
203 Self::Unknown => false,
204 }
205 }
206}
207
208#[derive(Debug, Clone, PartialEq, Eq)]
210pub struct RStrValue {
211 bytes: Arc<[u8]>,
212 encoding: REncoding,
213 native_encoding_source: NativeEncodingSource,
214}
215
216impl RStr {
217 pub fn new(
220 bytes: &[u8],
221 encoding: REncoding,
222 native_encoding_source: NativeEncodingSource,
223 ) -> Self {
224 Self::Value(RStrValue {
225 bytes: Arc::from(bytes),
226 encoding,
227 native_encoding_source,
228 })
229 }
230
231 pub fn as_str(&self) -> Option<Result<Cow<'_, str>, Error>> {
232 match self {
233 Self::Na => None,
234 Self::Value(value) => Some(value.as_str()),
235 }
236 }
237
238 pub fn encoding(&self) -> Option<REncoding> {
242 match self {
243 Self::Na => None,
244 Self::Value(value) => Some(value.encoding()),
245 }
246 }
247}
248
249impl RStrValue {
250 fn as_str(&self) -> Result<Cow<'_, str>, Error> {
251 match self.encoding {
252 REncoding::Native => {
253 if self.bytes.is_ascii() || self.native_encoding_source.decodes_as_utf8() {
254 std::str::from_utf8(&self.bytes)
255 .map(Cow::Borrowed)
256 .map_err(|_| Error::InvalidStringEncoding)
257 } else {
258 Err(Error::InvalidStringEncoding)
259 }
260 }
261 REncoding::Utf8 => std::str::from_utf8(&self.bytes)
262 .map(Cow::Borrowed)
263 .map_err(|_| Error::InvalidStringEncoding),
264 REncoding::Latin1 => Ok(Cow::Owned(
265 self.bytes.iter().map(|&byte| byte as char).collect(),
266 )),
267 REncoding::Bytes => Err(Error::InvalidStringEncoding),
268 }
269 }
270
271 pub fn bytes(&self) -> &[u8] {
273 &self.bytes
274 }
275
276 pub fn encoding(&self) -> REncoding {
278 self.encoding
279 }
280
281 pub fn native_encoding_source(&self) -> &NativeEncodingSource {
283 &self.native_encoding_source
284 }
285
286 pub fn header_native_encoding(&self) -> Option<&str> {
292 match &self.native_encoding_source {
293 NativeEncodingSource::Header(name) => Some(name),
294 NativeEncodingSource::AssumedUtf8 | NativeEncodingSource::Unknown => None,
295 }
296 }
297}
298
299fn is_utf8_native_encoding(encoding: Option<&str>) -> bool {
300 encoding
301 .map(|encoding| {
302 encoding.eq_ignore_ascii_case("UTF-8") || encoding.eq_ignore_ascii_case("UTF8")
303 })
304 .unwrap_or(false)
305}
306
307#[derive(Debug, Clone, Copy, PartialEq, Eq)]
308#[non_exhaustive]
309pub enum REncoding {
310 Native,
311 Utf8,
312 Latin1,
313 Bytes,
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn native_ascii_strings_decode_without_header_encoding() {
322 let value = RStr::new(b"name", REncoding::Native, NativeEncodingSource::Unknown);
323 assert_eq!(value.as_str().unwrap().unwrap().as_ref(), "name");
324 }
325
326 #[test]
327 fn native_utf8_strings_decode_when_header_encoding_is_utf8() {
328 let value = RStr::new(
329 "cafe\u{301}".as_bytes(),
330 REncoding::Native,
331 NativeEncodingSource::Header(Arc::from("UTF-8")),
332 );
333 assert_eq!(value.as_str().unwrap().unwrap().as_ref(), "cafe\u{301}");
334 }
335
336 #[test]
337 fn native_non_ascii_strings_reject_unknown_native_encoding() {
338 let value = RStr::new(
339 "é".as_bytes(),
340 REncoding::Native,
341 NativeEncodingSource::Unknown,
342 );
343 assert_eq!(
344 value.as_str().unwrap().unwrap_err(),
345 Error::InvalidStringEncoding
346 );
347 }
348}
349
350#[derive(Debug, Clone, Copy)]
351pub struct Limits {
352 max_depth: u32,
353 max_vector_len: usize,
354 max_total_elements: usize,
355 max_references: usize,
356}
357
358impl Default for Limits {
359 fn default() -> Self {
360 Self {
361 max_depth: 5_000,
362 max_vector_len: 8_000_000,
363 max_total_elements: 16_000_000,
364 max_references: 16_000_000,
365 }
366 }
367}
368
369impl Limits {
370 pub fn max_depth(mut self, value: u32) -> Self {
371 self.max_depth = value;
372 self
373 }
374
375 pub fn max_vector_len(mut self, value: usize) -> Self {
376 self.max_vector_len = value;
377 self
378 }
379
380 pub fn max_total_elements(mut self, value: usize) -> Self {
381 self.max_total_elements = value;
382 self
383 }
384
385 #[must_use]
387 pub fn max_references(mut self, value: usize) -> Self {
388 self.max_references = value;
389 self
390 }
391
392 pub(crate) fn max_depth_value(self) -> u32 {
393 self.max_depth
394 }
395 pub(crate) fn max_vector_len_value(self) -> usize {
396 self.max_vector_len
397 }
398 pub(crate) fn max_total_elements_value(self) -> usize {
399 self.max_total_elements
400 }
401 pub(crate) fn max_references_value(self) -> usize {
402 self.max_references
403 }
404}
405
406#[derive(Debug, Clone, Copy, PartialEq, Eq)]
407#[non_exhaustive]
408pub enum SexpKind {
409 Nil,
410 Sym,
411 PairList,
412 Env,
413 Char,
414 Logical,
415 Integer,
416 Real,
417 String,
418 List,
419 ExtPtr,
420 WeakRef,
421 Persist,
422 Package,
423 Namespace,
424 Ref,
425 Closure,
426 BuiltIn,
427 Special,
428 Promise,
429 Lang,
430 DotDotDot,
431 ByteCode,
432 S4,
433 Complex,
434 Raw,
435 Other(u8),
436}
437
438impl SexpKind {
439 pub fn from_type_code(type_code: u8) -> Self {
440 match type_code {
441 0 | 254 => Self::Nil,
442 1 => Self::Sym,
443 2 => Self::PairList,
444 3 => Self::Closure,
445 4 => Self::Env,
446 5 => Self::Promise,
447 6 => Self::Lang,
448 7 => Self::Special,
449 8 => Self::BuiltIn,
450 9 => Self::Char,
451 10 => Self::Logical,
452 13 => Self::Integer,
453 14 => Self::Real,
454 15 => Self::Complex,
455 16 => Self::String,
456 17 => Self::DotDotDot,
457 19 => Self::List,
458 21 => Self::ByteCode,
459 22 => Self::ExtPtr,
460 23 => Self::WeakRef,
461 24 => Self::Raw,
462 25 => Self::S4,
463 247 => Self::Persist,
464 248 => Self::Package,
465 249 | 250 => Self::Namespace,
466 255 => Self::Ref,
467 other => Self::Other(other),
468 }
469 }
470}