1use crate::from_r::{SexpError, SexpLengthError, SexpTypeError, TryFromSexp};
88use crate::into_r::IntoR;
89use crate::{R_xlen_t, RNativeType, SEXP, SEXPTYPE, SexpExt};
90use core::marker::PhantomData;
91
92pub type RVector<T> = RArray<T, 1>;
96
97pub type RMatrix<T> = RArray<T, 2>;
99
100pub type RArray3D<T> = RArray<T, 3>;
102#[derive(#[automatically_derived]
impl<T: ::core::clone::Clone, const NDIM : usize> ::core::clone::Clone for
RArray<T, NDIM> {
#[inline]
fn clone(&self) -> Self {
RArray {
sexp: ::core::clone::Clone::clone(&self.sexp),
_marker: ::core::clone::Clone::clone(&self._marker),
}
}
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy, const NDIM : usize> ::core::marker::Copy for
RArray<T, NDIM> {
}Copy)]
121#[repr(transparent)]
122pub struct RArray<T, const NDIM: usize> {
123 sexp: SEXP,
124 _marker: PhantomData<*const T>,
126}
127impl<T, const NDIM: usize> RArray<T, NDIM> {
132 #[inline]
140 pub const unsafe fn from_sexp_unchecked(sexp: SEXP) -> Self {
141 Self {
142 sexp,
143 _marker: PhantomData,
144 }
145 }
146
147 #[inline]
149 pub const fn as_sexp(&self) -> SEXP {
150 self.sexp
151 }
152
153 #[inline]
155 pub fn into_inner(self) -> SEXP {
156 self.sexp
157 }
158
159 #[inline]
165 pub unsafe fn dims(&self) -> [usize; NDIM] {
166 unsafe { get_dims::<NDIM>(self.sexp) }
167 }
168
169 #[inline]
179 pub unsafe fn dim(&self, dim: usize) -> usize {
180 if !(dim < NDIM) {
{
::core::panicking::panic_fmt(format_args!("dimension index out of bounds"));
}
};assert!(dim < NDIM, "dimension index out of bounds");
181 unsafe { self.dims()[dim] }
182 }
183
184 #[inline]
186 pub fn len(&self) -> usize {
187 self.sexp.len()
188 }
189
190 #[inline]
192 pub fn is_empty(&self) -> bool {
193 self.len() == 0
194 }
195
196 #[inline]
206 pub unsafe fn linear_index(&self, indices: [usize; NDIM]) -> usize {
207 let dims = unsafe { self.dims() };
208 let mut linear = 0;
209 let mut stride = 1;
210 for i in 0..NDIM {
211 if !(indices[i] < dims[i]) {
{
::core::panicking::panic_fmt(format_args!("index {0} out of bounds for dimension {1} (size {2})",
indices[i], i, dims[i]));
}
};assert!(
212 indices[i] < dims[i],
213 "index {} out of bounds for dimension {} (size {})",
214 indices[i],
215 i,
216 dims[i]
217 );
218 linear += indices[i] * stride;
219 stride *= dims[i];
220 }
221 linear
222 }
223}
224impl<T: RNativeType, const NDIM: usize> RArray<T, NDIM> {
229 #[inline]
241 pub unsafe fn from_sexp(sexp: SEXP) -> Result<Self, SexpError> {
242 let actual = sexp.type_of();
244 if actual != T::SEXP_TYPE {
245 return Err(SexpTypeError {
246 expected: T::SEXP_TYPE,
247 actual,
248 }
249 .into());
250 }
251
252 let ndim = get_ndim(sexp);
254 if ndim != NDIM {
255 return Err(SexpLengthError {
256 expected: NDIM,
257 actual: ndim,
258 }
259 .into());
260 }
261
262 Ok(Self {
263 sexp,
264 _marker: PhantomData,
265 })
266 }
267
268 #[inline]
274 pub unsafe fn as_slice(&self) -> &[T] {
275 unsafe { self.sexp.as_slice() }
276 }
277
278 #[inline]
285 pub unsafe fn as_slice_mut(&mut self) -> &mut [T] {
286 unsafe {
287 let ptr = T::dataptr_mut(self.sexp);
288 crate::from_r::r_slice_mut(ptr, self.len())
289 }
290 }
291
292 #[inline]
316 pub unsafe fn to_vec(&self) -> Vec<T>
317 where
318 T: Copy,
319 {
320 unsafe { self.as_slice().to_vec() }
321 }
322
323 #[inline]
333 pub unsafe fn get(&self, indices: [usize; NDIM]) -> T
334 where
335 T: Copy,
336 {
337 let idx = unsafe { self.linear_index(indices) };
338 unsafe { *self.as_slice().get_unchecked(idx) }
339 }
340
341 #[inline]
352 pub unsafe fn set(&mut self, indices: [usize; NDIM], value: T)
353 where
354 T: Copy,
355 {
356 let idx = unsafe { self.linear_index(indices) };
357 unsafe {
358 *self.as_slice_mut().get_unchecked_mut(idx) = value;
359 }
360 }
361}
362impl<T: RNativeType> RMatrix<T> {
367 #[inline]
373 pub unsafe fn nrow(&self) -> usize {
374 unsafe { self.dim(0) }
375 }
376
377 #[inline]
383 pub unsafe fn ncol(&self) -> usize {
384 unsafe { self.dim(1) }
385 }
386
387 #[inline]
393 pub unsafe fn get_rc(&self, row: usize, col: usize) -> T
394 where
395 T: Copy,
396 {
397 unsafe { self.get([row, col]) }
398 }
399
400 #[inline]
407 pub unsafe fn set_rc(&mut self, row: usize, col: usize, value: T)
408 where
409 T: Copy,
410 {
411 unsafe { self.set([row, col], value) }
412 }
413
414 #[inline]
420 pub unsafe fn column(&self, col: usize) -> &[T] {
421 let nrow = unsafe { self.nrow() };
422 let ncol = unsafe { self.ncol() };
423 if !(col < ncol) {
{
::core::panicking::panic_fmt(format_args!("column index out of bounds"));
}
};assert!(col < ncol, "column index out of bounds");
424 let start = col * nrow;
425 unsafe { &self.as_slice()[start..start + nrow] }
426 }
427
428 #[inline]
441 pub unsafe fn column_mut(&mut self, col: usize) -> &mut [T] {
442 let nrow = unsafe { self.nrow() };
443 let ncol = unsafe { self.ncol() };
444 if !(col < ncol) {
{
::core::panicking::panic_fmt(format_args!("column index out of bounds"));
}
};assert!(col < ncol, "column index out of bounds");
445 let start = col * nrow;
446 unsafe { &mut self.as_slice_mut()[start..start + nrow] }
447 }
448}
449impl<T: RNativeType, const NDIM: usize> RArray<T, NDIM> {
454 #[inline]
463 fn get_attr_opt(&self, name: SEXP) -> Option<SEXP> {
464 let attr = self.sexp.get_attr(name);
465 if attr.is_nil() { None } else { Some(attr) }
466 }
467
468 #[inline]
476 pub unsafe fn get_names(&self) -> Option<SEXP> {
477 self.get_attr_opt(SEXP::names_symbol())
479 }
480
481 #[inline]
489 pub unsafe fn get_class(&self) -> Option<SEXP> {
490 self.get_attr_opt(SEXP::class_symbol())
492 }
493
494 #[inline]
502 pub unsafe fn get_dimnames(&self) -> Option<SEXP> {
503 self.get_attr_opt(SEXP::dimnames_symbol())
505 }
506
507 #[inline]
515 pub unsafe fn get_rownames(&self) -> Option<SEXP> {
516 unsafe {
517 let rownames = sys::Rf_GetRowNames(self.sexp);
518 if rownames.is_nil() {
519 None
520 } else {
521 Some(rownames)
522 }
523 }
524 }
525
526 #[inline]
534 pub unsafe fn get_colnames(&self) -> Option<SEXP> {
535 unsafe {
536 let dimnames = self.sexp.get_dimnames();
537 if dimnames.is_nil() {
538 return None;
539 }
540 let colnames = sys::Rf_GetColNames(dimnames);
541 if colnames.is_nil() {
542 None
543 } else {
544 Some(colnames)
545 }
546 }
547 }
548 #[inline]
564 pub unsafe fn set_names(&mut self, names: SEXP) {
565 self.sexp.set_names(names);
566 }
567
568 #[inline]
576 pub unsafe fn set_class(&mut self, class: SEXP) {
577 self.sexp.set_class(class);
578 }
579
580 #[inline]
588 pub unsafe fn set_dimnames(&mut self, dimnames: SEXP) {
589 self.sexp.set_dimnames(dimnames);
590 }
591 }
593impl<T: RNativeType, const NDIM: usize> RArray<T, NDIM> {
598 pub unsafe fn new<F>(dims: [usize; NDIM], init: F) -> Self
620 where
621 F: FnOnce(&mut [T]),
622 {
623 let total_len: usize = dims
624 .iter()
625 .try_fold(1usize, |acc, &d| acc.checked_mul(d))
626 .expect("array total length overflows usize");
627
628 if !(total_len <= R_xlen_t::MAX as usize) {
{
::core::panicking::panic_fmt(format_args!("array total length {0} exceeds R_xlen_t::MAX",
total_len));
}
};assert!(
629 total_len <= R_xlen_t::MAX as usize,
630 "array total length {total_len} exceeds R_xlen_t::MAX"
631 );
632
633 let sexp = unsafe { sys::Rf_allocVector(T::SEXP_TYPE, total_len as R_xlen_t) };
635
636 unsafe { set_dims::<NDIM>(sexp, &dims) };
638
639 let ptr = unsafe { T::dataptr_mut(sexp) };
641 let slice = unsafe { crate::from_r::r_slice_mut(ptr, total_len) };
642 init(slice);
643
644 Self {
645 sexp,
646 _marker: PhantomData,
647 }
648 }
649
650 pub unsafe fn zeros(dims: [usize; NDIM]) -> Self
657 where
658 T: Default + Copy,
659 {
660 unsafe {
661 Self::new(dims, |slice| {
662 slice.fill(T::default());
663 })
664 }
665 }
666}
667impl<T: RNativeType, const NDIM: usize> TryFromSexp for RArray<T, NDIM> {
672 type Error = SexpError;
673
674 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
675 unsafe { Self::from_sexp(sexp) }
676 }
677
678 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
679 unsafe { Self::from_sexp(sexp) }
680 }
681}
682use crate::RLogical;
691use crate::coerce::TryCoerce;
692use crate::sys::{self};
693
694fn validate_coercion<S, T>(slice: &[S]) -> Result<(), SexpError>
696where
697 S: Copy + TryCoerce<T>,
698 <S as TryCoerce<T>>::Error: std::fmt::Debug,
699{
700 for &val in slice {
701 val.try_coerce()
702 .map_err(|e| SexpError::InvalidValue(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", e))
})format!("{e:?}")))?;
703 }
704 Ok(())
705}
706
707macro_rules! impl_rarray_try_from_sexp_coerce {
711 ($source:ty => $target:ty) => {
712 impl<const NDIM: usize> TryFromSexp for RArray<$target, NDIM> {
713 type Error = SexpError;
714
715 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
716 let actual = sexp.type_of();
718 if actual != <$source as RNativeType>::SEXP_TYPE {
719 return Err(SexpTypeError {
720 expected: <$source as RNativeType>::SEXP_TYPE,
721 actual,
722 }
723 .into());
724 }
725
726 let ndim = get_ndim(sexp);
728 if ndim != NDIM {
729 return Err(SexpLengthError {
730 expected: NDIM,
731 actual: ndim,
732 }
733 .into());
734 }
735
736 let slice: &[$source] = unsafe { sexp.as_slice() };
738 validate_coercion::<$source, $target>(slice)?;
739
740 Ok(Self {
741 sexp,
742 _marker: PhantomData,
743 })
744 }
745
746 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
747 Self::try_from_sexp(sexp)
748 }
749 }
750
751 impl<const NDIM: usize> RArray<$target, NDIM> {
752 #[inline]
762 pub unsafe fn to_vec_coerced(&self) -> Vec<$target> {
763 let slice: &[$source] = unsafe { self.sexp.as_slice() };
764 slice
765 .iter()
766 .copied()
767 .map(|v| {
768 <$source as TryCoerce<$target>>::try_coerce(v)
769 .expect("coercion should succeed")
770 })
771 .collect()
772 }
773 }
774 };
775}
776
777impl<const NDIM : usize> TryFromSexp for RArray<i8, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, i8>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<i8, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<i8> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<i8>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => i8);
779impl<const NDIM : usize> TryFromSexp for RArray<i16, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, i16>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<i16, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<i16> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<i16>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => i16);
780impl<const NDIM : usize> TryFromSexp for RArray<i64, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, i64>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<i64, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<i64> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<i64>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => i64);
781impl<const NDIM : usize> TryFromSexp for RArray<isize, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, isize>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<isize, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<isize> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<isize>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => isize);
782impl<const NDIM : usize> TryFromSexp for RArray<u16, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, u16>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<u16, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<u16> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<u16>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => u16);
783impl<const NDIM : usize> TryFromSexp for RArray<u32, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, u32>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<u32, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<u32> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<u32>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => u32);
784impl<const NDIM : usize> TryFromSexp for RArray<u64, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, u64>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<u64, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<u64> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<u64>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => u64);
785impl<const NDIM : usize> TryFromSexp for RArray<usize, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <i32 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <i32 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[i32] = unsafe { sexp.as_slice() };
validate_coercion::<i32, usize>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<usize, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<usize> {
let slice: &[i32] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<i32 as
TryCoerce<usize>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(i32 => usize);
786
787impl<const NDIM : usize> TryFromSexp for RArray<f32, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <f64 as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <f64 as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[f64] = unsafe { sexp.as_slice() };
validate_coercion::<f64, f32>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<f32, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<f32> {
let slice: &[f64] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<f64 as
TryCoerce<f32>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(f64 => f32);
789
790impl<const NDIM : usize> TryFromSexp for RArray<bool, NDIM> {
type Error = SexpError;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let actual = sexp.type_of();
if actual != <RLogical as RNativeType>::SEXP_TYPE {
return Err(SexpTypeError {
expected: <RLogical as RNativeType>::SEXP_TYPE,
actual,
}.into());
}
let ndim = get_ndim(sexp);
if ndim != NDIM {
return Err(SexpLengthError {
expected: NDIM,
actual: ndim,
}.into());
}
let slice: &[RLogical] = unsafe { sexp.as_slice() };
validate_coercion::<RLogical, bool>(slice)?;
Ok(Self { sexp, _marker: PhantomData })
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
Self::try_from_sexp(sexp)
}
}
impl<const NDIM : usize> RArray<bool, NDIM> {
#[inline]
pub unsafe fn to_vec_coerced(&self) -> Vec<bool> {
let slice: &[RLogical] = unsafe { self.sexp.as_slice() };
slice.iter().copied().map(|v|
{
<RLogical as
TryCoerce<bool>>::try_coerce(v).expect("coercion should succeed")
}).collect()
}
}impl_rarray_try_from_sexp_coerce!(RLogical => bool);
792impl<T: RNativeType, const NDIM: usize> IntoR for RArray<T, NDIM> {
797 type Error = std::convert::Infallible;
798 fn try_into_sexp(self) -> Result<crate::SEXP, Self::Error> {
799 Ok(self.into_sexp())
800 }
801 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::SEXP, Self::Error> {
802 Ok(unsafe { self.into_sexp_unchecked() })
803 }
804 fn into_sexp(self) -> SEXP {
805 self.sexp
806 }
807
808 unsafe fn into_sexp_unchecked(self) -> SEXP {
809 self.sexp
810 }
811}
812fn get_ndim(sexp: SEXP) -> usize {
818 {
819 let dim_sexp = sexp.get_dim();
820 if dim_sexp.type_of() != SEXPTYPE::INTSXP {
821 1
823 } else {
824 dim_sexp.len()
825 }
826 }
827}
828
829unsafe fn get_dims<const NDIM: usize>(sexp: SEXP) -> [usize; NDIM] {
835 let mut dims = [0usize; NDIM];
836
837 unsafe {
838 let dim_sexp = sexp.get_dim();
839
840 if dim_sexp.type_of() != SEXPTYPE::INTSXP {
841 if NDIM == 1 {
843 dims[0] = sexp.len();
844 }
845 } else {
846 let dim_slice: &[i32] = dim_sexp.as_slice();
847 for (i, &d) in dim_slice.iter().take(NDIM).enumerate() {
848 dims[i] = d as usize;
849 }
850 }
851 }
852
853 dims
854}
855
856unsafe fn set_dims<const NDIM: usize>(sexp: SEXP, dims: &[usize; NDIM]) {
862 unsafe {
863 let (dim_sexp, dim_slice) = crate::into_r::alloc_r_vector::<i32>(NDIM);
864 let _guard = crate::OwnedProtect::new(dim_sexp);
865
866 for (slot, &d) in dim_slice.iter_mut().zip(dims.iter()) {
867 *slot = i32::try_from(d).unwrap_or_else(|_| {
868 {
::core::panicking::panic_fmt(format_args!("array dimension {0} exceeds i32::MAX",
d));
};panic!("array dimension {d} exceeds i32::MAX");
869 });
870 }
871
872 sexp.set_dim(dim_sexp);
873 }
874}
875impl<T: RNativeType, const NDIM: usize> std::fmt::Debug for RArray<T, NDIM> {
880 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
881 f.debug_struct("RArray")
882 .field("ndim", &NDIM)
883 .field("len", &self.len())
884 .field("sexp", &self.sexp)
885 .finish()
886 }
887}
888#[cfg(test)]
893mod tests {
894 use super::*;
895
896 #[test]
897 fn matrix_is_array2() {
898 fn assert_matrix<T: RNativeType>(_: RMatrix<T>) {}
899 fn assert_array2<T: RNativeType>(_: RArray<T, 2>) {}
900
901 let m: RMatrix<f64> = unsafe { RArray::from_sexp_unchecked(SEXP(std::ptr::null_mut())) };
903 assert_matrix(m);
904 assert_array2(m);
905 }
906
907 #[test]
908 fn size_equals_sexp() {
909 assert_eq!(
911 std::mem::size_of::<RArray<f64, 2>>(),
912 std::mem::size_of::<SEXP>()
913 );
914 }
915
916 }
920