1use crate::coerce::{CoerceError, TryCoerce};
51use crate::from_r::BATCHED_ERROR_CAP;
52use crate::into_r::IntoR;
53use crate::{RLogical, SEXP};
54use std::fmt;
55
56#[derive(Debug, Clone, PartialEq, Eq)]
60pub enum StorageCoerceError {
61 Unsupported {
63 from: &'static str,
65 to: &'static str,
67 },
68 OutOfRange {
70 from: &'static str,
72 to: &'static str,
74 index: Option<usize>,
76 },
77 NonFinite {
79 to: &'static str,
81 index: Option<usize>,
83 },
84 PrecisionLoss {
86 to: &'static str,
88 index: Option<usize>,
90 },
91 NotIntegral {
93 to: &'static str,
95 index: Option<usize>,
97 },
98 MissingValue {
100 to: &'static str,
102 index: Option<usize>,
104 },
105 InvalidUtf8 {
107 index: Option<usize>,
109 },
110 Batched {
114 container: &'static str,
116 listed: Vec<StorageCoerceError>,
118 total: usize,
120 },
121}
122
123impl fmt::Display for StorageCoerceError {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 match self {
126 StorageCoerceError::Unsupported { from, to } => {
127 write!(f, "cannot convert {} to {}", from, to)
128 }
129 StorageCoerceError::OutOfRange { from, to, index } => {
130 if let Some(i) = index {
131 write!(f, "value at index {} out of range for {} → {}", i, from, to)
132 } else {
133 write!(f, "value out of range for {} → {}", from, to)
134 }
135 }
136 StorageCoerceError::NonFinite { to, index } => {
137 if let Some(i) = index {
138 write!(
139 f,
140 "non-finite value at index {} cannot convert to {}",
141 i, to
142 )
143 } else {
144 write!(f, "non-finite value cannot convert to {}", to)
145 }
146 }
147 StorageCoerceError::PrecisionLoss { to, index } => {
148 if let Some(i) = index {
149 write!(
150 f,
151 "value at index {} would lose precision converting to {}",
152 i, to
153 )
154 } else {
155 write!(f, "value would lose precision converting to {}", to)
156 }
157 }
158 StorageCoerceError::NotIntegral { to, index } => {
159 if let Some(i) = index {
160 write!(
161 f,
162 "non-integral value at index {} cannot convert to {}",
163 i, to
164 )
165 } else {
166 write!(f, "non-integral value cannot convert to {}", to)
167 }
168 }
169 StorageCoerceError::MissingValue { to, index } => {
170 if let Some(i) = index {
171 write!(f, "missing value at index {} cannot convert to {}", i, to)
172 } else {
173 write!(f, "missing value cannot convert to {}", to)
174 }
175 }
176 StorageCoerceError::InvalidUtf8 { index } => {
177 if let Some(i) = index {
178 write!(f, "invalid UTF-8 at index {}", i)
179 } else {
180 write!(f, "invalid UTF-8")
181 }
182 }
183 StorageCoerceError::Batched {
184 container,
185 listed,
186 total,
187 } => {
188 write!(f, "{} conversion failed: ", container)?;
189 for (i, e) in listed.iter().enumerate() {
190 if i > 0 {
191 write!(f, "; ")?;
192 }
193 write!(f, "{}", e)?;
194 }
195 if *total > listed.len() {
196 write!(f, "; and {} more", total - listed.len())?;
197 }
198 Ok(())
199 }
200 }
201 }
202}
203
204impl std::error::Error for StorageCoerceError {}
205
206impl StorageCoerceError {
207 #[inline]
209 pub fn at_index(self, idx: usize) -> Self {
210 match self {
211 StorageCoerceError::OutOfRange { from, to, .. } => StorageCoerceError::OutOfRange {
212 from,
213 to,
214 index: Some(idx),
215 },
216 StorageCoerceError::NonFinite { to, .. } => StorageCoerceError::NonFinite {
217 to,
218 index: Some(idx),
219 },
220 StorageCoerceError::PrecisionLoss { to, .. } => StorageCoerceError::PrecisionLoss {
221 to,
222 index: Some(idx),
223 },
224 StorageCoerceError::NotIntegral { to, .. } => StorageCoerceError::NotIntegral {
225 to,
226 index: Some(idx),
227 },
228 StorageCoerceError::MissingValue { to, .. } => StorageCoerceError::MissingValue {
229 to,
230 index: Some(idx),
231 },
232 StorageCoerceError::InvalidUtf8 { .. } => {
233 StorageCoerceError::InvalidUtf8 { index: Some(idx) }
234 }
235 batched @ StorageCoerceError::Batched { .. } => batched,
238 other => other,
239 }
240 }
241}
242pub trait IntoRAs<Target> {
274 fn into_r_as(self) -> Result<SEXP, StorageCoerceError>;
276}
277#[inline]
283fn try_coerce_scalar<T, R>(
284 value: T,
285 from: &'static str,
286 to: &'static str,
287) -> Result<R, StorageCoerceError>
288where
289 T: TryCoerce<R>,
290 T::Error: Into<CoerceErrorKind>,
291{
292 value
293 .try_coerce()
294 .map_err(|e| map_coerce_error(e.into(), from, to))
295}
296
297#[derive(Debug)]
299enum CoerceErrorKind {
300 Overflow,
301 PrecisionLoss,
302 NaN,
303 Infallible,
304}
305
306impl From<CoerceError> for CoerceErrorKind {
307 fn from(e: CoerceError) -> Self {
308 match e {
309 CoerceError::Overflow => CoerceErrorKind::Overflow,
310 CoerceError::PrecisionLoss => CoerceErrorKind::PrecisionLoss,
311 CoerceError::NaN => CoerceErrorKind::NaN,
312 CoerceError::Zero => CoerceErrorKind::Overflow, }
314 }
315}
316
317impl From<std::convert::Infallible> for CoerceErrorKind {
318 fn from(_: std::convert::Infallible) -> Self {
319 CoerceErrorKind::Infallible
320 }
321}
322
323fn map_coerce_error(
324 kind: CoerceErrorKind,
325 from: &'static str,
326 to: &'static str,
327) -> StorageCoerceError {
328 match kind {
329 CoerceErrorKind::Overflow => StorageCoerceError::OutOfRange {
330 from,
331 to,
332 index: None,
333 },
334 CoerceErrorKind::PrecisionLoss => StorageCoerceError::PrecisionLoss { to, index: None },
335 CoerceErrorKind::NaN => StorageCoerceError::NonFinite { to, index: None },
336 CoerceErrorKind::Infallible => unreachable!(),
337 }
338}
339macro_rules! impl_into_r_as_scalar {
344 ($target:ty, $target_name:literal; $from:ty, $from_name:literal) => {
345 impl IntoRAs<$target> for $from {
346 #[inline]
347 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
348 let v: $target = try_coerce_scalar(self, $from_name, $target_name)?;
349 Ok(v.into_sexp())
350 }
351 }
352 };
353}
354
355impl IntoRAs<i32> for i32 {
357 #[inline]
358 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
359 Ok(self.into_sexp())
360 }
361}
362
363impl_into_r_as_scalar!(i32, "i32"; i8, "i8");
365impl_into_r_as_scalar!(i32, "i32"; i16, "i16");
366impl_into_r_as_scalar!(i32, "i32"; u8, "u8");
367impl_into_r_as_scalar!(i32, "i32"; u16, "u16");
368
369impl_into_r_as_scalar!(i32, "i32"; i64, "i64");
371impl_into_r_as_scalar!(i32, "i32"; isize, "isize");
372impl_into_r_as_scalar!(i32, "i32"; u32, "u32");
373impl_into_r_as_scalar!(i32, "i32"; u64, "u64");
374impl_into_r_as_scalar!(i32, "i32"; usize, "usize");
375
376impl_into_r_as_scalar!(i32, "i32"; f32, "f32");
378impl_into_r_as_scalar!(i32, "i32"; f64, "f64");
379
380impl IntoRAs<i32> for bool {
382 #[inline]
383 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
384 Ok((self as i32).into_sexp())
385 }
386}
387impl IntoRAs<f64> for f64 {
393 #[inline]
394 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
395 if !self.is_finite() {
396 return Err(StorageCoerceError::NonFinite {
397 to: "f64",
398 index: None,
399 });
400 }
401 Ok(self.into_sexp())
402 }
403}
404
405impl IntoRAs<f64> for f32 {
407 #[inline]
408 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
409 if !self.is_finite() {
410 return Err(StorageCoerceError::NonFinite {
411 to: "f64",
412 index: None,
413 });
414 }
415 Ok((self as f64).into_sexp())
416 }
417}
418
419impl IntoRAs<f64> for i8 {
421 #[inline]
422 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
423 Ok((self as f64).into_sexp())
424 }
425}
426
427impl IntoRAs<f64> for i16 {
428 #[inline]
429 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
430 Ok((self as f64).into_sexp())
431 }
432}
433
434impl IntoRAs<f64> for i32 {
435 #[inline]
436 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
437 if self == crate::altrep_traits::NA_INTEGER {
441 return Err(StorageCoerceError::MissingValue {
442 to: "f64",
443 index: None,
444 });
445 }
446 Ok((self as f64).into_sexp())
447 }
448}
449
450impl IntoRAs<f64> for u8 {
451 #[inline]
452 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
453 Ok((self as f64).into_sexp())
454 }
455}
456
457impl IntoRAs<f64> for u16 {
458 #[inline]
459 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
460 Ok((self as f64).into_sexp())
461 }
462}
463
464impl IntoRAs<f64> for u32 {
465 #[inline]
466 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
467 Ok((self as f64).into_sexp())
468 }
469}
470
471impl_into_r_as_scalar!(f64, "f64"; i64, "i64");
473impl_into_r_as_scalar!(f64, "f64"; u64, "u64");
474impl_into_r_as_scalar!(f64, "f64"; isize, "isize");
475impl_into_r_as_scalar!(f64, "f64"; usize, "usize");
476
477impl IntoRAs<f64> for bool {
479 #[inline]
480 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
481 Ok((if self { 1.0 } else { 0.0 }).into_sexp())
482 }
483}
484impl IntoRAs<u8> for u8 {
490 #[inline]
491 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
492 Ok(self.into_sexp())
493 }
494}
495
496impl_into_r_as_scalar!(u8, "u8"; i8, "i8");
498impl_into_r_as_scalar!(u8, "u8"; i16, "i16");
499impl_into_r_as_scalar!(u8, "u8"; i32, "i32");
500impl_into_r_as_scalar!(u8, "u8"; i64, "i64");
501impl_into_r_as_scalar!(u8, "u8"; isize, "isize");
502impl_into_r_as_scalar!(u8, "u8"; u16, "u16");
503impl_into_r_as_scalar!(u8, "u8"; u32, "u32");
504impl_into_r_as_scalar!(u8, "u8"; u64, "u64");
505impl_into_r_as_scalar!(u8, "u8"; usize, "usize");
506impl_into_r_as_scalar!(u8, "u8"; f32, "f32");
507impl_into_r_as_scalar!(u8, "u8"; f64, "f64");
508impl IntoRAs<RLogical> for bool {
513 #[inline]
514 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
515 Ok(self.into_sexp())
516 }
517}
518
519impl IntoRAs<RLogical> for RLogical {
520 #[inline]
521 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
522 Ok(self.into_sexp())
523 }
524}
525
526impl IntoRAs<RLogical> for i32 {
528 #[inline]
529 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
530 match self {
531 0 => Ok(false.into_sexp()),
532 1 => Ok(true.into_sexp()),
533 crate::altrep_traits::NA_INTEGER => Ok(RLogical::NA.into_sexp()),
534 _ => Err(StorageCoerceError::OutOfRange {
535 from: "i32",
536 to: "RLogical",
537 index: None,
538 }),
539 }
540 }
541}
542impl IntoRAs<String> for String {
547 #[inline]
548 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
549 Ok(self.into_sexp())
550 }
551}
552
553impl IntoRAs<String> for &str {
554 #[inline]
555 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
556 Ok(self.into_sexp())
557 }
558}
559
560impl IntoRAs<String> for f64 {
562 #[inline]
563 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
564 let s = if self.is_nan() {
565 "NaN".to_string()
566 } else if self.is_infinite() {
567 if self.is_sign_positive() {
568 "Inf".to_string()
569 } else {
570 "-Inf".to_string()
571 }
572 } else {
573 self.to_string()
574 };
575 Ok(s.into_sexp())
576 }
577}
578
579impl IntoRAs<String> for f32 {
580 #[inline]
581 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
582 <f64 as IntoRAs<String>>::into_r_as(self as f64)
583 }
584}
585
586impl IntoRAs<String> for i32 {
587 #[inline]
588 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
589 Ok(self.to_string().into_sexp())
590 }
591}
592
593impl IntoRAs<String> for i64 {
594 #[inline]
595 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
596 Ok(self.to_string().into_sexp())
597 }
598}
599
600impl IntoRAs<String> for bool {
601 #[inline]
602 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
603 Ok((if self { "TRUE" } else { "FALSE" }).into_sexp())
604 }
605}
606
607impl IntoRAs<String> for RLogical {
608 #[inline]
609 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
610 let s = match self.to_option_bool() {
611 None => "NA",
612 Some(true) => "TRUE",
613 Some(false) => "FALSE",
614 };
615 Ok(s.into_sexp())
616 }
617}
618macro_rules! impl_vec_into_r_as {
623 ($target:ty, $target_name:literal; $from:ty, $from_name:literal) => {
624 impl IntoRAs<$target> for Vec<$from> {
625 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
626 let mut result = Vec::with_capacity(self.len());
627 let mut listed: Vec<StorageCoerceError> = Vec::new();
628 let mut total = 0usize;
629 for (i, val) in self.into_iter().enumerate() {
630 match try_coerce_scalar::<$from, $target>(val, $from_name, $target_name) {
631 Ok(v) => result.push(v),
632 Err(e) => {
633 if listed.len() < BATCHED_ERROR_CAP {
634 listed.push(e.at_index(i));
635 }
636 total += 1;
637 }
638 }
639 }
640 if total > 0 {
641 return Err(StorageCoerceError::Batched {
642 container: concat!("Vec<", $from_name, ">"),
643 listed,
644 total,
645 });
646 }
647 Ok(result.into_sexp())
648 }
649 }
650
651 impl IntoRAs<$target> for &[$from] {
652 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
653 let mut result = Vec::with_capacity(self.len());
654 let mut listed: Vec<StorageCoerceError> = Vec::new();
655 let mut total = 0usize;
656 for (i, &val) in self.iter().enumerate() {
657 match try_coerce_scalar::<$from, $target>(val, $from_name, $target_name) {
658 Ok(v) => result.push(v),
659 Err(e) => {
660 if listed.len() < BATCHED_ERROR_CAP {
661 listed.push(e.at_index(i));
662 }
663 total += 1;
664 }
665 }
666 }
667 if total > 0 {
668 return Err(StorageCoerceError::Batched {
669 container: concat!("&[", $from_name, "]"),
670 listed,
671 total,
672 });
673 }
674 Ok(result.into_sexp())
675 }
676 }
677 };
678}
679
680impl IntoRAs<i32> for Vec<i32> {
682 #[inline]
683 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
684 Ok(self.into_sexp())
685 }
686}
687
688impl IntoRAs<i32> for &[i32] {
689 #[inline]
690 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
691 Ok(self.into_sexp())
692 }
693}
694
695impl_vec_into_r_as!(i32, "i32"; i8, "i8");
696impl_vec_into_r_as!(i32, "i32"; i16, "i16");
697impl_vec_into_r_as!(i32, "i32"; u8, "u8");
698impl_vec_into_r_as!(i32, "i32"; u16, "u16");
699impl_vec_into_r_as!(i32, "i32"; i64, "i64");
700impl_vec_into_r_as!(i32, "i32"; isize, "isize");
701impl_vec_into_r_as!(i32, "i32"; u32, "u32");
702impl_vec_into_r_as!(i32, "i32"; u64, "u64");
703impl_vec_into_r_as!(i32, "i32"; usize, "usize");
704impl_vec_into_r_as!(i32, "i32"; f32, "f32");
705impl_vec_into_r_as!(i32, "i32"; f64, "f64");
706
707impl IntoRAs<i32> for Vec<bool> {
709 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
710 let result: Vec<i32> = self.into_iter().map(|b| b as i32).collect();
711 Ok(result.into_sexp())
712 }
713}
714
715impl IntoRAs<i32> for &[bool] {
716 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
717 let result: Vec<i32> = self.iter().map(|&b| b as i32).collect();
718 Ok(result.into_sexp())
719 }
720}
721impl IntoRAs<f64> for Vec<f64> {
727 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
728 let mut listed: Vec<StorageCoerceError> = Vec::new();
729 let mut total = 0usize;
730 for (i, &val) in self.iter().enumerate() {
731 if !val.is_finite() {
732 if listed.len() < BATCHED_ERROR_CAP {
733 listed.push(StorageCoerceError::NonFinite {
734 to: "f64",
735 index: Some(i),
736 });
737 }
738 total += 1;
739 }
740 }
741 if total > 0 {
742 return Err(StorageCoerceError::Batched {
743 container: "Vec<f64>",
744 listed,
745 total,
746 });
747 }
748 Ok(self.into_sexp())
749 }
750}
751
752impl IntoRAs<f64> for &[f64] {
753 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
754 let mut listed: Vec<StorageCoerceError> = Vec::new();
755 let mut total = 0usize;
756 for (i, &val) in self.iter().enumerate() {
757 if !val.is_finite() {
758 if listed.len() < BATCHED_ERROR_CAP {
759 listed.push(StorageCoerceError::NonFinite {
760 to: "f64",
761 index: Some(i),
762 });
763 }
764 total += 1;
765 }
766 }
767 if total > 0 {
768 return Err(StorageCoerceError::Batched {
769 container: "&[f64]",
770 listed,
771 total,
772 });
773 }
774 Ok(self.into_sexp())
775 }
776}
777
778impl IntoRAs<f64> for Vec<f32> {
780 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
781 let mut result = Vec::with_capacity(self.len());
782 let mut listed: Vec<StorageCoerceError> = Vec::new();
783 let mut total = 0usize;
784 for (i, val) in self.into_iter().enumerate() {
785 if !val.is_finite() {
786 if listed.len() < BATCHED_ERROR_CAP {
787 listed.push(StorageCoerceError::NonFinite {
788 to: "f64",
789 index: Some(i),
790 });
791 }
792 total += 1;
793 } else {
794 result.push(val as f64);
795 }
796 }
797 if total > 0 {
798 return Err(StorageCoerceError::Batched {
799 container: "Vec<f32>",
800 listed,
801 total,
802 });
803 }
804 Ok(result.into_sexp())
805 }
806}
807
808impl IntoRAs<f64> for &[f32] {
809 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
810 let mut result = Vec::with_capacity(self.len());
811 let mut listed: Vec<StorageCoerceError> = Vec::new();
812 let mut total = 0usize;
813 for (i, &val) in self.iter().enumerate() {
814 if !val.is_finite() {
815 if listed.len() < BATCHED_ERROR_CAP {
816 listed.push(StorageCoerceError::NonFinite {
817 to: "f64",
818 index: Some(i),
819 });
820 }
821 total += 1;
822 } else {
823 result.push(val as f64);
824 }
825 }
826 if total > 0 {
827 return Err(StorageCoerceError::Batched {
828 container: "&[f32]",
829 listed,
830 total,
831 });
832 }
833 Ok(result.into_sexp())
834 }
835}
836
837macro_rules! impl_vec_into_r_as_f64_infallible {
839 ($from:ty) => {
840 impl IntoRAs<f64> for Vec<$from> {
841 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
842 let result: Vec<f64> = self.into_iter().map(|v| v as f64).collect();
843 Ok(result.into_sexp())
844 }
845 }
846
847 impl IntoRAs<f64> for &[$from] {
848 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
849 let result: Vec<f64> = self.iter().map(|&v| v as f64).collect();
850 Ok(result.into_sexp())
851 }
852 }
853 };
854}
855
856impl_vec_into_r_as_f64_infallible!(i8);
857impl_vec_into_r_as_f64_infallible!(i16);
858impl_vec_into_r_as_f64_infallible!(u8);
859impl_vec_into_r_as_f64_infallible!(u16);
860impl_vec_into_r_as_f64_infallible!(u32);
861
862impl IntoRAs<f64> for Vec<i32> {
866 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
867 let mut result = Vec::with_capacity(self.len());
868 let mut listed: Vec<StorageCoerceError> = Vec::new();
869 let mut total = 0usize;
870 for (i, val) in self.into_iter().enumerate() {
871 if val == crate::altrep_traits::NA_INTEGER {
872 if listed.len() < BATCHED_ERROR_CAP {
873 listed.push(StorageCoerceError::MissingValue {
874 to: "f64",
875 index: Some(i),
876 });
877 }
878 total += 1;
879 } else {
880 result.push(val as f64);
881 }
882 }
883 if total > 0 {
884 return Err(StorageCoerceError::Batched {
885 container: "Vec<i32>",
886 listed,
887 total,
888 });
889 }
890 Ok(result.into_sexp())
891 }
892}
893
894impl IntoRAs<f64> for &[i32] {
895 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
896 let mut result = Vec::with_capacity(self.len());
897 let mut listed: Vec<StorageCoerceError> = Vec::new();
898 let mut total = 0usize;
899 for (i, &val) in self.iter().enumerate() {
900 if val == crate::altrep_traits::NA_INTEGER {
901 if listed.len() < BATCHED_ERROR_CAP {
902 listed.push(StorageCoerceError::MissingValue {
903 to: "f64",
904 index: Some(i),
905 });
906 }
907 total += 1;
908 } else {
909 result.push(val as f64);
910 }
911 }
912 if total > 0 {
913 return Err(StorageCoerceError::Batched {
914 container: "&[i32]",
915 listed,
916 total,
917 });
918 }
919 Ok(result.into_sexp())
920 }
921}
922
923impl_vec_into_r_as!(f64, "f64"; i64, "i64");
925impl_vec_into_r_as!(f64, "f64"; u64, "u64");
926impl_vec_into_r_as!(f64, "f64"; isize, "isize");
927impl_vec_into_r_as!(f64, "f64"; usize, "usize");
928
929impl IntoRAs<f64> for Vec<bool> {
931 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
932 let result: Vec<f64> = self
933 .into_iter()
934 .map(|b| if b { 1.0 } else { 0.0 })
935 .collect();
936 Ok(result.into_sexp())
937 }
938}
939
940impl IntoRAs<f64> for &[bool] {
941 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
942 let result: Vec<f64> = self.iter().map(|&b| if b { 1.0 } else { 0.0 }).collect();
943 Ok(result.into_sexp())
944 }
945}
946impl IntoRAs<u8> for Vec<u8> {
952 #[inline]
953 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
954 Ok(self.into_sexp())
955 }
956}
957
958impl IntoRAs<u8> for &[u8] {
959 #[inline]
960 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
961 Ok(self.into_sexp())
962 }
963}
964
965impl_vec_into_r_as!(u8, "u8"; i8, "i8");
966impl_vec_into_r_as!(u8, "u8"; i16, "i16");
967impl_vec_into_r_as!(u8, "u8"; i32, "i32");
968impl_vec_into_r_as!(u8, "u8"; i64, "i64");
969impl_vec_into_r_as!(u8, "u8"; isize, "isize");
970impl_vec_into_r_as!(u8, "u8"; u16, "u16");
971impl_vec_into_r_as!(u8, "u8"; u32, "u32");
972impl_vec_into_r_as!(u8, "u8"; u64, "u64");
973impl_vec_into_r_as!(u8, "u8"; usize, "usize");
974impl_vec_into_r_as!(u8, "u8"; f32, "f32");
975impl_vec_into_r_as!(u8, "u8"; f64, "f64");
976impl IntoRAs<RLogical> for Vec<bool> {
981 #[inline]
982 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
983 Ok(self.into_sexp())
984 }
985}
986
987impl IntoRAs<RLogical> for &[bool] {
988 #[inline]
989 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
990 Ok(self.into_sexp())
991 }
992}
993impl IntoRAs<String> for Vec<String> {
998 #[inline]
999 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1000 Ok(self.into_sexp())
1001 }
1002}
1003
1004impl IntoRAs<String> for &[String] {
1005 #[inline]
1006 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1007 Ok(self.into_sexp())
1008 }
1009}
1010
1011impl IntoRAs<String> for Vec<&str> {
1012 #[inline]
1013 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1014 Ok(self.into_sexp())
1015 }
1016}
1017
1018impl IntoRAs<String> for &[&str] {
1019 #[inline]
1020 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1021 Ok(self.into_sexp())
1022 }
1023}
1024
1025impl IntoRAs<String> for Vec<f64> {
1027 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1028 let strings: Vec<String> = self
1029 .into_iter()
1030 .map(|v| {
1031 if v.is_nan() {
1032 "NaN".to_string()
1033 } else if v.is_infinite() {
1034 if v.is_sign_positive() {
1035 "Inf".to_string()
1036 } else {
1037 "-Inf".to_string()
1038 }
1039 } else {
1040 v.to_string()
1041 }
1042 })
1043 .collect();
1044 Ok(strings.into_sexp())
1045 }
1046}
1047
1048impl IntoRAs<String> for Vec<i32> {
1049 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1050 let strings: Vec<String> = self.into_iter().map(|v| v.to_string()).collect();
1051 Ok(strings.into_sexp())
1052 }
1053}
1054
1055impl IntoRAs<String> for Vec<i64> {
1056 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1057 let strings: Vec<String> = self.into_iter().map(|v| v.to_string()).collect();
1058 Ok(strings.into_sexp())
1059 }
1060}
1061
1062impl IntoRAs<String> for Vec<bool> {
1063 fn into_r_as(self) -> Result<SEXP, StorageCoerceError> {
1064 let strings: Vec<String> = self
1065 .into_iter()
1066 .map(|b| if b { "TRUE" } else { "FALSE" }.to_string())
1067 .collect();
1068 Ok(strings.into_sexp())
1069 }
1070}
1071#[cfg(test)]
1076mod tests {
1077 use super::*;
1078
1079 fn _assert_into_r_as<T, Target>()
1083 where
1084 T: IntoRAs<Target>,
1085 {
1086 }
1087
1088 #[test]
1089 fn test_trait_bounds() {
1090 _assert_into_r_as::<i32, i32>();
1092 _assert_into_r_as::<i64, i32>();
1093 _assert_into_r_as::<f64, i32>();
1094 _assert_into_r_as::<bool, i32>();
1095
1096 _assert_into_r_as::<f64, f64>();
1098 _assert_into_r_as::<i32, f64>();
1099 _assert_into_r_as::<i64, f64>();
1100 _assert_into_r_as::<bool, f64>();
1101
1102 _assert_into_r_as::<u8, u8>();
1104 _assert_into_r_as::<i32, u8>();
1105
1106 _assert_into_r_as::<bool, RLogical>();
1108 _assert_into_r_as::<i32, RLogical>();
1109
1110 _assert_into_r_as::<String, String>();
1112 _assert_into_r_as::<&str, String>();
1113 _assert_into_r_as::<f64, String>();
1114 _assert_into_r_as::<i32, String>();
1115 _assert_into_r_as::<bool, String>();
1116
1117 _assert_into_r_as::<Vec<i32>, i32>();
1119 _assert_into_r_as::<Vec<i64>, i32>();
1120 _assert_into_r_as::<Vec<f64>, i32>();
1121
1122 _assert_into_r_as::<Vec<f64>, f64>();
1124 _assert_into_r_as::<Vec<i32>, f64>();
1125 _assert_into_r_as::<Vec<i64>, f64>();
1126
1127 _assert_into_r_as::<Vec<u8>, u8>();
1129 _assert_into_r_as::<Vec<i32>, u8>();
1130
1131 _assert_into_r_as::<Vec<String>, String>();
1133 _assert_into_r_as::<Vec<f64>, String>();
1134 }
1135
1136 #[test]
1143 fn batched_vec_i64_to_i32_lists_all_failing_indices() {
1144 let mut v = vec![0i64; 43];
1145 for &i in &[3usize, 17, 42] {
1146 v[i] = i64::MAX;
1147 }
1148 let result = IntoRAs::<i32>::into_r_as(v);
1149 match result {
1150 Err(StorageCoerceError::Batched {
1151 container,
1152 listed,
1153 total,
1154 }) => {
1155 assert_eq!(container, "Vec<i64>");
1156 assert_eq!(total, 3);
1157 assert_eq!(listed.len(), 3);
1158 let display = StorageCoerceError::Batched {
1159 container,
1160 listed,
1161 total,
1162 }
1163 .to_string();
1164 assert!(display.contains("index 3"), "{display}");
1165 assert!(display.contains("index 17"), "{display}");
1166 assert!(display.contains("index 42"), "{display}");
1167 }
1168 other => panic!("expected Batched, got {other:?}"),
1169 }
1170 }
1171
1172 #[test]
1175 fn batched_vec_i64_to_i32_caps_listed_and_summarizes_rest() {
1176 let v = vec![i64::MAX; 15];
1177 let result = IntoRAs::<i32>::into_r_as(v);
1178 match result {
1179 Err(e @ StorageCoerceError::Batched { .. }) => {
1180 if let StorageCoerceError::Batched { listed, total, .. } = &e {
1181 assert_eq!(*total, 15);
1182 assert_eq!(listed.len(), BATCHED_ERROR_CAP);
1183 }
1184 let display = e.to_string();
1185 assert!(display.contains("and 5 more"), "{display}");
1186 }
1187 other => panic!("expected Batched, got {other:?}"),
1188 }
1189 }
1190
1191 #[test]
1194 fn batched_slice_i64_to_i32_lists_all_failing_indices() {
1195 let mut v = vec![0i64; 6];
1196 v[1] = i64::MAX;
1197 v[4] = i64::MIN;
1198 let result = IntoRAs::<i32>::into_r_as(v.as_slice());
1199 match result {
1200 Err(e @ StorageCoerceError::Batched { .. }) => {
1201 if let StorageCoerceError::Batched {
1202 container,
1203 listed,
1204 total,
1205 } = &e
1206 {
1207 assert_eq!(*container, "&[i64]");
1208 assert_eq!(*total, 2);
1209 assert_eq!(listed.len(), 2);
1210 }
1211 let display = e.to_string();
1212 assert!(display.contains("&[i64] conversion failed"), "{display}");
1213 assert!(display.contains("index 1"), "{display}");
1214 assert!(display.contains("index 4"), "{display}");
1215 }
1216 other => panic!("expected Batched, got {other:?}"),
1217 }
1218 }
1219
1220 #[test]
1223 fn scalar_failure_display_unchanged() {
1224 let result = IntoRAs::<i32>::into_r_as(i64::MAX);
1225 match result {
1226 Err(e @ StorageCoerceError::OutOfRange { .. }) => {
1227 assert_eq!(e.to_string(), "value out of range for i64 → i32");
1228 }
1229 other => panic!("expected scalar OutOfRange, got {other:?}"),
1230 }
1231 }
1232}
1233