1use crate::altrep_traits::{NA_INTEGER, NA_LOGICAL, NA_REAL};
43use crate::{Rboolean, Rcomplex};
44
45pub trait Coerce<R> {
65 fn coerce(self) -> R;
69}
70
71pub trait TryCoerce<R> {
78 type Error;
80 fn try_coerce(self) -> Result<R, Self::Error>;
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum CoerceError {
87 Overflow,
89 PrecisionLoss,
91 NaN,
93 Zero,
95}
96
97impl std::fmt::Display for CoerceError {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 match self {
100 CoerceError::Overflow => write!(f, "value out of range"),
101 CoerceError::PrecisionLoss => write!(f, "precision loss"),
102 CoerceError::NaN => write!(f, "NaN cannot be converted"),
103 CoerceError::Zero => write!(f, "zero not allowed"),
104 }
105 }
106}
107
108impl std::error::Error for CoerceError {}
109
110impl<T, R> TryCoerce<R> for T
113where
114 T: Coerce<R>,
115{
116 type Error = std::convert::Infallible;
117
118 #[inline(always)]
119 fn try_coerce(self) -> Result<R, Self::Error> {
120 Ok(self.coerce())
121 }
122}
123macro_rules! impl_identity {
132 ($t:ty) => {
133 impl Coerce<$t> for $t {
134 #[inline(always)]
135 fn coerce(self) -> $t {
136 self
137 }
138 }
139 };
140}
141
142impl_identity!(i32);
143impl_identity!(f64);
144impl_identity!(Rboolean);
145impl_identity!(u8);
146impl_identity!(Rcomplex);
147macro_rules! impl_widen {
156 ($($from:ty => $to:ty),+ $(,)?) => {
157 $(
158 impl Coerce<$to> for $from {
159 #[inline(always)]
160 fn coerce(self) -> $to {
161 self.into()
162 }
163 }
164 )+
165 };
166}
167
168macro_rules! impl_try_narrow {
171 ($target:ty; $($from:ty),+ $(,)?) => {
172 $(
173 impl TryCoerce<$target> for $from {
174 type Error = CoerceError;
175 #[inline]
176 fn try_coerce(self) -> Result<$target, CoerceError> {
177 self.try_into().map_err(|_| CoerceError::Overflow)
178 }
179 }
180 )+
181 };
182}
183impl<T: crate::markers::WidensToI32> Coerce<i32> for T {
192 #[inline(always)]
193 fn coerce(self) -> i32 {
194 self.into()
195 }
196}
197
198impl<T: crate::markers::WidensToF64> Coerce<f64> for T {
203 #[inline(always)]
204 fn coerce(self) -> f64 {
205 self.into()
206 }
207}
208impl_widen!(u8 => i64, u8 => isize, u8 => u64, u8 => usize, u8 => f32);
213
214impl Coerce<f32> for i32 {
215 #[inline(always)]
216 fn coerce(self) -> f32 {
217 self as f32
218 }
219}
220impl Coerce<Rboolean> for bool {
225 #[inline(always)]
226 fn coerce(self) -> Rboolean {
227 if self {
228 Rboolean::TRUE
229 } else {
230 Rboolean::FALSE
231 }
232 }
233}
234
235impl Coerce<i32> for bool {
236 #[inline(always)]
237 fn coerce(self) -> i32 {
238 if self { 1 } else { 0 }
239 }
240}
241
242impl Coerce<f64> for bool {
243 #[inline(always)]
244 fn coerce(self) -> f64 {
245 if self { 1.0 } else { 0.0 }
246 }
247}
248
249impl Coerce<i32> for Rboolean {
250 #[inline(always)]
251 fn coerce(self) -> i32 {
252 self as i32
253 }
254}
255impl Coerce<f64> for Option<f64> {
261 #[inline(always)]
262 fn coerce(self) -> f64 {
263 self.unwrap_or(NA_REAL)
264 }
265}
266
267impl Coerce<i32> for Option<i32> {
269 #[inline(always)]
270 fn coerce(self) -> i32 {
271 self.unwrap_or(NA_INTEGER)
272 }
273}
274
275impl Coerce<i32> for Option<bool> {
277 #[inline(always)]
278 fn coerce(self) -> i32 {
279 match self {
280 Some(true) => 1,
281 Some(false) => 0,
282 None => NA_LOGICAL,
283 }
284 }
285}
286
287impl Coerce<i32> for Option<Rboolean> {
289 #[inline(always)]
290 fn coerce(self) -> i32 {
291 match self {
292 Some(v) => v as i32,
293 None => NA_LOGICAL,
294 }
295 }
296}
297impl Coerce<i64> for i32 {
303 #[inline(always)]
304 fn coerce(self) -> i64 {
305 self.into()
306 }
307}
308
309impl Coerce<isize> for i32 {
311 #[inline(always)]
312 fn coerce(self) -> isize {
313 self as isize
314 }
315}
316
317impl TryCoerce<u32> for i32 {
319 type Error = CoerceError;
320
321 #[inline]
322 fn try_coerce(self) -> Result<u32, CoerceError> {
323 self.try_into().map_err(|_| CoerceError::Overflow)
324 }
325}
326
327impl TryCoerce<u64> for i32 {
329 type Error = CoerceError;
330
331 #[inline]
332 fn try_coerce(self) -> Result<u64, CoerceError> {
333 self.try_into().map_err(|_| CoerceError::Overflow)
334 }
335}
336
337impl TryCoerce<usize> for i32 {
339 type Error = CoerceError;
340
341 #[inline]
342 fn try_coerce(self) -> Result<usize, CoerceError> {
343 self.try_into().map_err(|_| CoerceError::Overflow)
344 }
345}
346use core::num::{
351 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroIsize, NonZeroU8, NonZeroU16, NonZeroU32,
352 NonZeroU64, NonZeroUsize,
353};
354
355macro_rules! impl_nonzero_from_self {
356 ($base:ty, $nz:ty) => {
357 impl TryCoerce<$nz> for $base {
358 type Error = CoerceError;
359
360 #[inline]
361 fn try_coerce(self) -> Result<$nz, CoerceError> {
362 <$nz>::new(self).ok_or(CoerceError::Zero)
363 }
364 }
365 };
366}
367
368impl_nonzero_from_self!(i8, NonZeroI8);
370impl_nonzero_from_self!(i16, NonZeroI16);
371impl_nonzero_from_self!(i32, NonZeroI32);
372impl_nonzero_from_self!(i64, NonZeroI64);
373impl_nonzero_from_self!(isize, NonZeroIsize);
374impl_nonzero_from_self!(u8, NonZeroU8);
375impl_nonzero_from_self!(u16, NonZeroU16);
376impl_nonzero_from_self!(u32, NonZeroU32);
377impl_nonzero_from_self!(u64, NonZeroU64);
378impl_nonzero_from_self!(usize, NonZeroUsize);
379
380impl TryCoerce<NonZeroI64> for i32 {
382 type Error = CoerceError;
383
384 #[inline]
385 fn try_coerce(self) -> Result<NonZeroI64, CoerceError> {
386 NonZeroI64::new(self.into()).ok_or(CoerceError::Zero)
387 }
388}
389
390impl TryCoerce<NonZeroIsize> for i32 {
392 type Error = CoerceError;
393
394 #[inline]
395 fn try_coerce(self) -> Result<NonZeroIsize, CoerceError> {
396 NonZeroIsize::new(self as isize).ok_or(CoerceError::Zero)
397 }
398}
399
400impl TryCoerce<NonZeroU32> for i32 {
402 type Error = CoerceError;
403
404 #[inline]
405 fn try_coerce(self) -> Result<NonZeroU32, CoerceError> {
406 let u: u32 = self.try_into().map_err(|_| CoerceError::Overflow)?;
407 NonZeroU32::new(u).ok_or(CoerceError::Zero)
408 }
409}
410
411impl TryCoerce<NonZeroU64> for i32 {
413 type Error = CoerceError;
414
415 #[inline]
416 fn try_coerce(self) -> Result<NonZeroU64, CoerceError> {
417 let u: u64 = self.try_into().map_err(|_| CoerceError::Overflow)?;
418 NonZeroU64::new(u).ok_or(CoerceError::Zero)
419 }
420}
421
422impl TryCoerce<NonZeroUsize> for i32 {
424 type Error = CoerceError;
425
426 #[inline]
427 fn try_coerce(self) -> Result<NonZeroUsize, CoerceError> {
428 let u: usize = self.try_into().map_err(|_| CoerceError::Overflow)?;
429 NonZeroUsize::new(u).ok_or(CoerceError::Zero)
430 }
431}
432
433impl TryCoerce<NonZeroI8> for i32 {
435 type Error = CoerceError;
436
437 #[inline]
438 fn try_coerce(self) -> Result<NonZeroI8, CoerceError> {
439 let n: i8 = self.try_into().map_err(|_| CoerceError::Overflow)?;
440 NonZeroI8::new(n).ok_or(CoerceError::Zero)
441 }
442}
443
444impl TryCoerce<NonZeroI16> for i32 {
446 type Error = CoerceError;
447
448 #[inline]
449 fn try_coerce(self) -> Result<NonZeroI16, CoerceError> {
450 let n: i16 = self.try_into().map_err(|_| CoerceError::Overflow)?;
451 NonZeroI16::new(n).ok_or(CoerceError::Zero)
452 }
453}
454
455impl TryCoerce<NonZeroU8> for i32 {
457 type Error = CoerceError;
458
459 #[inline]
460 fn try_coerce(self) -> Result<NonZeroU8, CoerceError> {
461 let u: u8 = self.try_into().map_err(|_| CoerceError::Overflow)?;
462 NonZeroU8::new(u).ok_or(CoerceError::Zero)
463 }
464}
465
466impl TryCoerce<NonZeroU16> for i32 {
468 type Error = CoerceError;
469
470 #[inline]
471 fn try_coerce(self) -> Result<NonZeroU16, CoerceError> {
472 let u: u16 = self.try_into().map_err(|_| CoerceError::Overflow)?;
473 NonZeroU16::new(u).ok_or(CoerceError::Zero)
474 }
475}
476#[derive(Debug, Clone, Copy, PartialEq, Eq)]
482pub enum LogicalCoerceError {
483 NAValue,
485 InvalidValue(i32),
487}
488
489impl std::fmt::Display for LogicalCoerceError {
490 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491 match self {
492 LogicalCoerceError::NAValue => write!(f, "NA cannot be converted to bool"),
493 LogicalCoerceError::InvalidValue(v) => write!(f, "invalid logical value: {}", v),
494 }
495 }
496}
497
498impl std::error::Error for LogicalCoerceError {}
499
500impl TryCoerce<bool> for i32 {
501 type Error = LogicalCoerceError;
502
503 #[inline]
504 fn try_coerce(self) -> Result<bool, LogicalCoerceError> {
505 match self {
506 0 => Ok(false),
507 1 => Ok(true),
508 i32::MIN => Err(LogicalCoerceError::NAValue),
510 other => Err(LogicalCoerceError::InvalidValue(other)),
511 }
512 }
513}
514
515impl TryCoerce<bool> for Rboolean {
516 type Error = LogicalCoerceError;
517
518 #[inline]
519 fn try_coerce(self) -> Result<bool, LogicalCoerceError> {
520 (self as i32).try_coerce()
521 }
522}
523
524impl TryCoerce<bool> for crate::RLogical {
525 type Error = LogicalCoerceError;
526
527 #[inline]
528 fn try_coerce(self) -> Result<bool, LogicalCoerceError> {
529 self.to_i32().try_coerce()
530 }
531}
532impl_try_narrow!(i32; u32, u64, usize, i64, isize);
537impl_try_narrow!(u8; i8, i16, i32, i64, u16, u32, u64, usize, isize);
542impl_widen!(u8 => u16, i8 => i16, u8 => i16, u8 => u32, u16 => u32);
547impl_try_narrow!(u16; i8, i16, i32, i64, u32, u64, usize, isize);
552impl_try_narrow!(i16; i32, i64, u16, u32, u64, usize, isize);
557impl_try_narrow!(i8; i16, i32, i64, u8, u16, u32, u64, usize, isize);
562impl TryCoerce<u16> for f64 {
567 type Error = CoerceError;
568
569 #[inline]
570 fn try_coerce(self) -> Result<u16, CoerceError> {
571 if self.is_nan() {
572 return Err(CoerceError::NaN);
573 }
574 if self.is_infinite() {
575 return Err(CoerceError::Overflow);
576 }
577 if self < 0.0 || self > u16::MAX as f64 {
578 return Err(CoerceError::Overflow);
579 }
580 if self.fract() != 0.0 {
581 return Err(CoerceError::PrecisionLoss);
582 }
583 Ok(self as u16)
584 }
585}
586
587impl TryCoerce<i16> for f64 {
588 type Error = CoerceError;
589
590 #[inline]
591 fn try_coerce(self) -> Result<i16, CoerceError> {
592 if self.is_nan() {
593 return Err(CoerceError::NaN);
594 }
595 if self.is_infinite() {
596 return Err(CoerceError::Overflow);
597 }
598 if self < i16::MIN as f64 || self > i16::MAX as f64 {
599 return Err(CoerceError::Overflow);
600 }
601 if self.fract() != 0.0 {
602 return Err(CoerceError::PrecisionLoss);
603 }
604 Ok(self as i16)
605 }
606}
607
608impl TryCoerce<i8> for f64 {
609 type Error = CoerceError;
610
611 #[inline]
612 fn try_coerce(self) -> Result<i8, CoerceError> {
613 if self.is_nan() {
614 return Err(CoerceError::NaN);
615 }
616 if self.is_infinite() {
617 return Err(CoerceError::Overflow);
618 }
619 if self < i8::MIN as f64 || self > i8::MAX as f64 {
620 return Err(CoerceError::Overflow);
621 }
622 if self.fract() != 0.0 {
623 return Err(CoerceError::PrecisionLoss);
624 }
625 Ok(self as i8)
626 }
627}
628impl TryCoerce<i32> for f64 {
633 type Error = CoerceError;
634
635 #[inline]
636 fn try_coerce(self) -> Result<i32, CoerceError> {
637 if self.is_nan() {
638 return Err(CoerceError::NaN);
639 }
640 if self.is_infinite() {
641 return Err(CoerceError::Overflow);
642 }
643 if self < i32::MIN as f64 || self > i32::MAX as f64 {
644 return Err(CoerceError::Overflow);
645 }
646 if self.fract() != 0.0 {
647 return Err(CoerceError::PrecisionLoss);
648 }
649 Ok(self as i32)
650 }
651}
652
653impl TryCoerce<i32> for f32 {
654 type Error = CoerceError;
655
656 #[inline]
657 fn try_coerce(self) -> Result<i32, CoerceError> {
658 f64::from(self).try_coerce()
659 }
660}
661
662impl Coerce<f32> for f64 {
664 #[inline(always)]
665 fn coerce(self) -> f32 {
666 self as f32
667 }
668}
669impl TryCoerce<u8> for f64 {
674 type Error = CoerceError;
675
676 #[inline]
677 fn try_coerce(self) -> Result<u8, CoerceError> {
678 if self.is_nan() {
679 return Err(CoerceError::NaN);
680 }
681 if self.is_infinite() {
682 return Err(CoerceError::Overflow);
683 }
684 if self < 0.0 || self > u8::MAX as f64 {
685 return Err(CoerceError::Overflow);
686 }
687 if self.fract() != 0.0 {
688 return Err(CoerceError::PrecisionLoss);
689 }
690 Ok(self as u8)
691 }
692}
693
694impl TryCoerce<u8> for f32 {
695 type Error = CoerceError;
696
697 #[inline]
698 fn try_coerce(self) -> Result<u8, CoerceError> {
699 f64::from(self).try_coerce()
700 }
701}
702impl TryCoerce<u32> for f64 {
707 type Error = CoerceError;
708
709 #[inline]
710 fn try_coerce(self) -> Result<u32, CoerceError> {
711 if self.is_nan() {
712 return Err(CoerceError::NaN);
713 }
714 if self.is_infinite() {
715 return Err(CoerceError::Overflow);
716 }
717 if self < 0.0 || self > u32::MAX as f64 {
718 return Err(CoerceError::Overflow);
719 }
720 if self.fract() != 0.0 {
721 return Err(CoerceError::PrecisionLoss);
722 }
723 Ok(self as u32)
724 }
725}
726impl TryCoerce<i64> for f64 {
747 type Error = CoerceError;
748
749 #[inline]
750 fn try_coerce(self) -> Result<i64, CoerceError> {
751 if self.is_nan() {
752 return Err(CoerceError::NaN);
753 }
754 if self.is_infinite() {
755 return Err(CoerceError::Overflow);
756 }
757 if self < i64::MIN as f64 || self >= i64::MAX as f64 {
759 return Err(CoerceError::Overflow);
760 }
761 if self.fract() != 0.0 {
762 return Err(CoerceError::PrecisionLoss);
763 }
764 Ok(self as i64)
765 }
766}
767
768impl TryCoerce<u64> for f64 {
769 type Error = CoerceError;
770
771 #[inline]
772 fn try_coerce(self) -> Result<u64, CoerceError> {
773 if self.is_nan() {
774 return Err(CoerceError::NaN);
775 }
776 if self.is_infinite() {
777 return Err(CoerceError::Overflow);
778 }
779 if self < 0.0 || self >= u64::MAX as f64 {
780 return Err(CoerceError::Overflow);
781 }
782 if self.fract() != 0.0 {
783 return Err(CoerceError::PrecisionLoss);
784 }
785 Ok(self as u64)
786 }
787}
788
789impl TryCoerce<isize> for f64 {
790 type Error = CoerceError;
791
792 #[inline]
793 fn try_coerce(self) -> Result<isize, CoerceError> {
794 if self.is_nan() {
795 return Err(CoerceError::NaN);
796 }
797 if self.is_infinite() {
798 return Err(CoerceError::Overflow);
799 }
800 if self < isize::MIN as f64 || self >= isize::MAX as f64 {
802 return Err(CoerceError::Overflow);
803 }
804 if self.fract() != 0.0 {
805 return Err(CoerceError::PrecisionLoss);
806 }
807 Ok(self as isize)
808 }
809}
810
811impl TryCoerce<usize> for f64 {
812 type Error = CoerceError;
813
814 #[inline]
815 fn try_coerce(self) -> Result<usize, CoerceError> {
816 if self.is_nan() {
817 return Err(CoerceError::NaN);
818 }
819 if self.is_infinite() {
820 return Err(CoerceError::Overflow);
821 }
822 if self < 0.0 || self >= usize::MAX as f64 {
824 return Err(CoerceError::Overflow);
825 }
826 if self.fract() != 0.0 {
827 return Err(CoerceError::PrecisionLoss);
828 }
829 Ok(self as usize)
830 }
831}
832impl TryCoerce<f64> for i64 {
853 type Error = CoerceError;
854
855 #[inline]
856 fn try_coerce(self) -> Result<f64, CoerceError> {
857 const MAX_SAFE: i64 = 1 << 53;
858 const MIN_SAFE: i64 = -(1 << 53);
859 if !(MIN_SAFE..=MAX_SAFE).contains(&self) {
860 return Err(CoerceError::PrecisionLoss);
861 }
862 Ok(self as f64)
863 }
864}
865
866impl TryCoerce<f64> for u64 {
870 type Error = CoerceError;
871
872 #[inline]
873 fn try_coerce(self) -> Result<f64, CoerceError> {
874 const MAX_SAFE: u64 = 1 << 53;
875 if self > MAX_SAFE {
876 return Err(CoerceError::PrecisionLoss);
877 }
878 Ok(self as f64)
879 }
880}
881
882impl TryCoerce<f64> for isize {
883 type Error = CoerceError;
884 #[inline]
885 fn try_coerce(self) -> Result<f64, CoerceError> {
886 (self as i64).try_coerce()
887 }
888}
889
890impl TryCoerce<f64> for usize {
891 type Error = CoerceError;
892 #[inline]
893 fn try_coerce(self) -> Result<f64, CoerceError> {
894 (self as u64).try_coerce()
895 }
896}
897use std::marker::PhantomData;
902
903#[repr(transparent)]
919#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
920pub struct Coerced<T, R> {
921 value: T,
922 _marker: PhantomData<R>,
923}
924
925impl<T, R> Coerced<T, R> {
926 #[inline]
928 pub const fn new(value: T) -> Self {
929 Self {
930 value,
931 _marker: PhantomData,
932 }
933 }
934
935 #[inline]
937 pub fn into_inner(self) -> T {
938 self.value
939 }
940
941 #[inline]
943 pub const fn as_inner(&self) -> &T {
944 &self.value
945 }
946
947 #[inline]
949 pub fn as_inner_mut(&mut self) -> &mut T {
950 &mut self.value
951 }
952}
953
954impl<T, R> std::ops::Deref for Coerced<T, R> {
955 type Target = T;
956
957 #[inline]
958 fn deref(&self) -> &Self::Target {
959 &self.value
960 }
961}
962
963impl<T, R> std::ops::DerefMut for Coerced<T, R> {
964 #[inline]
965 fn deref_mut(&mut self) -> &mut Self::Target {
966 &mut self.value
967 }
968}
969impl<T: Copy + Coerce<R>, R> Coerce<Vec<R>> for &[T] {
975 #[inline]
976 fn coerce(self) -> Vec<R> {
977 self.iter().copied().map(Coerce::coerce).collect()
978 }
979}
980
981impl<T: Coerce<R>, R> Coerce<Vec<R>> for Vec<T> {
983 #[inline]
984 fn coerce(self) -> Vec<R> {
985 self.into_iter().map(Coerce::coerce).collect()
986 }
987}
988
989impl<T: Coerce<R>, R> Coerce<Box<[R]>> for Box<[T]> {
991 #[inline]
992 fn coerce(self) -> Box<[R]> {
993 Vec::from(self).into_iter().map(Coerce::coerce).collect()
994 }
995}
996
997impl<T: Coerce<R>, R> Coerce<std::collections::VecDeque<R>> for std::collections::VecDeque<T> {
999 fn coerce(self) -> std::collections::VecDeque<R> {
1000 self.into_iter().map(Coerce::coerce).collect()
1001 }
1002}
1003
1004#[cfg(feature = "tinyvec")]
1013impl<T, R, const N: usize> Coerce<tinyvec::TinyVec<[R; N]>> for tinyvec::TinyVec<[T; N]>
1017where
1018 T: Coerce<R>,
1019 [T; N]: tinyvec::Array<Item = T>,
1020 [R; N]: tinyvec::Array<Item = R>,
1021{
1022 fn coerce(self) -> tinyvec::TinyVec<[R; N]> {
1023 self.into_iter().map(Coerce::coerce).collect()
1024 }
1025}
1026
1027#[cfg(feature = "tinyvec")]
1028impl<T, R, const N: usize> Coerce<tinyvec::ArrayVec<[R; N]>> for tinyvec::ArrayVec<[T; N]>
1032where
1033 T: Coerce<R>,
1034 [T; N]: tinyvec::Array<Item = T>,
1035 [R; N]: tinyvec::Array<Item = R>,
1036{
1037 fn coerce(self) -> tinyvec::ArrayVec<[R; N]> {
1038 self.into_iter().map(Coerce::coerce).collect()
1039 }
1040}
1041macro_rules! impl_tuple_coerce {
1047 (($($T:ident),+), ($($R:ident),+), ($($idx:tt),+)) => {
1048 impl<$($T,)+ $($R,)+> Coerce<($($R,)+)> for ($($T,)+)
1049 where
1050 $($T: Coerce<$R>,)+
1051 {
1052 #[inline]
1053 fn coerce(self) -> ($($R,)+) {
1054 ($(Coerce::<$R>::coerce(self.$idx),)+)
1055 }
1056 }
1057 };
1058}
1059
1060impl_tuple_coerce!((A, B), (RA, RB), (0, 1));
1062impl_tuple_coerce!((A, B, C), (RA, RB, RC), (0, 1, 2));
1063impl_tuple_coerce!((A, B, C, D), (RA, RB, RC, RD), (0, 1, 2, 3));
1064impl_tuple_coerce!((A, B, C, D, E), (RA, RB, RC, RD, RE), (0, 1, 2, 3, 4));
1065impl_tuple_coerce!(
1066 (A, B, C, D, E, F),
1067 (RA, RB, RC, RD, RE, RF),
1068 (0, 1, 2, 3, 4, 5)
1069);
1070impl_tuple_coerce!(
1071 (A, B, C, D, E, F, G),
1072 (RA, RB, RC, RD, RE, RF, RG),
1073 (0, 1, 2, 3, 4, 5, 6)
1074);
1075impl_tuple_coerce!(
1076 (A, B, C, D, E, F, G, H),
1077 (RA, RB, RC, RD, RE, RF, RG, RH),
1078 (0, 1, 2, 3, 4, 5, 6, 7)
1079);
1080#[cfg(test)]
1085mod tests;
1086