1use std::marker::PhantomData;
27use std::ops::Deref;
28use std::sync::OnceLock;
29
30use crate::altrep_traits::NA_INTEGER;
31use crate::from_r::{
32 BatchedErrors, SexpError, SexpLengthError, SexpNaError, TryFromSexp, charsxp_to_str,
33};
34use crate::gc_protect::OwnedProtect;
35use crate::into_r::IntoR;
36use crate::sys::Rf_allocVector;
37use crate::{IsNA, SEXP, SEXPTYPE, SexpExt};
38
39static FACTOR_CLASS: OnceLock<SEXP> = OnceLock::new();
42
43pub(crate) fn factor_class_sexp() -> SEXP {
44 *FACTOR_CLASS.get_or_init(|| build_levels_sexp_cached(&["factor"]))
45}
46pub trait RFactor: crate::match_arg::MatchArg + Copy + 'static {
55 fn to_level_index(self) -> i32;
57
58 fn from_level_index(idx: i32) -> Option<Self>;
60}
61pub fn build_levels_sexp(levels: &[&str]) -> SEXP {
75 build_levels_sexp_protected(levels).get()
76}
77
78fn build_levels_sexp_protected(levels: &[&str]) -> OwnedProtect {
80 if levels.iter().any(|level| level.as_bytes().contains(&0)) {
83 {
::core::panicking::panic_fmt(format_args!("level name contains null byte"));
};panic!("level name contains null byte");
84 }
85 let len = levels.len().try_into().expect("too many factor levels");
86 unsafe {
87 let sexp = OwnedProtect::new(Rf_allocVector(SEXPTYPE::STRSXP, len));
88 for (i, level) in (0..len).zip(levels) {
89 sexp.set_string_elt(i, SEXP::charsxp(level));
92 }
93 sexp
94 }
95}
96
97pub fn build_levels_sexp_cached(levels: &[&str]) -> SEXP {
99 unsafe {
100 let sexp = build_levels_sexp_protected(levels);
101 crate::sys::R_PreserveObject(sexp.get());
102 sexp.get()
103 }
104}
105
106pub fn build_factor(indices: &[i32], levels: SEXP) -> SEXP {
111 unsafe {
112 let (sexp, dst) = crate::into_r::alloc_r_vector::<i32>(indices.len());
113 let sexp = OwnedProtect::new(sexp);
115 dst.copy_from_slice(indices);
116 sexp.set_levels(levels);
117 sexp.set_class(factor_class_sexp());
118 sexp.get()
119 }
120}
121
122pub fn build_factor_with_levels(indices: &[i32], level_names: &[&str]) -> SEXP {
137 let levels = build_levels_sexp_protected(level_names);
138 build_factor(indices, levels.get())
139}
140pub struct Factor<'a> {
164 indices: &'a [i32],
165 levels_sexp: SEXP,
166 _marker: PhantomData<&'a ()>,
167}
168
169impl<'a> Factor<'a> {
170 pub fn try_new(sexp: SEXP) -> Result<Self, SexpError> {
174 if !sexp.is_factor() {
175 return Err(SexpError::InvalidValue("expected a factor".into()));
176 }
177
178 let indices = unsafe { sexp.as_slice::<i32>() };
179 let levels_sexp = sexp.get_levels();
180
181 Ok(Self {
182 indices,
183 levels_sexp,
184 _marker: PhantomData,
185 })
186 }
187
188 #[inline]
190 pub fn len(&self) -> usize {
191 self.indices.len()
192 }
193
194 #[inline]
196 pub fn is_empty(&self) -> bool {
197 self.indices.is_empty()
198 }
199
200 #[inline]
202 pub fn levels_sexp(&self) -> SEXP {
203 self.levels_sexp
204 }
205
206 #[inline]
208 pub fn n_levels(&self) -> usize {
209 self.levels_sexp.len()
210 }
211
212 #[inline]
214 pub fn level(&self, idx: usize) -> &'a str {
215 if !(idx < self.n_levels()) {
{
::core::panicking::panic_fmt(format_args!("level index {1} out of bounds (n_levels = {0})",
self.n_levels(), idx));
}
};assert!(
216 idx < self.n_levels(),
217 "level index {idx} out of bounds (n_levels = {})",
218 self.n_levels()
219 );
220 let charsxp = self.levels_sexp.string_elt(idx as isize);
221 unsafe { charsxp_to_str(charsxp) }
222 }
223}
224
225impl Deref for Factor<'_> {
226 type Target = [i32];
227
228 #[inline]
229 fn deref(&self) -> &Self::Target {
230 self.indices
231 }
232}
233
234impl<'a> TryFromSexp for Factor<'a> {
235 type Error = SexpError;
236 const CHARACTER_ONLY: bool = true;
237
238 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
239 Self::try_new(sexp)
240 }
241}
242pub struct FactorMut<'a> {
261 indices: &'a mut [i32],
262 levels_sexp: SEXP,
263 _marker: PhantomData<&'a mut ()>,
264}
265
266impl<'a> FactorMut<'a> {
267 pub fn try_new(sexp: SEXP) -> Result<Self, SexpError> {
271 if !sexp.is_factor() {
272 return Err(SexpError::InvalidValue("expected a factor".into()));
273 }
274
275 let indices = unsafe { sexp.as_mut_slice::<i32>() };
276 let levels_sexp = sexp.get_levels();
277
278 Ok(Self {
279 indices,
280 levels_sexp,
281 _marker: PhantomData,
282 })
283 }
284
285 #[inline]
287 pub fn len(&self) -> usize {
288 self.indices.len()
289 }
290
291 #[inline]
293 pub fn is_empty(&self) -> bool {
294 self.indices.is_empty()
295 }
296
297 #[inline]
299 pub fn levels_sexp(&self) -> SEXP {
300 self.levels_sexp
301 }
302
303 #[inline]
305 pub fn n_levels(&self) -> usize {
306 self.levels_sexp.len()
307 }
308
309 #[inline]
311 pub fn level(&self, idx: usize) -> &'a str {
312 if !(idx < self.n_levels()) {
{
::core::panicking::panic_fmt(format_args!("level index {1} out of bounds (n_levels = {0})",
self.n_levels(), idx));
}
};assert!(
313 idx < self.n_levels(),
314 "level index {idx} out of bounds (n_levels = {})",
315 self.n_levels()
316 );
317 let charsxp = self.levels_sexp.string_elt(idx as isize);
318 unsafe { charsxp_to_str(charsxp) }
319 }
320}
321
322impl Deref for FactorMut<'_> {
323 type Target = [i32];
324
325 #[inline]
326 fn deref(&self) -> &Self::Target {
327 self.indices
328 }
329}
330
331impl std::ops::DerefMut for FactorMut<'_> {
332 #[inline]
333 fn deref_mut(&mut self) -> &mut Self::Target {
334 self.indices
335 }
336}
337pub(crate) fn validate_factor_levels(sexp: SEXP, expected: &[&str]) -> Result<(), SexpError> {
343 if !sexp.is_factor() {
344 return Err(SexpError::InvalidValue("expected a factor".into()));
345 }
346
347 let levels = sexp.get_levels();
348 if levels.type_of() != SEXPTYPE::STRSXP {
349 return Err(SexpError::InvalidValue("levels is not STRSXP".into()));
350 }
351
352 let n = levels.len();
353 if n != expected.len() {
354 return Err(SexpError::InvalidValue(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0} levels, got {1}",
expected.len(), n))
})format!(
355 "expected {} levels, got {}",
356 expected.len(),
357 n
358 )));
359 }
360
361 for (i, exp) in expected.iter().enumerate() {
362 let charsxp = levels.string_elt(i as isize);
363 let actual = unsafe { charsxp_to_str(charsxp) };
364 if actual != *exp {
365 return Err(SexpError::InvalidValue(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("level {0}: expected \'{1}\', got \'{2}\'",
i + 1, exp, actual))
})format!(
366 "level {}: expected '{}', got '{}'",
367 i + 1,
368 exp,
369 actual
370 )));
371 }
372 }
373
374 Ok(())
375}
376fn code_not_a_level(code: i32) -> String {
383 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("code {0} is not a level of the factor",
code))
})format!("code {code} is not a level of the factor")
384}
385
386fn read_factor_codes<U>(
390 sexp: SEXP,
391 elt: impl Fn(i32) -> Result<U, String>,
392) -> Result<Vec<U>, SexpError> {
393 let len = sexp.len();
394 let mut result = Vec::with_capacity(len);
395 let mut errors = BatchedErrors::default();
396 for i in 0..len {
397 match elt(sexp.integer_elt(i as isize)) {
398 Ok(v) => result.push(v),
399 Err(reason) => errors.push(i, || reason),
400 }
401 }
402 if errors.is_empty() {
403 Ok(result)
404 } else {
405 Err(errors.into_element_error())
406 }
407}
408
409#[inline]
411pub fn factor_from_sexp<T: RFactor>(sexp: SEXP) -> Result<T, SexpError> {
412 validate_factor_levels(sexp, T::CHOICES)?;
413
414 let len = sexp.len();
415 if len != 1 {
416 return Err(SexpLengthError {
417 expected: 1,
418 actual: len,
419 }
420 .into());
421 }
422
423 let idx = sexp.integer_elt(0);
424 if idx.is_na() {
425 return Err(SexpNaError {
426 sexp_type: SEXPTYPE::INTSXP,
427 }
428 .into());
429 }
430
431 T::from_level_index(idx).ok_or_else(|| SexpError::InvalidValue(code_not_a_level(idx)))
432}
433
434#[inline]
437pub(crate) fn factor_vec_from_sexp<T: UnitEnumFactor>(sexp: SEXP) -> Result<Vec<T>, SexpError> {
438 validate_factor_levels(sexp, T::FACTOR_LEVELS)?;
439 read_factor_codes(sexp, |idx| {
440 if idx.is_na() {
441 return Err("NA is not allowed".to_string());
442 }
443 T::from_factor_index(idx).ok_or_else(|| code_not_a_level(idx))
444 })
445}
446
447#[inline]
449pub(crate) fn factor_option_vec_from_sexp<T: RFactor>(
450 sexp: SEXP,
451) -> Result<Vec<Option<T>>, SexpError> {
452 validate_factor_levels(sexp, T::CHOICES)?;
453 read_factor_codes(sexp, |idx| {
454 if idx.is_na() {
455 return Ok(None);
456 }
457 T::from_level_index(idx)
458 .map(Some)
459 .ok_or_else(|| code_not_a_level(idx))
460 })
461}
462
463#[inline]
470pub fn unit_factor_option_vec_from_sexp<T: UnitEnumFactor>(
471 sexp: SEXP,
472) -> Result<Vec<Option<T>>, SexpError> {
473 validate_factor_levels(sexp, T::FACTOR_LEVELS)?;
474 read_factor_codes(sexp, |idx| {
475 if idx.is_na() {
476 return Ok(None);
477 }
478 T::from_factor_index(idx)
479 .map(Some)
480 .ok_or_else(|| code_not_a_level(idx))
481 })
482}
483#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for FactorVec<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "FactorVec",
&&self.0)
}
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for FactorVec<T> {
#[inline]
fn clone(&self) -> Self {
FactorVec(::core::clone::Clone::clone(&self.0))
}
}Clone)]
492pub struct FactorVec<T>(pub Vec<T>);
493
494impl<T> FactorVec<T> {
495 pub fn new(vec: Vec<T>) -> Self {
497 Self(vec)
498 }
499
500 pub fn into_inner(self) -> Vec<T> {
502 self.0
503 }
504}
505
506impl<T> From<Vec<T>> for FactorVec<T> {
507 fn from(vec: Vec<T>) -> Self {
508 Self(vec)
509 }
510}
511
512impl<T> Deref for FactorVec<T> {
513 type Target = Vec<T>;
514 fn deref(&self) -> &Self::Target {
515 &self.0
516 }
517}
518
519impl<T> std::ops::DerefMut for FactorVec<T> {
520 fn deref_mut(&mut self) -> &mut Self::Target {
521 &mut self.0
522 }
523}
524
525impl<T: UnitEnumFactor> IntoR for FactorVec<T> {
526 type Error = std::convert::Infallible;
527 fn try_into_sexp(self) -> Result<crate::SEXP, Self::Error> {
528 Ok(self.into_sexp())
529 }
530 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::SEXP, Self::Error> {
531 self.try_into_sexp()
532 }
533 fn into_sexp(self) -> SEXP {
534 let indices: Vec<i32> = self.0.into_iter().map(T::to_factor_index).collect();
535 build_factor_with_levels(&indices, T::FACTOR_LEVELS)
538 }
539}
540
541impl<T: UnitEnumFactor> TryFromSexp for FactorVec<T> {
542 type Error = SexpError;
543 const CHARACTER_ONLY: bool = true;
544 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
545 factor_vec_from_sexp(sexp).map(FactorVec)
546 }
547}
548
549#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for FactorOptionVec<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"FactorOptionVec", &&self.0)
}
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for FactorOptionVec<T> {
#[inline]
fn clone(&self) -> Self {
FactorOptionVec(::core::clone::Clone::clone(&self.0))
}
}Clone)]
551pub struct FactorOptionVec<T>(pub Vec<Option<T>>);
552
553impl<T> FactorOptionVec<T> {
554 pub fn new(vec: Vec<Option<T>>) -> Self {
556 Self(vec)
557 }
558
559 pub fn into_inner(self) -> Vec<Option<T>> {
561 self.0
562 }
563}
564
565impl<T> From<Vec<Option<T>>> for FactorOptionVec<T> {
566 fn from(vec: Vec<Option<T>>) -> Self {
567 Self(vec)
568 }
569}
570
571impl<T> Deref for FactorOptionVec<T> {
572 type Target = Vec<Option<T>>;
573 fn deref(&self) -> &Self::Target {
574 &self.0
575 }
576}
577
578impl<T> std::ops::DerefMut for FactorOptionVec<T> {
579 fn deref_mut(&mut self) -> &mut Self::Target {
580 &mut self.0
581 }
582}
583
584impl<T: RFactor + crate::match_arg::MatchArg> UnitEnumFactor for T {
586 const FACTOR_LEVELS: &'static [&'static str] = T::CHOICES;
587 fn to_factor_index(self) -> i32 {
588 self.to_level_index()
589 }
590 fn from_factor_index(idx: i32) -> Option<Self> {
591 T::from_level_index(idx)
592 }
593}
594
595impl<T: RFactor> TryFromSexp for FactorOptionVec<T> {
596 type Error = SexpError;
597 const CHARACTER_ONLY: bool = true;
598 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
599 factor_option_vec_from_sexp(sexp).map(FactorOptionVec)
600 }
601}
602
603pub trait UnitEnumFactor: Sized {
621 const FACTOR_LEVELS: &'static [&'static str];
623
624 fn to_factor_index(self) -> i32;
626
627 fn from_factor_index(idx: i32) -> Option<Self>;
633}
634
635impl<T: UnitEnumFactor> IntoR for FactorOptionVec<T> {
636 type Error = std::convert::Infallible;
637 fn try_into_sexp(self) -> Result<crate::SEXP, Self::Error> {
638 Ok(self.into_sexp())
639 }
640 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::SEXP, Self::Error> {
641 self.try_into_sexp()
642 }
643 fn into_sexp(self) -> SEXP {
644 let indices: Vec<i32> = self
648 .0
649 .into_iter()
650 .map(|opt| match opt {
651 None => NA_INTEGER,
652 Some(v) => v.to_factor_index(),
653 })
654 .collect();
655 build_factor_with_levels(&indices, T::FACTOR_LEVELS)
656 }
657}
658#[cfg(test)]
663mod tests {
664 use super::*;
665 use crate::match_arg::MatchArg;
666
667 #[derive(Copy, Clone, Debug, PartialEq)]
668 enum TestColor {
669 Red,
670 Green,
671 Blue,
672 }
673
674 impl MatchArg for TestColor {
675 const CHOICES: &'static [&'static str] = &["Red", "Green", "Blue"];
676
677 fn from_choice(choice: &str) -> Option<Self> {
678 match choice {
679 "Red" => Some(TestColor::Red),
680 "Green" => Some(TestColor::Green),
681 "Blue" => Some(TestColor::Blue),
682 _ => None,
683 }
684 }
685
686 fn to_choice(self) -> &'static str {
687 match self {
688 TestColor::Red => "Red",
689 TestColor::Green => "Green",
690 TestColor::Blue => "Blue",
691 }
692 }
693 }
694
695 impl RFactor for TestColor {
696 fn to_level_index(self) -> i32 {
697 match self {
698 TestColor::Red => 1,
699 TestColor::Green => 2,
700 TestColor::Blue => 3,
701 }
702 }
703
704 fn from_level_index(idx: i32) -> Option<Self> {
705 match idx {
706 1 => Some(TestColor::Red),
707 2 => Some(TestColor::Green),
708 3 => Some(TestColor::Blue),
709 _ => None,
710 }
711 }
712 }
713
714 #[test]
715 fn test_level_index_roundtrip() {
716 assert_eq!(
717 TestColor::from_level_index(TestColor::Red.to_level_index()),
718 Some(TestColor::Red)
719 );
720 assert_eq!(
721 TestColor::from_level_index(TestColor::Green.to_level_index()),
722 Some(TestColor::Green)
723 );
724 assert_eq!(
725 TestColor::from_level_index(TestColor::Blue.to_level_index()),
726 Some(TestColor::Blue)
727 );
728 }
729
730 #[test]
731 fn test_invalid_index() {
732 assert_eq!(TestColor::from_level_index(0), None);
733 assert_eq!(TestColor::from_level_index(4), None);
734 assert_eq!(TestColor::from_level_index(-1), None);
735 }
736
737 #[test]
738 fn test_levels_array() {
739 assert_eq!(TestColor::CHOICES, &["Red", "Green", "Blue"]);
740 }
741
742 #[derive(Copy, Clone, Debug, PartialEq)]
744 enum Size {
745 Small,
746 Large,
747 }
748
749 impl MatchArg for Size {
750 const CHOICES: &'static [&'static str] = &["Small", "Large"];
751
752 fn from_choice(choice: &str) -> Option<Self> {
753 match choice {
754 "Small" => Some(Size::Small),
755 "Large" => Some(Size::Large),
756 _ => None,
757 }
758 }
759
760 fn to_choice(self) -> &'static str {
761 match self {
762 Size::Small => "Small",
763 Size::Large => "Large",
764 }
765 }
766 }
767
768 impl RFactor for Size {
769 fn to_level_index(self) -> i32 {
770 match self {
771 Size::Small => 1,
772 Size::Large => 2,
773 }
774 }
775
776 fn from_level_index(idx: i32) -> Option<Self> {
777 match idx {
778 1 => Some(Size::Small),
779 2 => Some(Size::Large),
780 _ => None,
781 }
782 }
783 }
784
785 #[derive(Copy, Clone, Debug, PartialEq)]
787 enum ColorSize {
788 Red(Size),
789 Green(Size),
790 Blue(Size),
791 }
792
793 impl MatchArg for ColorSize {
794 const CHOICES: &'static [&'static str] = &[
795 "Red.Small",
796 "Red.Large",
797 "Green.Small",
798 "Green.Large",
799 "Blue.Small",
800 "Blue.Large",
801 ];
802
803 fn from_choice(choice: &str) -> Option<Self> {
804 let idx_1 = Self::CHOICES
805 .iter()
806 .position(|&l| l == choice)
807 .map(|i| i as i32 + 1)?;
808 Self::from_level_index(idx_1)
809 }
810
811 fn to_choice(self) -> &'static str {
812 Self::CHOICES[(self.to_level_index() - 1) as usize]
813 }
814 }
815
816 impl RFactor for ColorSize {
817 fn to_level_index(self) -> i32 {
818 match self {
819 Self::Red(inner) => {
820 let inner_idx_0 = inner.to_level_index() - 1;
821 inner_idx_0 + 1
822 }
823 Self::Green(inner) => {
824 let inner_idx_0 = inner.to_level_index() - 1;
825 2 + inner_idx_0 + 1
826 }
827 Self::Blue(inner) => {
828 let inner_idx_0 = inner.to_level_index() - 1;
829 2 * 2 + inner_idx_0 + 1
830 }
831 }
832 }
833
834 fn from_level_index(idx: i32) -> Option<Self> {
835 match idx {
836 1..=2 => {
837 let inner_idx_1 = (idx - 1) % 2 + 1;
838 Size::from_level_index(inner_idx_1).map(Self::Red)
839 }
840 3..=4 => {
841 let inner_idx_1 = (idx - 1) % 2 + 1;
842 Size::from_level_index(inner_idx_1).map(Self::Green)
843 }
844 5..=6 => {
845 let inner_idx_1 = (idx - 1) % 2 + 1;
846 Size::from_level_index(inner_idx_1).map(Self::Blue)
847 }
848 _ => None,
849 }
850 }
851 }
852
853 #[test]
854 fn test_interaction_levels() {
855 assert_eq!(
856 ColorSize::CHOICES,
857 &[
858 "Red.Small",
859 "Red.Large",
860 "Green.Small",
861 "Green.Large",
862 "Blue.Small",
863 "Blue.Large"
864 ]
865 );
866 }
867
868 #[test]
869 fn test_interaction_to_index() {
870 assert_eq!(ColorSize::Red(Size::Small).to_level_index(), 1);
871 assert_eq!(ColorSize::Red(Size::Large).to_level_index(), 2);
872 assert_eq!(ColorSize::Green(Size::Small).to_level_index(), 3);
873 assert_eq!(ColorSize::Green(Size::Large).to_level_index(), 4);
874 assert_eq!(ColorSize::Blue(Size::Small).to_level_index(), 5);
875 assert_eq!(ColorSize::Blue(Size::Large).to_level_index(), 6);
876 }
877
878 #[test]
879 fn test_interaction_from_index() {
880 assert_eq!(
881 ColorSize::from_level_index(1),
882 Some(ColorSize::Red(Size::Small))
883 );
884 assert_eq!(
885 ColorSize::from_level_index(2),
886 Some(ColorSize::Red(Size::Large))
887 );
888 assert_eq!(
889 ColorSize::from_level_index(3),
890 Some(ColorSize::Green(Size::Small))
891 );
892 assert_eq!(
893 ColorSize::from_level_index(4),
894 Some(ColorSize::Green(Size::Large))
895 );
896 assert_eq!(
897 ColorSize::from_level_index(5),
898 Some(ColorSize::Blue(Size::Small))
899 );
900 assert_eq!(
901 ColorSize::from_level_index(6),
902 Some(ColorSize::Blue(Size::Large))
903 );
904 assert_eq!(ColorSize::from_level_index(0), None);
905 assert_eq!(ColorSize::from_level_index(7), None);
906 }
907
908 #[test]
909 fn test_interaction_roundtrip() {
910 for i in 1..=6 {
911 let color_size = ColorSize::from_level_index(i).unwrap();
912 assert_eq!(color_size.to_level_index(), i);
913 }
914 }
915}
916