1use std::ffi::CString;
27use std::marker::PhantomData;
28use std::ops::Deref;
29use std::sync::OnceLock;
30
31use crate::altrep_traits::NA_INTEGER;
32use crate::ffi::{INTEGER, Rf_allocVector, Rf_install, Rf_xlength, SEXP, SEXPTYPE, SexpExt};
33use crate::from_r::{SexpError, TryFromSexp, charsxp_to_str};
34use crate::into_r::IntoR;
35
36static FACTOR_CLASS: OnceLock<SEXP> = OnceLock::new();
39
40pub(crate) fn factor_class_sexp() -> SEXP {
41 *FACTOR_CLASS.get_or_init(|| unsafe {
42 let class_sexp = Rf_allocVector(SEXPTYPE::STRSXP, 1);
43 crate::ffi::R_PreserveObject(class_sexp);
44 let sym = Rf_install(c"factor".as_ptr());
46 class_sexp.set_string_elt(0, sym.printname());
47 class_sexp
48 })
49}
50pub trait RFactor: crate::match_arg::MatchArg + Copy + 'static {
59 fn to_level_index(self) -> i32;
61
62 fn from_level_index(idx: i32) -> Option<Self>;
64}
65pub fn build_levels_sexp(levels: &[&str]) -> SEXP {
73 unsafe {
74 let sexp = Rf_allocVector(SEXPTYPE::STRSXP, levels.len() as isize);
75 for (i, level) in levels.iter().enumerate() {
76 let c_str = CString::new(*level).expect("level name contains null byte");
78 let sym = Rf_install(c_str.as_ptr());
79 sexp.set_string_elt(i as isize, sym.printname());
80 }
81 sexp
82 }
83}
84
85pub fn build_levels_sexp_cached(levels: &[&str]) -> SEXP {
87 unsafe {
88 let sexp = build_levels_sexp(levels);
89 crate::ffi::R_PreserveObject(sexp);
90 sexp
91 }
92}
93
94pub fn build_factor(indices: &[i32], levels: SEXP) -> SEXP {
96 unsafe {
97 let (sexp, dst) = crate::into_r::alloc_r_vector::<i32>(indices.len());
98 dst.copy_from_slice(indices);
99 sexp.set_levels(levels);
100 sexp.set_class(factor_class_sexp());
101 sexp
102 }
103}
104pub struct Factor<'a> {
127 indices: &'a [i32],
128 levels_sexp: SEXP,
129 _marker: PhantomData<&'a ()>,
130}
131
132impl<'a> Factor<'a> {
133 pub fn try_new(sexp: SEXP) -> Result<Self, SexpError> {
137 if !sexp.is_factor() {
138 return Err(SexpError::InvalidValue("expected a factor".into()));
139 }
140
141 let len = unsafe { Rf_xlength(sexp) } as usize;
142 let ptr = unsafe { INTEGER(sexp) };
143 let indices = unsafe { crate::from_r::r_slice(ptr, len) };
144 let levels_sexp = sexp.get_levels();
145
146 Ok(Self {
147 indices,
148 levels_sexp,
149 _marker: PhantomData,
150 })
151 }
152
153 #[inline]
155 pub fn len(&self) -> usize {
156 self.indices.len()
157 }
158
159 #[inline]
161 pub fn is_empty(&self) -> bool {
162 self.indices.is_empty()
163 }
164
165 #[inline]
167 pub fn levels_sexp(&self) -> SEXP {
168 self.levels_sexp
169 }
170
171 #[inline]
173 pub fn n_levels(&self) -> usize {
174 unsafe { Rf_xlength(self.levels_sexp) as usize }
175 }
176
177 #[inline]
179 pub fn level(&self, idx: usize) -> &'a str {
180 assert!(
181 idx < self.n_levels(),
182 "level index {idx} out of bounds (n_levels = {})",
183 self.n_levels()
184 );
185 let charsxp = self.levels_sexp.string_elt(idx as isize);
186 unsafe { charsxp_to_str(charsxp) }
187 }
188}
189
190impl Deref for Factor<'_> {
191 type Target = [i32];
192
193 #[inline]
194 fn deref(&self) -> &Self::Target {
195 self.indices
196 }
197}
198
199impl<'a> TryFromSexp for Factor<'a> {
200 type Error = SexpError;
201
202 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
203 Self::try_new(sexp)
204 }
205}
206pub struct FactorMut<'a> {
225 indices: &'a mut [i32],
226 levels_sexp: SEXP,
227 _marker: PhantomData<&'a mut ()>,
228}
229
230impl<'a> FactorMut<'a> {
231 pub fn try_new(sexp: SEXP) -> Result<Self, SexpError> {
235 if !sexp.is_factor() {
236 return Err(SexpError::InvalidValue("expected a factor".into()));
237 }
238
239 let len = unsafe { Rf_xlength(sexp) } as usize;
240 let ptr = unsafe { INTEGER(sexp) };
241 let indices = unsafe { crate::from_r::r_slice_mut(ptr, len) };
242 let levels_sexp = sexp.get_levels();
243
244 Ok(Self {
245 indices,
246 levels_sexp,
247 _marker: PhantomData,
248 })
249 }
250
251 #[inline]
253 pub fn len(&self) -> usize {
254 self.indices.len()
255 }
256
257 #[inline]
259 pub fn is_empty(&self) -> bool {
260 self.indices.is_empty()
261 }
262
263 #[inline]
265 pub fn levels_sexp(&self) -> SEXP {
266 self.levels_sexp
267 }
268
269 #[inline]
271 pub fn n_levels(&self) -> usize {
272 unsafe { Rf_xlength(self.levels_sexp) as usize }
273 }
274
275 #[inline]
277 pub fn level(&self, idx: usize) -> &'a str {
278 assert!(
279 idx < self.n_levels(),
280 "level index {idx} out of bounds (n_levels = {})",
281 self.n_levels()
282 );
283 let charsxp = self.levels_sexp.string_elt(idx as isize);
284 unsafe { charsxp_to_str(charsxp) }
285 }
286}
287
288impl Deref for FactorMut<'_> {
289 type Target = [i32];
290
291 #[inline]
292 fn deref(&self) -> &Self::Target {
293 self.indices
294 }
295}
296
297impl std::ops::DerefMut for FactorMut<'_> {
298 #[inline]
299 fn deref_mut(&mut self) -> &mut Self::Target {
300 self.indices
301 }
302}
303pub(crate) fn validate_factor_levels(sexp: SEXP, expected: &[&str]) -> Result<(), SexpError> {
309 if !sexp.is_factor() {
310 return Err(SexpError::InvalidValue("expected a factor".into()));
311 }
312
313 let levels = sexp.get_levels();
314 if levels.type_of() != SEXPTYPE::STRSXP {
315 return Err(SexpError::InvalidValue("levels is not STRSXP".into()));
316 }
317
318 let n = unsafe { Rf_xlength(levels) } as usize;
319 if n != expected.len() {
320 return Err(SexpError::InvalidValue(format!(
321 "expected {} levels, got {}",
322 expected.len(),
323 n
324 )));
325 }
326
327 for (i, exp) in expected.iter().enumerate() {
328 let charsxp = levels.string_elt(i as isize);
329 let actual = unsafe { charsxp_to_str(charsxp) };
330 if actual != *exp {
331 return Err(SexpError::InvalidValue(format!(
332 "level {}: expected '{}', got '{}'",
333 i + 1,
334 exp,
335 actual
336 )));
337 }
338 }
339
340 Ok(())
341}
342#[inline]
348pub fn factor_from_sexp<T: RFactor>(sexp: SEXP) -> Result<T, SexpError> {
349 validate_factor_levels(sexp, T::CHOICES)?;
350
351 let len = unsafe { Rf_xlength(sexp) };
352 if len != 1 {
353 return Err(SexpError::InvalidValue(format!(
354 "expected length 1, got {}",
355 len
356 )));
357 }
358
359 let idx = sexp.integer_elt(0);
360 if idx == NA_INTEGER {
361 return Err(SexpError::InvalidValue("unexpected NA".into()));
362 }
363
364 T::from_level_index(idx).ok_or_else(|| SexpError::InvalidValue("index out of range".into()))
365}
366
367#[inline]
369pub(crate) fn factor_vec_from_sexp<T: RFactor>(sexp: SEXP) -> Result<Vec<T>, SexpError> {
370 validate_factor_levels(sexp, T::CHOICES)?;
371
372 let len = unsafe { Rf_xlength(sexp) } as usize;
373 let mut result = Vec::with_capacity(len);
374
375 for i in 0..len {
376 let idx = sexp.integer_elt(i as isize);
377 if idx == NA_INTEGER {
378 return Err(SexpError::InvalidValue(format!("NA at index {}", i)));
379 }
380 result.push(
381 T::from_level_index(idx)
382 .ok_or_else(|| SexpError::InvalidValue("index out of range".into()))?,
383 );
384 }
385
386 Ok(result)
387}
388
389#[inline]
391pub(crate) fn factor_option_vec_from_sexp<T: RFactor>(
392 sexp: SEXP,
393) -> Result<Vec<Option<T>>, SexpError> {
394 validate_factor_levels(sexp, T::CHOICES)?;
395
396 let len = unsafe { Rf_xlength(sexp) } as usize;
397 let mut result = Vec::with_capacity(len);
398
399 for i in 0..len {
400 let idx = sexp.integer_elt(i as isize);
401 if idx == NA_INTEGER {
402 result.push(None);
403 } else {
404 result.push(Some(T::from_level_index(idx).ok_or_else(|| {
405 SexpError::InvalidValue("index out of range".into())
406 })?));
407 }
408 }
409
410 Ok(result)
411}
412#[derive(Debug, Clone)]
418pub struct FactorVec<T>(pub Vec<T>);
419
420impl<T> FactorVec<T> {
421 pub fn new(vec: Vec<T>) -> Self {
423 Self(vec)
424 }
425
426 pub fn into_inner(self) -> Vec<T> {
428 self.0
429 }
430}
431
432impl<T> From<Vec<T>> for FactorVec<T> {
433 fn from(vec: Vec<T>) -> Self {
434 Self(vec)
435 }
436}
437
438impl<T> Deref for FactorVec<T> {
439 type Target = Vec<T>;
440 fn deref(&self) -> &Self::Target {
441 &self.0
442 }
443}
444
445impl<T> std::ops::DerefMut for FactorVec<T> {
446 fn deref_mut(&mut self) -> &mut Self::Target {
447 &mut self.0
448 }
449}
450
451impl<T: RFactor> IntoR for FactorVec<T> {
452 type Error = std::convert::Infallible;
453 fn try_into_sexp(self) -> Result<crate::ffi::SEXP, Self::Error> {
454 Ok(self.into_sexp())
455 }
456 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::ffi::SEXP, Self::Error> {
457 self.try_into_sexp()
458 }
459 fn into_sexp(self) -> SEXP {
460 let indices: Vec<i32> = self.0.iter().map(|v| v.to_level_index()).collect();
461 build_factor(&indices, build_levels_sexp(T::CHOICES))
462 }
463}
464
465impl<T: RFactor> TryFromSexp for FactorVec<T> {
466 type Error = SexpError;
467 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
468 factor_vec_from_sexp(sexp).map(FactorVec)
469 }
470}
471
472#[derive(Debug, Clone)]
474pub struct FactorOptionVec<T>(pub Vec<Option<T>>);
475
476impl<T> FactorOptionVec<T> {
477 pub fn new(vec: Vec<Option<T>>) -> Self {
479 Self(vec)
480 }
481
482 pub fn into_inner(self) -> Vec<Option<T>> {
484 self.0
485 }
486}
487
488impl<T> From<Vec<Option<T>>> for FactorOptionVec<T> {
489 fn from(vec: Vec<Option<T>>) -> Self {
490 Self(vec)
491 }
492}
493
494impl<T> Deref for FactorOptionVec<T> {
495 type Target = Vec<Option<T>>;
496 fn deref(&self) -> &Self::Target {
497 &self.0
498 }
499}
500
501impl<T> std::ops::DerefMut for FactorOptionVec<T> {
502 fn deref_mut(&mut self) -> &mut Self::Target {
503 &mut self.0
504 }
505}
506
507impl<T: RFactor> IntoR for FactorOptionVec<T> {
508 type Error = std::convert::Infallible;
509 fn try_into_sexp(self) -> Result<crate::ffi::SEXP, Self::Error> {
510 Ok(self.into_sexp())
511 }
512 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::ffi::SEXP, Self::Error> {
513 self.try_into_sexp()
514 }
515 fn into_sexp(self) -> SEXP {
516 let indices: Vec<i32> = self
517 .0
518 .iter()
519 .map(|v| v.map_or(NA_INTEGER, |x| x.to_level_index()))
520 .collect();
521 build_factor(&indices, build_levels_sexp(T::CHOICES))
522 }
523}
524
525impl<T: RFactor> TryFromSexp for FactorOptionVec<T> {
526 type Error = SexpError;
527 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
528 factor_option_vec_from_sexp(sexp).map(FactorOptionVec)
529 }
530}
531#[cfg(test)]
536mod tests {
537 use super::*;
538 use crate::match_arg::MatchArg;
539
540 #[derive(Copy, Clone, Debug, PartialEq)]
541 enum TestColor {
542 Red,
543 Green,
544 Blue,
545 }
546
547 impl MatchArg for TestColor {
548 const CHOICES: &'static [&'static str] = &["Red", "Green", "Blue"];
549
550 fn from_choice(choice: &str) -> Option<Self> {
551 match choice {
552 "Red" => Some(TestColor::Red),
553 "Green" => Some(TestColor::Green),
554 "Blue" => Some(TestColor::Blue),
555 _ => None,
556 }
557 }
558
559 fn to_choice(self) -> &'static str {
560 match self {
561 TestColor::Red => "Red",
562 TestColor::Green => "Green",
563 TestColor::Blue => "Blue",
564 }
565 }
566 }
567
568 impl RFactor for TestColor {
569 fn to_level_index(self) -> i32 {
570 match self {
571 TestColor::Red => 1,
572 TestColor::Green => 2,
573 TestColor::Blue => 3,
574 }
575 }
576
577 fn from_level_index(idx: i32) -> Option<Self> {
578 match idx {
579 1 => Some(TestColor::Red),
580 2 => Some(TestColor::Green),
581 3 => Some(TestColor::Blue),
582 _ => None,
583 }
584 }
585 }
586
587 #[test]
588 fn test_level_index_roundtrip() {
589 assert_eq!(
590 TestColor::from_level_index(TestColor::Red.to_level_index()),
591 Some(TestColor::Red)
592 );
593 assert_eq!(
594 TestColor::from_level_index(TestColor::Green.to_level_index()),
595 Some(TestColor::Green)
596 );
597 assert_eq!(
598 TestColor::from_level_index(TestColor::Blue.to_level_index()),
599 Some(TestColor::Blue)
600 );
601 }
602
603 #[test]
604 fn test_invalid_index() {
605 assert_eq!(TestColor::from_level_index(0), None);
606 assert_eq!(TestColor::from_level_index(4), None);
607 assert_eq!(TestColor::from_level_index(-1), None);
608 }
609
610 #[test]
611 fn test_levels_array() {
612 assert_eq!(TestColor::CHOICES, &["Red", "Green", "Blue"]);
613 }
614
615 #[derive(Copy, Clone, Debug, PartialEq)]
617 enum Size {
618 Small,
619 Large,
620 }
621
622 impl MatchArg for Size {
623 const CHOICES: &'static [&'static str] = &["Small", "Large"];
624
625 fn from_choice(choice: &str) -> Option<Self> {
626 match choice {
627 "Small" => Some(Size::Small),
628 "Large" => Some(Size::Large),
629 _ => None,
630 }
631 }
632
633 fn to_choice(self) -> &'static str {
634 match self {
635 Size::Small => "Small",
636 Size::Large => "Large",
637 }
638 }
639 }
640
641 impl RFactor for Size {
642 fn to_level_index(self) -> i32 {
643 match self {
644 Size::Small => 1,
645 Size::Large => 2,
646 }
647 }
648
649 fn from_level_index(idx: i32) -> Option<Self> {
650 match idx {
651 1 => Some(Size::Small),
652 2 => Some(Size::Large),
653 _ => None,
654 }
655 }
656 }
657
658 #[derive(Copy, Clone, Debug, PartialEq)]
660 enum ColorSize {
661 Red(Size),
662 Green(Size),
663 Blue(Size),
664 }
665
666 impl MatchArg for ColorSize {
667 const CHOICES: &'static [&'static str] = &[
668 "Red.Small",
669 "Red.Large",
670 "Green.Small",
671 "Green.Large",
672 "Blue.Small",
673 "Blue.Large",
674 ];
675
676 fn from_choice(choice: &str) -> Option<Self> {
677 let idx_1 = Self::CHOICES
678 .iter()
679 .position(|&l| l == choice)
680 .map(|i| i as i32 + 1)?;
681 Self::from_level_index(idx_1)
682 }
683
684 fn to_choice(self) -> &'static str {
685 Self::CHOICES[(self.to_level_index() - 1) as usize]
686 }
687 }
688
689 impl RFactor for ColorSize {
690 fn to_level_index(self) -> i32 {
691 match self {
692 Self::Red(inner) => {
693 let inner_idx_0 = inner.to_level_index() - 1;
694 inner_idx_0 + 1
695 }
696 Self::Green(inner) => {
697 let inner_idx_0 = inner.to_level_index() - 1;
698 2 + inner_idx_0 + 1
699 }
700 Self::Blue(inner) => {
701 let inner_idx_0 = inner.to_level_index() - 1;
702 2 * 2 + inner_idx_0 + 1
703 }
704 }
705 }
706
707 fn from_level_index(idx: i32) -> Option<Self> {
708 match idx {
709 1..=2 => {
710 let inner_idx_1 = (idx - 1) % 2 + 1;
711 Size::from_level_index(inner_idx_1).map(Self::Red)
712 }
713 3..=4 => {
714 let inner_idx_1 = (idx - 1) % 2 + 1;
715 Size::from_level_index(inner_idx_1).map(Self::Green)
716 }
717 5..=6 => {
718 let inner_idx_1 = (idx - 1) % 2 + 1;
719 Size::from_level_index(inner_idx_1).map(Self::Blue)
720 }
721 _ => None,
722 }
723 }
724 }
725
726 #[test]
727 fn test_interaction_levels() {
728 assert_eq!(
729 ColorSize::CHOICES,
730 &[
731 "Red.Small",
732 "Red.Large",
733 "Green.Small",
734 "Green.Large",
735 "Blue.Small",
736 "Blue.Large"
737 ]
738 );
739 }
740
741 #[test]
742 fn test_interaction_to_index() {
743 assert_eq!(ColorSize::Red(Size::Small).to_level_index(), 1);
744 assert_eq!(ColorSize::Red(Size::Large).to_level_index(), 2);
745 assert_eq!(ColorSize::Green(Size::Small).to_level_index(), 3);
746 assert_eq!(ColorSize::Green(Size::Large).to_level_index(), 4);
747 assert_eq!(ColorSize::Blue(Size::Small).to_level_index(), 5);
748 assert_eq!(ColorSize::Blue(Size::Large).to_level_index(), 6);
749 }
750
751 #[test]
752 fn test_interaction_from_index() {
753 assert_eq!(
754 ColorSize::from_level_index(1),
755 Some(ColorSize::Red(Size::Small))
756 );
757 assert_eq!(
758 ColorSize::from_level_index(2),
759 Some(ColorSize::Red(Size::Large))
760 );
761 assert_eq!(
762 ColorSize::from_level_index(3),
763 Some(ColorSize::Green(Size::Small))
764 );
765 assert_eq!(
766 ColorSize::from_level_index(4),
767 Some(ColorSize::Green(Size::Large))
768 );
769 assert_eq!(
770 ColorSize::from_level_index(5),
771 Some(ColorSize::Blue(Size::Small))
772 );
773 assert_eq!(
774 ColorSize::from_level_index(6),
775 Some(ColorSize::Blue(Size::Large))
776 );
777 assert_eq!(ColorSize::from_level_index(0), None);
778 assert_eq!(ColorSize::from_level_index(7), None);
779 }
780
781 #[test]
782 fn test_interaction_roundtrip() {
783 for i in 1..=6 {
784 let color_size = ColorSize::from_level_index(i).unwrap();
785 assert_eq!(color_size.to_level_index(), i);
786 }
787 }
788}
789