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}
356
357impl Default for Limits {
358 fn default() -> Self {
359 Self {
360 max_depth: 5_000,
361 max_vector_len: 8_000_000,
362 max_total_elements: 16_000_000,
363 }
364 }
365}
366
367impl Limits {
368 pub fn max_depth(mut self, value: u32) -> Self {
369 self.max_depth = value;
370 self
371 }
372
373 pub fn max_vector_len(mut self, value: usize) -> Self {
374 self.max_vector_len = value;
375 self
376 }
377
378 pub fn max_total_elements(mut self, value: usize) -> Self {
379 self.max_total_elements = value;
380 self
381 }
382
383 pub(crate) fn max_depth_value(self) -> u32 {
384 self.max_depth
385 }
386 pub(crate) fn max_vector_len_value(self) -> usize {
387 self.max_vector_len
388 }
389 pub(crate) fn max_total_elements_value(self) -> usize {
390 self.max_total_elements
391 }
392}
393
394#[derive(Debug, Clone, Copy, PartialEq, Eq)]
395#[non_exhaustive]
396pub enum SexpKind {
397 Nil,
398 Sym,
399 PairList,
400 Env,
401 Char,
402 Logical,
403 Integer,
404 Real,
405 String,
406 List,
407 ExtPtr,
408 WeakRef,
409 Persist,
410 Package,
411 Namespace,
412 Ref,
413 Closure,
414 BuiltIn,
415 Special,
416 Promise,
417 Lang,
418 DotDotDot,
419 ByteCode,
420 S4,
421 Complex,
422 Raw,
423 Other(u8),
424}
425
426impl SexpKind {
427 pub fn from_type_code(type_code: u8) -> Self {
428 match type_code {
429 0 | 254 => Self::Nil,
430 1 => Self::Sym,
431 2 => Self::PairList,
432 3 => Self::Closure,
433 4 => Self::Env,
434 5 => Self::Promise,
435 6 => Self::Lang,
436 7 => Self::Special,
437 8 => Self::BuiltIn,
438 9 => Self::Char,
439 10 => Self::Logical,
440 13 => Self::Integer,
441 14 => Self::Real,
442 15 => Self::Complex,
443 16 => Self::String,
444 17 => Self::DotDotDot,
445 19 => Self::List,
446 21 => Self::ByteCode,
447 22 => Self::ExtPtr,
448 23 => Self::WeakRef,
449 24 => Self::Raw,
450 25 => Self::S4,
451 247 => Self::Persist,
452 248 => Self::Package,
453 249 | 250 => Self::Namespace,
454 255 => Self::Ref,
455 other => Self::Other(other),
456 }
457 }
458}