1use std::sync::Arc;
2
3use crate::{
4 Attribute, Attributes, ByteCursor, EnvHandle, Error, Header, Limits, Persisted, REncoding,
5 RObject, RStr, RValue, SexpKind, Symbol,
6};
7
8const TYPE_MASK: u32 = 0xff;
9const ATTRIBUTES_BIT: u32 = 1 << 9;
10const TAG_BIT: u32 = 1 << 10;
11const LEVELS_SHIFT: u32 = 12;
12
13const NILSXP: u8 = 0;
14const SYMSXP: u8 = 1;
15const LISTSXP: u8 = 2;
16const CLOSXP: u8 = 3;
17const ENVSXP: u8 = 4;
18const PROMSXP: u8 = 5;
19const LANGSXP: u8 = 6;
20const SPECIALSXP: u8 = 7;
21const BUILTINSXP: u8 = 8;
22const CHARSXP: u8 = 9;
23const LGLSXP: u8 = 10;
24const INTSXP: u8 = 13;
25const REALSXP: u8 = 14;
26const CPLXSXP: u8 = 15;
27const STRSXP: u8 = 16;
28const DOTSXP: u8 = 17;
29const VECSXP: u8 = 19;
30const EXPRSXP: u8 = 20;
31const RAWSXP: u8 = 24;
32const S4SXP: u8 = 25;
33#[cfg(test)]
34const EXTPTRSXP: u8 = 22;
35const BASEENV_SXP: u8 = 241;
36const EMPTYENV_SXP: u8 = 242;
37const PACKAGESXP: u8 = 248;
38const NAMESPACESXP: u8 = 249;
39const BASENAMESPACE_SXP: u8 = 250;
40const MISSINGARG_SXP: u8 = 251;
41const UNBOUNDVALUE_SXP: u8 = 252;
42const GLOBALENV_SXP: u8 = 253;
43const NILVALUE_SXP: u8 = 254;
44const REFSXP: u8 = 255;
45const PERSISTSXP: u8 = 247;
46
47const NA_INTEGER: i32 = i32::MIN;
48const NA_REAL_BITS: u64 = 0x7ff0_0000_0000_07a2;
49
50pub fn parse(bytes: &[u8]) -> Result<RObject, Error> {
51 parse_with_limits(bytes, Limits::default())
52}
53
54pub fn parse_with_limits(bytes: &[u8], limits: Limits) -> Result<RObject, Error> {
55 let mut cursor = ByteCursor::new(bytes);
56 let header = Header::parse(&mut cursor)?;
57 Decoder::new(limits, header.native_encoding).decode_root(&mut cursor)
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub(crate) struct ItemFlags {
62 raw: u32,
63 type_code: u8,
64}
65
66impl ItemFlags {
67 pub(crate) fn from_raw(raw: u32) -> Self {
68 Self {
69 raw,
70 type_code: (raw & TYPE_MASK) as u8,
71 }
72 }
73
74 fn type_code(self) -> u8 {
75 self.type_code
76 }
77
78 fn kind(self) -> SexpKind {
79 SexpKind::from_type_code(self.type_code)
80 }
81
82 fn has_attributes(self) -> bool {
83 self.raw & ATTRIBUTES_BIT != 0
84 }
85
86 fn has_tag(self) -> bool {
87 self.raw & TAG_BIT != 0
88 }
89
90 fn levels(self) -> u32 {
91 self.raw >> LEVELS_SHIFT
92 }
93
94 fn ref_index_inline(self) -> u32 {
95 self.raw >> 8
96 }
97
98 #[cfg(test)]
99 fn is_object(self) -> bool {
100 self.raw & (1 << 8) != 0
101 }
102}
103
104#[derive(Debug, Clone)]
105enum RefEntry {
106 Symbol(Symbol),
107 Persisted(Persisted),
108 Env(EnvHandle),
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121enum Mode {
122 Strict,
123 Discard,
124}
125
126#[derive(Default)]
127struct RefTable {
128 entries: Vec<RefEntry>,
129}
130
131impl RefTable {
132 fn register(&mut self, entry: RefEntry) {
133 self.entries.push(entry);
134 }
135
136 fn resolve(&self, index: u32, offset: usize) -> Result<&RefEntry, Error> {
137 if index == 0 {
138 return Err(Error::RefIndexOutOfRange {
139 index,
140 len: self.entries.len(),
141 offset,
142 });
143 }
144 self.entries
145 .get(index as usize - 1)
146 .ok_or(Error::RefIndexOutOfRange {
147 index,
148 len: self.entries.len(),
149 offset,
150 })
151 }
152}
153
154struct Decoder {
155 refs: RefTable,
156 limits: Limits,
157 total_elements: usize,
158 native_encoding: Option<Arc<str>>,
159}
160
161impl Decoder {
162 fn new(limits: Limits, native_encoding: Option<String>) -> Self {
163 Self {
164 refs: RefTable::default(),
165 limits,
166 total_elements: 0,
167 native_encoding: native_encoding.map(Arc::from),
168 }
169 }
170
171 fn decode_root(&mut self, cursor: &mut ByteCursor<'_>) -> Result<RObject, Error> {
172 self.decode_object(cursor, 0, Mode::Strict)
173 }
174
175 fn decode_object(
176 &mut self,
177 cursor: &mut ByteCursor<'_>,
178 depth: u32,
179 mode: Mode,
180 ) -> Result<RObject, Error> {
181 self.check_depth(depth)?;
182 let flags = self.read_flags(cursor)?;
183 self.decode_object_with_flags(cursor, flags, depth, mode)
184 }
185
186 fn decode_object_with_flags(
187 &mut self,
188 cursor: &mut ByteCursor<'_>,
189 flags: ItemFlags,
190 depth: u32,
191 mode: Mode,
192 ) -> Result<RObject, Error> {
193 match flags.type_code() {
199 REFSXP => return self.decode_ref(cursor, flags),
200 ENVSXP => return self.decode_env(cursor, depth),
201 GLOBALENV_SXP => return Ok(env_object(EnvHandle::Global)),
202 BASEENV_SXP | BASENAMESPACE_SXP => return Ok(env_object(EnvHandle::Base)),
203 EMPTYENV_SXP => return Ok(env_object(EnvHandle::Empty)),
204 _ => {}
205 }
206
207 let value = match flags.type_code() {
208 NILSXP | NILVALUE_SXP => RValue::Null,
209 CHARSXP => RValue::Character(vec![self.decode_char_with_flags(cursor, flags)?]),
210 STRSXP => RValue::Character(self.decode_character_vector(cursor)?),
211 LGLSXP => RValue::Logical(self.decode_logical_vector(cursor)?),
212 INTSXP => RValue::Integer(self.decode_integer_vector(cursor)?),
213 REALSXP => RValue::Real(self.decode_real_vector(cursor)?),
214 VECSXP => RValue::List(self.decode_list(cursor, depth, mode)?),
215 SYMSXP => RValue::Symbol(self.decode_symbol_with_flags(cursor, flags)?),
216 PERSISTSXP => RValue::Persisted(self.decode_persisted(cursor)?),
217 PACKAGESXP | NAMESPACESXP => {
218 RValue::Environment(self.decode_package_or_namespace(cursor)?)
219 }
220 other => {
221 if mode == Mode::Discard {
222 return self.decode_discard(cursor, flags, depth);
223 }
224 return Err(Error::UnsupportedSexp {
225 kind: SexpKind::from_type_code(other),
226 type_code: other,
227 offset: cursor.position().saturating_sub(4),
228 });
229 }
230 };
231
232 let attributes = if flags.has_attributes() {
233 self.decode_attributes(cursor, depth + 1, mode)?
234 } else {
235 Attributes::default()
236 };
237
238 Ok(RObject::from_parts(value, attributes))
239 }
240
241 fn decode_env(&mut self, cursor: &mut ByteCursor<'_>, depth: u32) -> Result<RObject, Error> {
247 let _locked = cursor.read_be_i32()?;
248 self.refs.register(RefEntry::Env(EnvHandle::Other));
249 for _ in 0..4 {
250 let _ = self.decode_object(cursor, depth + 1, Mode::Discard)?;
251 }
252 Ok(env_object(EnvHandle::Other))
253 }
254
255 fn decode_package_or_namespace(
259 &mut self,
260 cursor: &mut ByteCursor<'_>,
261 ) -> Result<EnvHandle, Error> {
262 let _ = self.decode_string_vec(cursor)?;
263 self.refs.register(RefEntry::Env(EnvHandle::Other));
264 Ok(EnvHandle::Other)
265 }
266
267 fn decode_discard(
273 &mut self,
274 cursor: &mut ByteCursor<'_>,
275 flags: ItemFlags,
276 depth: u32,
277 ) -> Result<RObject, Error> {
278 if is_dotted_pair(flags) {
279 self.discard_pairlist_chain(cursor, flags, depth)?;
283 return Ok(RObject::from_parts(RValue::Null, Attributes::default()));
284 }
285
286 match flags.type_code() {
287 UNBOUNDVALUE_SXP | MISSINGARG_SXP => {
288 return Ok(RObject::from_parts(RValue::Null, Attributes::default()));
289 }
290 SPECIALSXP | BUILTINSXP => {
291 let len = self.read_vector_len(cursor)?;
292 let _ = cursor.read_exact(len)?;
293 }
294 CPLXSXP => {
295 let len = self.read_vector_len(cursor)?;
296 for _ in 0..len {
297 let _ = cursor.read_exact(16)?;
298 }
299 }
300 RAWSXP => {
301 let len = self.read_vector_len(cursor)?;
302 let _ = cursor.read_exact(len)?;
303 }
304 EXPRSXP => {
305 let _ = self.decode_list(cursor, depth, Mode::Discard)?;
307 }
308 S4SXP => {
309 }
311 other => {
312 return Err(Error::UnsupportedSexp {
313 kind: SexpKind::from_type_code(other),
314 type_code: other,
315 offset: cursor.position().saturating_sub(4),
316 });
317 }
318 }
319
320 let attributes = if flags.has_attributes() {
321 self.decode_attributes(cursor, depth + 1, Mode::Discard)?
322 } else {
323 Attributes::default()
324 };
325
326 Ok(RObject::from_parts(RValue::Null, attributes))
327 }
328
329 fn discard_pairlist_chain(
337 &mut self,
338 cursor: &mut ByteCursor<'_>,
339 flags: ItemFlags,
340 depth: u32,
341 ) -> Result<(), Error> {
342 let mut flags = flags;
343 loop {
344 self.account_elements(1, cursor.position())?;
345 if flags.has_attributes() {
346 let _ = self.decode_attributes(cursor, depth + 1, Mode::Discard)?;
347 }
348 if flags.has_tag() {
349 let _ = self.decode_object(cursor, depth + 1, Mode::Discard)?;
350 }
351 let _ = self.decode_object(cursor, depth + 1, Mode::Discard)?;
352
353 let cdr_flags = self.read_flags(cursor)?;
354 if is_dotted_pair(cdr_flags) {
355 flags = cdr_flags;
356 continue;
357 }
358 if is_nil(cdr_flags) {
359 return Ok(());
360 }
361 let _ = self.decode_object_with_flags(cursor, cdr_flags, depth + 1, Mode::Discard)?;
362 return Ok(());
363 }
364 }
365
366 fn read_flags(&mut self, cursor: &mut ByteCursor<'_>) -> Result<ItemFlags, Error> {
367 Ok(ItemFlags::from_raw(cursor.read_be_u32()?))
368 }
369
370 fn decode_ref(
371 &mut self,
372 cursor: &mut ByteCursor<'_>,
373 flags: ItemFlags,
374 ) -> Result<RObject, Error> {
375 let inline_index = flags.ref_index_inline();
376 let index = if inline_index == 0 {
377 cursor.read_be_i32()? as u32
378 } else {
379 inline_index
380 };
381
382 match self
383 .refs
384 .resolve(index, cursor.position().saturating_sub(4))?
385 {
386 RefEntry::Symbol(symbol) => Ok(RObject::from_parts(
387 RValue::Symbol(symbol.clone()),
388 Attributes::default(),
389 )),
390 RefEntry::Persisted(persisted) => Ok(RObject::from_parts(
391 RValue::Persisted(persisted.clone()),
392 Attributes::default(),
393 )),
394 RefEntry::Env(handle) => Ok(env_object(*handle)),
395 }
396 }
397
398 fn decode_list(
399 &mut self,
400 cursor: &mut ByteCursor<'_>,
401 depth: u32,
402 mode: Mode,
403 ) -> Result<Vec<RObject>, Error> {
404 let len = self.read_vector_len(cursor)?;
405 (0..len)
406 .map(|_| self.decode_object(cursor, depth + 1, mode))
407 .collect()
408 }
409
410 fn decode_logical_vector(
411 &mut self,
412 cursor: &mut ByteCursor<'_>,
413 ) -> Result<Vec<Option<bool>>, Error> {
414 let len = self.read_vector_len(cursor)?;
415 (0..len)
416 .map(|_| {
417 Ok(match cursor.read_be_i32()? {
418 NA_INTEGER => None,
419 0 => Some(false),
420 _ => Some(true),
421 })
422 })
423 .collect()
424 }
425
426 fn decode_integer_vector(
427 &mut self,
428 cursor: &mut ByteCursor<'_>,
429 ) -> Result<Vec<Option<i32>>, Error> {
430 let len = self.read_vector_len(cursor)?;
431 (0..len)
432 .map(|_| {
433 let value = cursor.read_be_i32()?;
434 Ok((value != NA_INTEGER).then_some(value))
435 })
436 .collect()
437 }
438
439 fn decode_real_vector(
440 &mut self,
441 cursor: &mut ByteCursor<'_>,
442 ) -> Result<Vec<Option<f64>>, Error> {
443 let len = self.read_vector_len(cursor)?;
444 (0..len)
445 .map(|_| {
446 let bits = cursor.read_be_u64()?;
447 Ok((bits != NA_REAL_BITS).then_some(f64::from_bits(bits)))
448 })
449 .collect()
450 }
451
452 fn decode_character_vector(&mut self, cursor: &mut ByteCursor<'_>) -> Result<Vec<RStr>, Error> {
453 let len = self.read_vector_len(cursor)?;
454 (0..len).map(|_| self.decode_char_item(cursor)).collect()
455 }
456
457 fn decode_char_item(&mut self, cursor: &mut ByteCursor<'_>) -> Result<RStr, Error> {
458 let flags = self.read_flags(cursor)?;
459 if flags.type_code() != CHARSXP {
460 return Err(Error::UnsupportedSexp {
461 kind: flags.kind(),
462 type_code: flags.type_code(),
463 offset: cursor.position().saturating_sub(4),
464 });
465 }
466 self.decode_char_with_flags(cursor, flags)
467 }
468
469 fn decode_char_with_flags(
470 &mut self,
471 cursor: &mut ByteCursor<'_>,
472 flags: ItemFlags,
473 ) -> Result<RStr, Error> {
474 let len = cursor.read_be_i32()?;
475 if len == -1 {
476 return Ok(RStr::Na);
477 }
478 if len < 0 {
479 return Err(Error::NegativeLength {
480 len,
481 offset: cursor.position().saturating_sub(4),
482 });
483 }
484
485 let encoding = decode_encoding(flags);
486 let bytes = cursor.read_exact(len as usize)?;
487 Ok(RStr::new(bytes, encoding, self.native_encoding.clone()))
488 }
489
490 fn decode_symbol_with_flags(
491 &mut self,
492 cursor: &mut ByteCursor<'_>,
493 _flags: ItemFlags,
494 ) -> Result<Symbol, Error> {
495 let print_name = self.decode_char_item(cursor)?;
496 let text = print_name
497 .as_str()
498 .ok_or(Error::InvalidSymbolName)?
499 .map_err(|_| Error::InvalidSymbolName)?;
500 let symbol = Symbol::new(Arc::<str>::from(text.as_ref()));
501 self.refs.register(RefEntry::Symbol(symbol.clone()));
502 Ok(symbol)
503 }
504
505 fn decode_persisted(&mut self, cursor: &mut ByteCursor<'_>) -> Result<Persisted, Error> {
506 let values = self.decode_string_vec(cursor)?;
507 let persisted = Persisted::new(values);
508 self.refs.register(RefEntry::Persisted(persisted.clone()));
509 Ok(persisted)
510 }
511
512 fn decode_string_vec(&mut self, cursor: &mut ByteCursor<'_>) -> Result<Vec<RStr>, Error> {
517 let _placeholder = cursor.read_be_i32()?;
518 let offset = cursor.position();
519 let len = cursor.read_be_i32()?;
520 let len = if len == -1 {
521 let len = read_long_len(cursor)?;
522 return Err(Error::PersistedLongVectorUnsupported { len, offset });
523 } else if len < 0 {
524 return Err(Error::NegativeLength { len, offset });
525 } else {
526 len as usize
527 };
528
529 if len > self.limits.max_vector_len_value() {
530 return Err(Error::VectorLengthLimitExceeded {
531 limit: self.limits.max_vector_len_value(),
532 length: len,
533 offset,
534 });
535 }
536 self.account_elements(len, offset)?;
537 (0..len)
538 .map(|_| self.decode_char_item(cursor))
539 .collect::<Result<Vec<_>, _>>()
540 }
541
542 fn decode_attributes(
543 &mut self,
544 cursor: &mut ByteCursor<'_>,
545 depth: u32,
546 mode: Mode,
547 ) -> Result<Attributes, Error> {
548 self.check_depth(depth)?;
549 let flags = self.read_flags(cursor)?;
550 if is_nil(flags) {
551 return Ok(Attributes::default());
552 }
553 let attributes = self.decode_attribute_pairlist_with_flags(cursor, flags, depth, mode)?;
554 Ok(Attributes::new(attributes))
555 }
556
557 fn decode_attribute_pairlist_with_flags(
558 &mut self,
559 cursor: &mut ByteCursor<'_>,
560 flags: ItemFlags,
561 depth: u32,
562 mode: Mode,
563 ) -> Result<Vec<Attribute>, Error> {
564 let flags_offset = cursor.position().saturating_sub(4);
568 if flags.type_code() != LISTSXP {
569 return Err(Error::UnsupportedSexp {
570 kind: flags.kind(),
571 type_code: flags.type_code(),
572 offset: flags_offset,
573 });
574 }
575
576 self.account_elements(1, cursor.position())?;
577
578 if flags.has_attributes() {
579 let _ = self.decode_attributes(cursor, depth + 1, mode)?;
580 }
581
582 let name = if flags.has_tag() {
583 self.decode_attribute_tag(cursor, depth + 1)?
584 } else {
585 return Err(Error::InvalidAttributeTag {
586 offset: flags_offset,
587 });
588 };
589
590 let value = self.decode_object(cursor, depth + 1, mode)?;
591 let cdr_flags = self.read_flags(cursor)?;
592 let mut attributes = vec![Attribute::new(name, value)];
593
594 if !is_nil(cdr_flags) {
595 attributes.extend(self.decode_attribute_pairlist_with_flags(
596 cursor,
597 cdr_flags,
598 depth + 1,
599 mode,
600 )?);
601 }
602
603 Ok(attributes)
604 }
605
606 fn decode_attribute_tag(
607 &mut self,
608 cursor: &mut ByteCursor<'_>,
609 depth: u32,
610 ) -> Result<Symbol, Error> {
611 self.check_depth(depth)?;
612 let flags = self.read_flags(cursor)?;
613 match flags.type_code() {
614 SYMSXP => self.decode_symbol_with_flags(cursor, flags),
615 REFSXP => {
616 let inline_index = flags.ref_index_inline();
617 let index = if inline_index == 0 {
618 cursor.read_be_i32()? as u32
619 } else {
620 inline_index
621 };
622 match self
623 .refs
624 .resolve(index, cursor.position().saturating_sub(4))?
625 {
626 RefEntry::Symbol(symbol) => Ok(symbol.clone()),
627 RefEntry::Persisted(_) | RefEntry::Env(_) => Err(Error::InvalidAttributeTag {
628 offset: cursor.position().saturating_sub(4),
629 }),
630 }
631 }
632 _ => Err(Error::InvalidAttributeTag {
633 offset: cursor.position().saturating_sub(4),
634 }),
635 }
636 }
637
638 fn read_vector_len(&mut self, cursor: &mut ByteCursor<'_>) -> Result<usize, Error> {
639 let offset = cursor.position();
640 let len = cursor.read_be_i32()?;
641 if len == -1 {
642 let len = read_long_len(cursor)?;
643 return Err(Error::LongVectorUnsupported { len, offset });
644 }
645 if len < 0 {
646 return Err(Error::NegativeLength { len, offset });
647 }
648 let len = len as usize;
649 if len > self.limits.max_vector_len_value() {
650 return Err(Error::VectorLengthLimitExceeded {
651 limit: self.limits.max_vector_len_value(),
652 length: len,
653 offset,
654 });
655 }
656 self.account_elements(len, offset)?;
657 Ok(len)
658 }
659
660 fn check_depth(&self, depth: u32) -> Result<(), Error> {
661 if depth > self.limits.max_depth_value() {
662 Err(Error::DepthLimitExceeded {
663 limit: self.limits.max_depth_value(),
664 })
665 } else {
666 Ok(())
667 }
668 }
669
670 fn account_elements(&mut self, count: usize, offset: usize) -> Result<(), Error> {
671 let total = self.total_elements.saturating_add(count);
672 if total > self.limits.max_total_elements_value() {
673 return Err(Error::TotalElementsLimitExceeded {
674 limit: self.limits.max_total_elements_value(),
675 total,
676 offset,
677 });
678 }
679 self.total_elements = total;
680 Ok(())
681 }
682}
683
684fn decode_encoding(flags: ItemFlags) -> REncoding {
689 let levels = flags.levels();
690 if levels & (1 << 3) != 0 {
691 REncoding::Utf8
692 } else if levels & (1 << 2) != 0 {
693 REncoding::Latin1
694 } else if levels & (1 << 1) != 0 {
695 REncoding::Bytes
696 } else {
697 REncoding::Native
698 }
699}
700
701fn is_nil(flags: ItemFlags) -> bool {
702 matches!(flags.type_code(), NILSXP | NILVALUE_SXP)
703}
704
705fn is_dotted_pair(flags: ItemFlags) -> bool {
706 matches!(
707 flags.type_code(),
708 LISTSXP | LANGSXP | CLOSXP | PROMSXP | DOTSXP
709 )
710}
711
712fn env_object(handle: EnvHandle) -> RObject {
713 RObject::from_parts(RValue::Environment(handle), Attributes::default())
714}
715
716fn read_long_len(cursor: &mut ByteCursor<'_>) -> Result<u64, Error> {
717 let upper = cursor.read_be_i32()? as u32 as u64;
718 let lower = cursor.read_be_i32()? as u32 as u64;
719 Ok((upper << 32) | lower)
720}
721
722#[cfg(test)]
723mod tests {
724 use super::*;
725 use std::{fs, io::Read, path::PathBuf};
726
727 use flate2::read::GzDecoder;
728
729 fn item(bytes: &[u8]) -> Result<RObject, Error> {
730 item_with_limits(bytes, Limits::default())
731 }
732
733 fn item_with_limits(bytes: &[u8], limits: Limits) -> Result<RObject, Error> {
734 let mut cursor = ByteCursor::new(bytes);
735 Decoder::new(limits, None).decode_root(&mut cursor)
736 }
737
738 fn fixture_dir() -> PathBuf {
739 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/data")
740 }
741
742 fn fixture(name: &str) -> RObject {
743 let bytes = fs::read(fixture_dir().join(name)).expect("fixture bytes");
744 let mut decoder = GzDecoder::new(bytes.as_slice());
745 let mut decompressed = Vec::new();
746 decoder
747 .read_to_end(&mut decompressed)
748 .expect("fixture gzip stream");
749 parse(&decompressed).expect(name)
750 }
751
752 fn rstr(value: &RStr) -> String {
753 value.as_str().unwrap().unwrap().into_owned()
754 }
755
756 fn strings(value: &RObject) -> Vec<String> {
757 let RValue::Character(values) = value.value() else {
758 panic!("expected character vector, got {value:?}");
759 };
760 values.iter().map(rstr).collect()
761 }
762
763 fn list(value: &RObject) -> &[RObject] {
764 let RValue::List(values) = value.value() else {
765 panic!("expected list, got {value:?}");
766 };
767 values
768 }
769
770 fn persisted(value: &RObject) -> &Persisted {
771 let RValue::Persisted(value) = value.value() else {
772 panic!("expected persisted value, got {value:?}");
773 };
774 value
775 }
776
777 fn env_handle(value: &RObject) -> EnvHandle {
778 let RValue::Environment(handle) = value.value() else {
779 panic!("expected environment, got {value:?}");
780 };
781 *handle
782 }
783
784 fn symbol_name(value: &RObject) -> &str {
785 let RValue::Symbol(symbol) = value.value() else {
786 panic!("expected symbol, got {value:?}");
787 };
788 symbol.as_str()
789 }
790
791 #[test]
792 fn decodes_flags_word() {
793 let flags = ItemFlags::from_raw(0x0004_0713);
794 assert_eq!(flags.type_code(), VECSXP);
795 assert!(flags.is_object());
796 assert!(flags.has_attributes());
797 assert!(flags.has_tag());
798 assert_eq!(flags.levels(), 0x40);
799
800 let ref_flags = ItemFlags::from_raw(0x0000_05ff);
801 assert_eq!(ref_flags.type_code(), REFSXP);
802 assert_eq!(ref_flags.ref_index_inline(), 5);
803 }
804
805 #[test]
806 fn decodes_na_string_integer_and_logical() {
807 let charsxp_na = [0, 0, 0, CHARSXP, 0xff, 0xff, 0xff, 0xff];
808 let value = item(&charsxp_na).unwrap();
809 assert_eq!(value.value(), &RValue::Character(vec![RStr::Na]));
810
811 let int_vec = [0, 0, 0, INTSXP, 0, 0, 0, 1, 0x80, 0, 0, 0];
812 let value = item(&int_vec).unwrap();
813 assert_eq!(value.value(), &RValue::Integer(vec![None]));
814
815 let logical_vec = [0, 0, 0, LGLSXP, 0, 0, 0, 2, 0x80, 0, 0, 0, 0, 0, 0, 1];
816 let value = item(&logical_vec).unwrap();
817 assert_eq!(value.value(), &RValue::Logical(vec![None, Some(true)]));
818 }
819
820 #[test]
821 fn charsxp_encoding_levels_bits() {
822 let flags: u32 = 9 | (8 << 12);
824 let mut bytes = flags.to_be_bytes().to_vec();
825 bytes.extend_from_slice(&1i32.to_be_bytes());
826 bytes.push(b'a');
827 let value = item(&bytes).unwrap();
828 let RValue::Character(strs) = value.value() else {
829 panic!("expected character vector, got {value:?}");
830 };
831 assert_eq!(strs[0].encoding(), Some(REncoding::Utf8));
832
833 let flags: u32 = 9 | (64 << 12);
836 let mut bytes = flags.to_be_bytes().to_vec();
837 bytes.extend_from_slice(&1i32.to_be_bytes());
838 bytes.push(b'a');
839 let value = item(&bytes).unwrap();
840 let RValue::Character(strs) = value.value() else {
841 panic!("expected character vector, got {value:?}");
842 };
843 assert_eq!(strs[0].encoding(), Some(REncoding::Native));
844 assert_eq!(strs[0].as_str().unwrap().unwrap().as_ref(), "a");
845 }
846
847 #[test]
848 fn untagged_attribute_cell_with_nested_attributes_reports_cell_offset() {
849 let mut bytes = Vec::new();
850 bytes.extend_from_slice(&(u32::from(LGLSXP) | ATTRIBUTES_BIT).to_be_bytes());
852 bytes.extend_from_slice(&1i32.to_be_bytes());
853 bytes.extend_from_slice(&1i32.to_be_bytes());
854 let cell_flags_offset = bytes.len();
855 bytes.extend_from_slice(&(u32::from(LISTSXP) | ATTRIBUTES_BIT).to_be_bytes());
858 bytes.extend_from_slice(&(u32::from(LISTSXP) | TAG_BIT).to_be_bytes());
859 bytes.extend_from_slice(&u32::from(SYMSXP).to_be_bytes());
860 bytes.extend_from_slice(&(u32::from(CHARSXP) | (8 << 12)).to_be_bytes());
861 bytes.extend_from_slice(&1i32.to_be_bytes());
862 bytes.push(b'x');
863 bytes.extend_from_slice(&u32::from(NILVALUE_SXP).to_be_bytes());
864 bytes.extend_from_slice(&u32::from(NILVALUE_SXP).to_be_bytes());
865
866 let err = item(&bytes).unwrap_err();
867 assert!(
868 matches!(err, Error::InvalidAttributeTag { offset } if offset == cell_flags_offset),
869 "expected InvalidAttributeTag at {cell_flags_offset}, got {err:?}"
870 );
871 }
872
873 #[test]
874 fn singleton_env_byte_level_decoding() {
875 for (byte, expected) in [
876 (253u8, EnvHandle::Global),
877 (241u8, EnvHandle::Base),
878 (242u8, EnvHandle::Empty),
879 (250u8, EnvHandle::Base),
880 ] {
881 let bytes = [0, 0, 0, byte];
882 let mut cursor = ByteCursor::new(&bytes);
883 let value = Decoder::new(Limits::default(), None)
884 .decode_root(&mut cursor)
885 .unwrap();
886 assert_eq!(value.value(), &RValue::Environment(expected));
887 assert_eq!(cursor.remaining(), 0);
888 }
889 }
890
891 #[test]
892 fn environment_frame_pairlist_cells_count_toward_total_elements_limit() {
893 let mut bytes = Vec::new();
894 bytes.extend_from_slice(&u32::from(ENVSXP).to_be_bytes());
895 bytes.extend_from_slice(&0i32.to_be_bytes());
896 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(LISTSXP).to_be_bytes());
899 for index in 0..3 {
900 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); let cdr = if index == 2 { 0 } else { u32::from(LISTSXP) };
902 bytes.extend_from_slice(&cdr.to_be_bytes());
903 }
904 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); let error = item_with_limits(&bytes, Limits::default().max_total_elements(2))
908 .expect_err("frame pairlist should exceed the element limit");
909 assert!(matches!(
910 error,
911 Error::TotalElementsLimitExceeded { limit: 2, .. }
912 ));
913 }
914
915 #[test]
916 fn compliant_environment_frame_pairlist_decodes_to_other() {
917 let mut bytes = Vec::new();
918 bytes.extend_from_slice(&u32::from(ENVSXP).to_be_bytes());
919 bytes.extend_from_slice(&0i32.to_be_bytes());
920 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(LISTSXP).to_be_bytes());
922 bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); bytes.extend_from_slice(&u32::from(0u8).to_be_bytes()); let value = item_with_limits(&bytes, Limits::default().max_total_elements(1))
928 .expect("compliant environment should decode");
929 assert_eq!(env_handle(&value), EnvHandle::Other);
930 }
931
932 #[test]
933 fn refsxp_out_of_range_index_is_reported() {
934 let err = item(&[0, 0, 1, REFSXP]).unwrap_err();
935 assert_eq!(
936 err,
937 Error::RefIndexOutOfRange {
938 index: 1,
939 len: 0,
940 offset: 0
941 }
942 );
943 }
944
945 #[test]
946 fn persistsxp_long_vector_escape_is_reported() {
947 let err = item(&[
948 0, 0, 0, PERSISTSXP, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 1, 0, 0, 0, 2,
949 ])
950 .unwrap_err();
951 assert_eq!(
952 err,
953 Error::PersistedLongVectorUnsupported {
954 len: 0x1_0000_0002,
955 offset: 8
956 }
957 );
958 }
959
960 #[test]
961 fn unsupported_type_is_reported() {
962 let err = item(&[0, 0, 0, EXTPTRSXP]).unwrap_err();
963 assert_eq!(
964 err,
965 Error::UnsupportedSexp {
966 kind: SexpKind::ExtPtr,
967 type_code: EXTPTRSXP,
968 offset: 0
969 }
970 );
971 }
972
973 #[test]
974 fn strict_mode_rejects_dotted_pair_at_top_level() {
975 let err = item(&[0, 0, 0, CLOSXP]).unwrap_err();
976 assert_eq!(
977 err,
978 Error::UnsupportedSexp {
979 kind: SexpKind::Closure,
980 type_code: CLOSXP,
981 offset: 0
982 }
983 );
984 }
985
986 #[test]
987 fn decodes_aliases_vector_fixtures() {
988 for version in [2, 3] {
989 let root = fixture(&format!("aliases_vector_v{version}.rds"));
990 assert_eq!(
991 strings(&root),
992 vec![
993 "minimal",
994 "multialias",
995 "multialias",
996 "multialias",
997 "multialias"
998 ]
999 );
1000 assert_eq!(
1001 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1002 vec![
1003 "minimal",
1004 "multialias",
1005 "multialias-method",
1006 "multialias.default",
1007 "print.multialias"
1008 ]
1009 );
1010 }
1011 }
1012
1013 #[test]
1014 fn decodes_shared_symbols_fixtures() {
1015 for version in [2, 3] {
1016 let root = fixture(&format!("shared_symbols_v{version}.rds"));
1017 assert_eq!(
1018 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1019 vec!["a", "b", "d"]
1020 );
1021 let items = list(&root);
1022 assert_eq!(items.len(), 3);
1023
1024 assert_eq!(
1025 items[0]
1026 .class()
1027 .unwrap()
1028 .iter()
1029 .map(rstr)
1030 .collect::<Vec<_>>(),
1031 vec!["widget"]
1032 );
1033 assert_eq!(
1034 strings(items[0].attributes().get("note").unwrap()),
1035 vec!["first"]
1036 );
1037
1038 let b_items = list(&items[1]);
1039 assert_eq!(
1040 items[1]
1041 .class()
1042 .unwrap()
1043 .iter()
1044 .map(rstr)
1045 .collect::<Vec<_>>(),
1046 vec!["widget"]
1047 );
1048 assert_eq!(
1049 strings(items[1].attributes().get("note").unwrap()),
1050 vec!["third"]
1051 );
1052 assert_eq!(
1053 items[1]
1054 .names()
1055 .unwrap()
1056 .iter()
1057 .map(rstr)
1058 .collect::<Vec<_>>(),
1059 vec!["c"]
1060 );
1061 assert_eq!(
1062 b_items[0]
1063 .class()
1064 .unwrap()
1065 .iter()
1066 .map(rstr)
1067 .collect::<Vec<_>>(),
1068 vec!["widget"]
1069 );
1070 assert_eq!(
1071 strings(b_items[0].attributes().get("note").unwrap()),
1072 vec!["second"]
1073 );
1074
1075 assert_eq!(strings(&items[2]), vec!["x"]);
1076 assert_eq!(
1077 items[2]
1078 .class()
1079 .unwrap()
1080 .iter()
1081 .map(rstr)
1082 .collect::<Vec<_>>(),
1083 vec!["widget"]
1084 );
1085 assert_eq!(
1086 strings(items[2].attributes().get("note").unwrap()),
1087 vec!["fourth"]
1088 );
1089 }
1090 }
1091
1092 #[test]
1093 fn decodes_persistsxp_basic_fixtures() {
1094 for version in [2, 3] {
1095 let root = fixture(&format!("persistsxp_basic_v{version}.rds"));
1096 assert_eq!(
1097 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1098 vec!["env", "tail"]
1099 );
1100 let items = list(&root);
1101 assert_eq!(
1102 persisted(&items[0])
1103 .as_slice()
1104 .iter()
1105 .map(rstr)
1106 .collect::<Vec<_>>(),
1107 vec!["srcref-env"]
1108 );
1109 assert_eq!(strings(&items[1]), vec!["tail-marker"]);
1110 }
1111 }
1112
1113 #[test]
1114 fn decodes_persistsxp_twice_fixtures() {
1115 for version in [2, 3] {
1116 let root = fixture(&format!("persistsxp_twice_v{version}.rds"));
1117 assert_eq!(
1118 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1119 vec!["first", "second", "after"]
1120 );
1121 let items = list(&root);
1122 let first = persisted(&items[0]);
1123 let second = persisted(&items[1]);
1124 assert_eq!(
1125 first.as_slice().iter().map(rstr).collect::<Vec<_>>(),
1126 vec!["srcref-env"]
1127 );
1128 assert_eq!(
1129 second.as_slice().iter().map(rstr).collect::<Vec<_>>(),
1130 vec!["srcref-env"]
1131 );
1132 assert!(!first.ptr_eq(second));
1133 assert_eq!(strings(&items[2]), vec!["tail-marker"]);
1134 }
1135 }
1136
1137 #[test]
1138 fn decodes_persistsxp_multi_fixtures() {
1139 for version in [2, 3] {
1140 let root = fixture(&format!("persistsxp_multi_v{version}.rds"));
1141 let items = list(&root);
1142 assert_eq!(
1143 persisted(&items[0])
1144 .as_slice()
1145 .iter()
1146 .map(rstr)
1147 .collect::<Vec<_>>(),
1148 vec!["a", "b", "c"]
1149 );
1150 assert_eq!(strings(&items[1]), vec!["tail-marker"]);
1151 }
1152 }
1153
1154 #[test]
1155 fn decodes_singleton_envs_fixtures() {
1156 for version in [2, 3] {
1157 let root = fixture(&format!("singleton_envs_v{version}.rds"));
1158 assert_eq!(
1159 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1160 vec!["global", "base", "empty"]
1161 );
1162 let items = list(&root);
1163 assert_eq!(env_handle(&items[0]), EnvHandle::Global);
1164 assert_eq!(env_handle(&items[1]), EnvHandle::Base);
1165 assert_eq!(env_handle(&items[2]), EnvHandle::Empty);
1166 }
1167 }
1168
1169 #[test]
1170 fn decodes_plain_env_fixtures() {
1171 for version in [2, 3] {
1172 let root = fixture(&format!("plain_env_v{version}.rds"));
1173 assert_eq!(env_handle(&root), EnvHandle::Other);
1174 assert!(root.attributes().is_empty());
1175 }
1176 }
1177
1178 #[test]
1179 fn decodes_env_with_closure_fixtures() {
1180 for version in [2, 3] {
1181 let root = fixture(&format!("env_with_closure_v{version}.rds"));
1182 assert_eq!(
1183 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1184 vec!["env", "tail"]
1185 );
1186 let items = list(&root);
1187 assert_eq!(items[0].value(), &RValue::Environment(EnvHandle::Other));
1188 assert_eq!(strings(&items[1]), vec!["tail-marker"]);
1189 }
1190 }
1191
1192 #[test]
1193 fn decodes_shared_env_refs_fixtures() {
1194 for version in [2, 3] {
1195 let root = fixture(&format!("shared_env_refs_v{version}.rds"));
1196 assert_eq!(
1197 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1198 vec!["vec", "sym_a", "env_first", "sym_b", "env_second"]
1199 );
1200 let items = list(&root);
1201 assert_eq!(
1202 items[0].value(),
1203 &RValue::Integer(vec![Some(4), Some(2), Some(7)])
1204 );
1205 assert_eq!(symbol_name(&items[1]), "dup_sym");
1206 assert_eq!(env_handle(&items[2]), EnvHandle::Other);
1207 assert_eq!(symbol_name(&items[3]), "dup_sym");
1208 assert_eq!(env_handle(&items[4]), EnvHandle::Other);
1209 }
1210 }
1211
1212 #[test]
1216 fn altrep_is_rejected() {
1217 let bytes = fs::read(fixture_dir().join("altrep_intseq_v3.rds")).expect("fixture bytes");
1218 let mut decoder = GzDecoder::new(bytes.as_slice());
1219 let mut decompressed = Vec::new();
1220 decoder
1221 .read_to_end(&mut decompressed)
1222 .expect("fixture gzip stream");
1223 let err = parse(&decompressed).unwrap_err();
1224 assert_eq!(
1225 err,
1226 Error::UnsupportedSexp {
1227 kind: SexpKind::Other(238),
1228 type_code: 238,
1229 offset: 23
1230 }
1231 );
1232 }
1233
1234 #[test]
1235 fn decodes_namespace_refs_fixtures() {
1236 for version in [2, 3] {
1237 let root = fixture(&format!("namespace_refs_v{version}.rds"));
1238 assert_eq!(
1239 root.names().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1240 vec!["ns_first", "ns_second", "tail"]
1241 );
1242 let items = list(&root);
1243 assert_eq!(items[0].value(), &RValue::Environment(EnvHandle::Other));
1244 assert_eq!(items[1].value(), &RValue::Environment(EnvHandle::Other));
1245 assert_eq!(strings(&items[2]), vec!["tail-marker"]);
1246 }
1247 }
1248
1249 #[test]
1250 fn decodes_rd_fixtures_as_rd_class_lists() {
1251 for name in ["rd_minimal", "rd_aliases", "rd_arguments", "rd_seealso"] {
1252 for version in [2, 3] {
1253 let root = fixture(&format!("{name}_v{version}.rds"));
1254 assert!(matches!(root.value(), &RValue::List(_)));
1255 assert_eq!(
1256 root.class().unwrap().iter().map(rstr).collect::<Vec<_>>(),
1257 vec!["Rd"]
1258 );
1259 if name == "rd_seealso" {
1260 assert!(root.attributes().get("srcref").is_some());
1261 }
1262
1263 let items = list(&root);
1269 assert!(!items.is_empty(), "{name}_v{version}: empty root list");
1270 let mut tagged_count = 0usize;
1271 for (index, item) in items.iter().enumerate() {
1272 if matches!(item.value(), &RValue::List(_)) {
1273 let rd_tag = item.attributes().get("Rd_tag");
1274 if index == 0 {
1275 assert!(
1276 rd_tag.is_some(),
1277 "{name}_v{version}: first element missing Rd_tag"
1278 );
1279 }
1280 if let Some(rd_tag) = rd_tag {
1281 assert!(
1282 matches!(rd_tag.value(), &RValue::Character(_)),
1283 "{name}_v{version}: Rd_tag value is not a character vector"
1284 );
1285 tagged_count += 1;
1286 }
1287 }
1288 }
1289 assert!(
1290 tagged_count >= 1,
1291 "{name}_v{version}: no list element carries Rd_tag"
1292 );
1293 }
1294 }
1295 }
1296}