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