miniextendr_api/altrep_data/
builtins.rs1use std::borrow::Cow;
13use std::ops::Range;
14
15use crate::altrep_traits::NA_REAL;
16use crate::ffi::{Rcomplex, SEXP};
17
18use super::{
19 AltComplexData, AltIntegerData, AltLogicalData, AltRawData, AltRealData, AltStringData,
20 AltrepDataptr, AltrepLen, AltrepSerialize, Logical, Sortedness,
21};
22
23macro_rules! impl_len_vec {
27 ($elem:ty) => {
28 impl AltrepLen for Vec<$elem> {
29 fn len(&self) -> usize {
30 Vec::len(self)
31 }
32 }
33 };
34}
35
36macro_rules! impl_len_boxed {
38 ($elem:ty) => {
39 impl AltrepLen for Box<[$elem]> {
40 fn len(&self) -> usize {
41 <[$elem]>::len(self)
42 }
43 }
44 };
45}
46
47macro_rules! impl_len_array {
49 ($elem:ty) => {
50 impl<const N: usize> AltrepLen for [$elem; N] {
51 fn len(&self) -> usize {
52 N
53 }
54 }
55 };
56}
57
58macro_rules! impl_len_slice {
60 ($elem:ty) => {
61 impl AltrepLen for &[$elem] {
62 fn len(&self) -> usize {
63 <[$elem]>::len(self)
64 }
65 }
66 };
67}
68
69macro_rules! impl_dataptr_vec {
71 ($elem:ty) => {
72 impl AltrepDataptr<$elem> for Vec<$elem> {
73 fn dataptr(&mut self, _writable: bool) -> Option<*mut $elem> {
74 Some(self.as_mut_ptr())
75 }
76
77 fn dataptr_or_null(&self) -> Option<*const $elem> {
78 Some(self.as_ptr())
79 }
80 }
81 };
82}
83
84macro_rules! impl_dataptr_boxed {
86 ($elem:ty) => {
87 impl AltrepDataptr<$elem> for Box<[$elem]> {
88 fn dataptr(&mut self, _writable: bool) -> Option<*mut $elem> {
89 Some(self.as_mut_ptr())
90 }
91
92 fn dataptr_or_null(&self) -> Option<*const $elem> {
93 Some(self.as_ptr())
94 }
95 }
96 };
97}
98
99macro_rules! impl_serialize {
104 ($ty:ty) => {
105 impl AltrepSerialize for $ty {
106 fn serialized_state(&self) -> SEXP {
107 use crate::into_r::IntoR;
108 self.clone().into_sexp()
109 }
110
111 fn unserialize(state: SEXP) -> Option<Self> {
112 use crate::from_r::TryFromSexp;
113 <$ty>::try_from_sexp(state).ok()
114 }
115 }
116 };
117}
118impl_serialize!(Vec<i32>);
123impl_serialize!(Vec<f64>);
124impl_serialize!(Vec<u8>);
125impl_serialize!(Vec<bool>);
126impl_serialize!(Vec<String>);
127impl_serialize!(Vec<Option<String>>);
128impl_serialize!(Vec<Rcomplex>);
129impl_serialize!(Vec<std::borrow::Cow<'static, str>>);
132impl_serialize!(Vec<Option<std::borrow::Cow<'static, str>>>);
133impl AltrepSerialize for Box<[i32]> {
141 fn serialized_state(&self) -> SEXP {
142 use crate::into_r::IntoR;
143 self.to_vec().into_sexp()
144 }
145
146 fn unserialize(state: SEXP) -> Option<Self> {
147 use crate::from_r::TryFromSexp;
148 Vec::<i32>::try_from_sexp(state)
149 .ok()
150 .map(|v| v.into_boxed_slice())
151 }
152}
153
154impl AltrepSerialize for Box<[f64]> {
155 fn serialized_state(&self) -> SEXP {
156 use crate::into_r::IntoR;
157 self.to_vec().into_sexp()
158 }
159
160 fn unserialize(state: SEXP) -> Option<Self> {
161 use crate::from_r::TryFromSexp;
162 Vec::<f64>::try_from_sexp(state)
163 .ok()
164 .map(|v| v.into_boxed_slice())
165 }
166}
167
168impl AltrepSerialize for Box<[u8]> {
169 fn serialized_state(&self) -> SEXP {
170 use crate::into_r::IntoR;
171 self.to_vec().into_sexp()
172 }
173
174 fn unserialize(state: SEXP) -> Option<Self> {
175 use crate::from_r::TryFromSexp;
176 Vec::<u8>::try_from_sexp(state)
177 .ok()
178 .map(|v| v.into_boxed_slice())
179 }
180}
181
182impl AltrepSerialize for Box<[bool]> {
183 fn serialized_state(&self) -> SEXP {
184 use crate::into_r::IntoR;
185 self.to_vec().into_sexp()
186 }
187
188 fn unserialize(state: SEXP) -> Option<Self> {
189 use crate::from_r::TryFromSexp;
190 Vec::<bool>::try_from_sexp(state)
191 .ok()
192 .map(|v| v.into_boxed_slice())
193 }
194}
195
196impl AltrepSerialize for Box<[String]> {
197 fn serialized_state(&self) -> SEXP {
198 use crate::into_r::IntoR;
199 self.to_vec().into_sexp()
200 }
201
202 fn unserialize(state: SEXP) -> Option<Self> {
203 use crate::from_r::TryFromSexp;
204 Vec::<String>::try_from_sexp(state)
205 .ok()
206 .map(|v| v.into_boxed_slice())
207 }
208}
209
210impl AltrepSerialize for Box<[Rcomplex]> {
211 fn serialized_state(&self) -> SEXP {
212 use crate::into_r::IntoR;
213 self.to_vec().into_sexp()
214 }
215
216 fn unserialize(state: SEXP) -> Option<Self> {
217 use crate::from_r::TryFromSexp;
218 Vec::<Rcomplex>::try_from_sexp(state)
219 .ok()
220 .map(|v| v.into_boxed_slice())
221 }
222}
223impl_len_vec!(i32);
228
229impl AltIntegerData for Vec<i32> {
230 fn elt(&self, i: usize) -> i32 {
231 self[i]
232 }
233
234 fn as_slice(&self) -> Option<&[i32]> {
235 Some(self.as_slice())
236 }
237
238 fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
239 let end = (start + len).min(self.len());
240 let actual_len = end.saturating_sub(start);
241 if actual_len > 0 {
242 buf[..actual_len].copy_from_slice(&self[start..end]);
243 }
244 actual_len
245 }
246
247 fn no_na(&self) -> Option<bool> {
248 Some(!self.contains(&i32::MIN))
249 }
250
251 fn sum(&self, na_rm: bool) -> Option<i64> {
252 let mut sum: i64 = 0;
253 for &x in self.iter() {
254 if x == i32::MIN {
255 if !na_rm {
256 return None; }
258 } else {
259 sum += x as i64;
260 }
261 }
262 Some(sum)
263 }
264
265 fn min(&self, na_rm: bool) -> Option<i32> {
266 let mut min = i32::MAX;
267 let mut found = false;
268 for &x in self.iter() {
269 if x == i32::MIN {
270 if !na_rm {
271 return None;
272 }
273 } else {
274 found = true;
275 min = min.min(x);
276 }
277 }
278 if found { Some(min) } else { None }
279 }
280
281 fn max(&self, na_rm: bool) -> Option<i32> {
282 let mut max = i32::MIN + 1; let mut found = false;
284 for &x in self.iter() {
285 if x == i32::MIN {
286 if !na_rm {
287 return None;
288 }
289 } else {
290 found = true;
291 max = max.max(x);
292 }
293 }
294 if found { Some(max) } else { None }
295 }
296}
297
298impl_dataptr_vec!(i32);
299
300impl_len_vec!(f64);
301
302impl AltRealData for Vec<f64> {
303 fn elt(&self, i: usize) -> f64 {
304 self[i]
305 }
306
307 fn as_slice(&self) -> Option<&[f64]> {
308 Some(self.as_slice())
309 }
310
311 fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
312 let end = (start + len).min(self.len());
313 let actual_len = end.saturating_sub(start);
314 if actual_len > 0 {
315 buf[..actual_len].copy_from_slice(&self[start..end]);
316 }
317 actual_len
318 }
319
320 fn no_na(&self) -> Option<bool> {
321 Some(!self.iter().any(|x| x.to_bits() == NA_REAL.to_bits()))
323 }
324
325 fn sum(&self, na_rm: bool) -> Option<f64> {
326 let mut sum = 0.0;
327 for &x in self.iter() {
328 if x.to_bits() == NA_REAL.to_bits() {
329 if !na_rm {
331 return Some(NA_REAL);
332 }
333 } else if x.is_nan() {
334 if !na_rm {
336 return Some(f64::NAN);
337 }
338 } else {
339 sum += x;
340 }
341 }
342 Some(sum)
343 }
344
345 fn min(&self, na_rm: bool) -> Option<f64> {
346 let mut min = f64::INFINITY;
347 let mut found = false;
348 for &x in self.iter() {
349 if x.to_bits() == NA_REAL.to_bits() {
350 if !na_rm {
351 return Some(NA_REAL);
352 }
353 } else if x.is_nan() {
354 if !na_rm {
355 return Some(f64::NAN);
356 }
357 } else {
358 found = true;
359 min = min.min(x);
360 }
361 }
362 if found { Some(min) } else { None }
363 }
364
365 fn max(&self, na_rm: bool) -> Option<f64> {
366 let mut max = f64::NEG_INFINITY;
367 let mut found = false;
368 for &x in self.iter() {
369 if x.to_bits() == NA_REAL.to_bits() {
370 if !na_rm {
371 return Some(NA_REAL);
372 }
373 } else if x.is_nan() {
374 if !na_rm {
375 return Some(f64::NAN);
376 }
377 } else {
378 found = true;
379 max = max.max(x);
380 }
381 }
382 if found { Some(max) } else { None }
383 }
384}
385
386impl_dataptr_vec!(f64);
387
388impl_len_vec!(u8);
389
390impl AltRawData for Vec<u8> {
391 fn elt(&self, i: usize) -> u8 {
392 self[i]
393 }
394
395 fn as_slice(&self) -> Option<&[u8]> {
396 Some(self.as_slice())
397 }
398
399 fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
400 let end = (start + len).min(self.len());
401 let actual_len = end.saturating_sub(start);
402 if actual_len > 0 {
403 buf[..actual_len].copy_from_slice(&self[start..end]);
404 }
405 actual_len
406 }
407}
408
409impl_dataptr_vec!(u8);
410
411impl_len_vec!(String);
412
413impl AltStringData for Vec<String> {
414 fn elt(&self, i: usize) -> Option<&str> {
415 Some(self[i].as_str())
416 }
417
418 fn no_na(&self) -> Option<bool> {
419 Some(true) }
421}
422
423impl_len_vec!(Option<String>);
424
425impl AltStringData for Vec<Option<String>> {
426 fn elt(&self, i: usize) -> Option<&str> {
427 self[i].as_deref()
428 }
429
430 fn no_na(&self) -> Option<bool> {
431 Some(!self.iter().any(|x| x.is_none()))
432 }
433}
434
435impl AltrepLen for Vec<std::borrow::Cow<'static, str>> {
436 fn len(&self) -> usize {
437 self.len()
438 }
439}
440
441impl AltStringData for Vec<std::borrow::Cow<'static, str>> {
442 fn elt(&self, i: usize) -> Option<&str> {
443 Some(self[i].as_ref())
444 }
445
446 fn no_na(&self) -> Option<bool> {
447 Some(true) }
449}
450
451impl AltrepLen for Vec<Option<std::borrow::Cow<'static, str>>> {
452 fn len(&self) -> usize {
453 self.len()
454 }
455}
456
457impl AltStringData for Vec<Option<std::borrow::Cow<'static, str>>> {
458 fn elt(&self, i: usize) -> Option<&str> {
459 self[i].as_deref()
460 }
461
462 fn no_na(&self) -> Option<bool> {
463 Some(!self.iter().any(|x| x.is_none()))
464 }
465}
466
467impl_len_vec!(bool);
468
469impl AltLogicalData for Vec<bool> {
470 fn elt(&self, i: usize) -> Logical {
471 if self[i] {
472 Logical::True
473 } else {
474 Logical::False
475 }
476 }
477
478 fn no_na(&self) -> Option<bool> {
479 Some(true) }
481
482 fn sum(&self, _na_rm: bool) -> Option<i64> {
483 Some(self.iter().filter(|&&x| x).count() as i64)
484 }
485}
486impl_len_boxed!(i32);
502
503impl AltIntegerData for Box<[i32]> {
504 fn elt(&self, i: usize) -> i32 {
505 self[i]
506 }
507
508 fn as_slice(&self) -> Option<&[i32]> {
509 Some(self)
510 }
511
512 fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
513 let end = (start + len).min(<[i32]>::len(self));
514 let actual_len = end.saturating_sub(start);
515 if actual_len > 0 {
516 buf[..actual_len].copy_from_slice(&self[start..end]);
517 }
518 actual_len
519 }
520
521 fn no_na(&self) -> Option<bool> {
522 Some(!self.contains(&i32::MIN))
523 }
524
525 fn sum(&self, na_rm: bool) -> Option<i64> {
526 let mut sum: i64 = 0;
527 for &x in self.iter() {
528 if x == i32::MIN {
529 if !na_rm {
530 return None;
531 }
532 } else {
533 sum += x as i64;
534 }
535 }
536 Some(sum)
537 }
538
539 fn min(&self, na_rm: bool) -> Option<i32> {
540 let mut min = i32::MAX;
541 let mut found = false;
542 for &x in self.iter() {
543 if x == i32::MIN {
544 if !na_rm {
545 return None;
546 }
547 } else {
548 found = true;
549 min = min.min(x);
550 }
551 }
552 if found { Some(min) } else { None }
553 }
554
555 fn max(&self, na_rm: bool) -> Option<i32> {
556 let mut max = i32::MIN + 1; let mut found = false;
558 for &x in self.iter() {
559 if x == i32::MIN {
560 if !na_rm {
561 return None;
562 }
563 } else {
564 found = true;
565 max = max.max(x);
566 }
567 }
568 if found { Some(max) } else { None }
569 }
570}
571
572impl_dataptr_boxed!(i32);
573
574impl_len_boxed!(f64);
575
576impl AltRealData for Box<[f64]> {
577 fn elt(&self, i: usize) -> f64 {
578 self[i]
579 }
580
581 fn as_slice(&self) -> Option<&[f64]> {
582 Some(self)
583 }
584
585 fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
586 let end = (start + len).min(<[f64]>::len(self));
587 let actual_len = end.saturating_sub(start);
588 if actual_len > 0 {
589 buf[..actual_len].copy_from_slice(&self[start..end]);
590 }
591 actual_len
592 }
593
594 fn no_na(&self) -> Option<bool> {
595 Some(!self.iter().any(|x| x.to_bits() == NA_REAL.to_bits()))
596 }
597
598 fn sum(&self, na_rm: bool) -> Option<f64> {
599 let mut sum = 0.0;
600 for &x in self.iter() {
601 if x.to_bits() == NA_REAL.to_bits() {
602 if !na_rm {
603 return Some(NA_REAL);
604 }
605 } else if x.is_nan() {
606 if !na_rm {
607 return Some(f64::NAN);
608 }
609 } else {
610 sum += x;
611 }
612 }
613 Some(sum)
614 }
615
616 fn min(&self, na_rm: bool) -> Option<f64> {
617 let mut min = f64::INFINITY;
618 let mut found = false;
619 for &x in self.iter() {
620 if x.to_bits() == NA_REAL.to_bits() {
621 if !na_rm {
622 return Some(NA_REAL);
623 }
624 } else if x.is_nan() {
625 if !na_rm {
626 return Some(f64::NAN);
627 }
628 } else {
629 found = true;
630 min = min.min(x);
631 }
632 }
633 if found { Some(min) } else { None }
634 }
635
636 fn max(&self, na_rm: bool) -> Option<f64> {
637 let mut max = f64::NEG_INFINITY;
638 let mut found = false;
639 for &x in self.iter() {
640 if x.to_bits() == NA_REAL.to_bits() {
641 if !na_rm {
642 return Some(NA_REAL);
643 }
644 } else if x.is_nan() {
645 if !na_rm {
646 return Some(f64::NAN);
647 }
648 } else {
649 found = true;
650 max = max.max(x);
651 }
652 }
653 if found { Some(max) } else { None }
654 }
655}
656
657impl_dataptr_boxed!(f64);
658
659impl_len_boxed!(u8);
660
661impl AltRawData for Box<[u8]> {
662 fn elt(&self, i: usize) -> u8 {
663 self[i]
664 }
665
666 fn as_slice(&self) -> Option<&[u8]> {
667 Some(self)
668 }
669
670 fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
671 let end = (start + len).min(<[u8]>::len(self));
672 let actual_len = end.saturating_sub(start);
673 if actual_len > 0 {
674 buf[..actual_len].copy_from_slice(&self[start..end]);
675 }
676 actual_len
677 }
678}
679
680impl_dataptr_boxed!(u8);
681
682impl_len_boxed!(bool);
683
684impl AltLogicalData for Box<[bool]> {
685 fn elt(&self, i: usize) -> Logical {
686 if self[i] {
687 Logical::True
688 } else {
689 Logical::False
690 }
691 }
692
693 fn no_na(&self) -> Option<bool> {
694 Some(true) }
696
697 fn sum(&self, _na_rm: bool) -> Option<i64> {
698 Some(self.iter().filter(|&&x| x).count() as i64)
699 }
700}
701
702impl_len_boxed!(String);
703
704impl AltStringData for Box<[String]> {
705 fn elt(&self, i: usize) -> Option<&str> {
706 Some(self[i].as_str())
707 }
708
709 fn no_na(&self) -> Option<bool> {
710 Some(true) }
712}
713impl AltrepSerialize for Range<i32> {
719 fn serialized_state(&self) -> SEXP {
720 use crate::into_r::IntoR;
721 vec![self.start, self.end].into_sexp()
722 }
723
724 fn unserialize(state: SEXP) -> Option<Self> {
725 use crate::from_r::TryFromSexp;
726 let v = Vec::<i32>::try_from_sexp(state).ok()?;
727 if v.len() == 2 { Some(v[0]..v[1]) } else { None }
728 }
729}
730
731impl AltrepSerialize for Range<i64> {
732 fn serialized_state(&self) -> SEXP {
733 use crate::into_r::IntoR;
734 vec![
737 f64::from_bits(self.start as u64),
738 f64::from_bits(self.end as u64),
739 ]
740 .into_sexp()
741 }
742
743 fn unserialize(state: SEXP) -> Option<Self> {
744 use crate::from_r::TryFromSexp;
745 let v = Vec::<f64>::try_from_sexp(state).ok()?;
746 if v.len() == 2 {
747 Some((v[0].to_bits() as i64)..(v[1].to_bits() as i64))
748 } else {
749 None
750 }
751 }
752}
753
754impl AltrepSerialize for Range<f64> {
755 fn serialized_state(&self) -> SEXP {
756 use crate::into_r::IntoR;
757 vec![self.start, self.end].into_sexp()
758 }
759
760 fn unserialize(state: SEXP) -> Option<Self> {
761 use crate::from_r::TryFromSexp;
762 let v = Vec::<f64>::try_from_sexp(state).ok()?;
763 if v.len() == 2 { Some(v[0]..v[1]) } else { None }
764 }
765}
766impl AltrepLen for Range<i32> {
771 fn len(&self) -> usize {
772 if self.end > self.start {
773 (self.end - self.start) as usize
774 } else {
775 0
776 }
777 }
778}
779
780impl AltIntegerData for Range<i32> {
781 fn elt(&self, i: usize) -> i32 {
782 self.start + i as i32
783 }
784
785 fn is_sorted(&self) -> Option<Sortedness> {
786 Some(Sortedness::Increasing)
787 }
788
789 fn no_na(&self) -> Option<bool> {
790 let contains_na = self.start == i32::MIN && self.end > i32::MIN;
794 Some(!contains_na)
795 }
796
797 fn sum(&self, na_rm: bool) -> Option<i64> {
798 let n = AltrepLen::len(self) as i64;
799 if n == 0 {
800 return Some(0);
801 }
802
803 let contains_na = self.start == i32::MIN && self.end > i32::MIN;
805 if contains_na && !na_rm {
806 return None; }
808
809 if contains_na {
812 let n_valid = n - 1;
814 if n_valid == 0 {
815 return Some(0);
816 }
817 let first = (self.start + 1) as i64;
818 let last = (self.end - 1) as i64;
819 Some(n_valid * (first + last) / 2)
820 } else {
821 let first = self.start as i64;
822 let last = (self.end - 1) as i64;
823 Some(n * (first + last) / 2)
824 }
825 }
826
827 fn min(&self, na_rm: bool) -> Option<i32> {
828 if AltrepLen::len(self) == 0 {
829 return None;
830 }
831
832 if self.start == i32::MIN {
834 if na_rm {
835 if self.end > self.start + 1 {
837 Some(self.start + 1)
838 } else {
839 None }
841 } else {
842 None }
844 } else {
845 Some(self.start)
846 }
847 }
848
849 fn max(&self, na_rm: bool) -> Option<i32> {
850 if AltrepLen::len(self) == 0 {
851 return None;
852 }
853
854 let contains_na = self.start == i32::MIN && self.end > i32::MIN;
857 if contains_na && !na_rm {
858 return None; }
860
861 Some(self.end - 1)
864 }
865}
866
867impl AltrepLen for Range<i64> {
868 fn len(&self) -> usize {
869 if self.end > self.start {
870 (self.end - self.start) as usize
871 } else {
872 0
873 }
874 }
875}
876
877impl AltIntegerData for Range<i64> {
878 fn elt(&self, i: usize) -> i32 {
879 let val = self.start.saturating_add(i as i64);
880 if val > i32::MAX as i64 || val <= i32::MIN as i64 {
883 crate::altrep_traits::NA_INTEGER
884 } else {
885 val as i32
886 }
887 }
888
889 fn is_sorted(&self) -> Option<Sortedness> {
890 Some(Sortedness::Increasing)
891 }
892
893 fn no_na(&self) -> Option<bool> {
894 let na_sentinel = i32::MIN as i64;
904 let i32_max = i32::MAX as i64;
905
906 let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
908
909 let has_underflow = self.start < na_sentinel;
912 let has_overflow = (self.end - 1) > i32_max;
913
914 Some(!contains_na_sentinel && !has_underflow && !has_overflow)
915 }
916
917 fn sum(&self, na_rm: bool) -> Option<i64> {
918 let n = AltrepLen::len(self) as i64;
919 if n == 0 {
920 return Some(0);
921 }
922
923 let na_sentinel = i32::MIN as i64;
925 let i32_max = i32::MAX as i64;
926 let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
927 let has_underflow = self.start < na_sentinel;
928 let has_overflow = (self.end - 1) > i32_max;
929 let has_na = contains_na_sentinel || has_underflow || has_overflow;
930
931 if has_na && !na_rm {
932 return None; }
934
935 if has_na {
936 return None;
939 }
940
941 let first = self.start;
942 let last = self.end - 1;
943
944 let sum_endpoints = first.checked_add(last)?;
947 let product = n.checked_mul(sum_endpoints)?;
948 Some(product / 2)
949 }
950
951 fn min(&self, na_rm: bool) -> Option<i32> {
952 if AltrepLen::len(self) == 0 {
953 return None;
954 }
955
956 let na_sentinel = i32::MIN as i64;
957 let i32_max = i32::MAX as i64;
958
959 let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
961 let has_underflow = self.start < na_sentinel;
962 let has_overflow = (self.end - 1) > i32_max;
963 let has_na = contains_na_sentinel || has_underflow || has_overflow;
964
965 if has_na && !na_rm {
966 return None; }
968
969 if has_na {
970 return None;
973 }
974
975 Some(self.start as i32)
977 }
978
979 fn max(&self, na_rm: bool) -> Option<i32> {
980 if AltrepLen::len(self) == 0 {
981 return None;
982 }
983
984 let na_sentinel = i32::MIN as i64;
985 let i32_max = i32::MAX as i64;
986
987 let contains_na_sentinel = self.start <= na_sentinel && self.end > na_sentinel;
989 let has_underflow = self.start < na_sentinel;
990 let has_overflow = (self.end - 1) > i32_max;
991 let has_na = contains_na_sentinel || has_underflow || has_overflow;
992
993 if has_na && !na_rm {
994 return None; }
996
997 if has_na {
998 return None;
1001 }
1002
1003 Some((self.end - 1) as i32)
1005 }
1006}
1007
1008impl AltrepLen for Range<f64> {
1009 fn len(&self) -> usize {
1010 if self.end > self.start {
1012 (self.end - self.start).ceil() as usize
1013 } else {
1014 0
1015 }
1016 }
1017}
1018
1019impl AltRealData for Range<f64> {
1020 fn elt(&self, i: usize) -> f64 {
1021 self.start + i as f64
1022 }
1023
1024 fn is_sorted(&self) -> Option<Sortedness> {
1025 Some(Sortedness::Increasing)
1026 }
1027
1028 fn no_na(&self) -> Option<bool> {
1029 Some(true)
1030 }
1031
1032 fn sum(&self, _na_rm: bool) -> Option<f64> {
1033 let n = AltrepLen::len(self) as f64;
1034 if n == 0.0 {
1035 return Some(0.0);
1036 }
1037 let first = self.start;
1038 let last = self.start + (n - 1.0);
1039 Some(n * (first + last) / 2.0)
1040 }
1041
1042 fn min(&self, _na_rm: bool) -> Option<f64> {
1043 if AltrepLen::len(self) > 0 {
1044 Some(self.start)
1045 } else {
1046 None
1047 }
1048 }
1049
1050 fn max(&self, _na_rm: bool) -> Option<f64> {
1051 if AltrepLen::len(self) > 0 {
1052 Some(self.start + (AltrepLen::len(self) - 1) as f64)
1053 } else {
1054 None
1055 }
1056 }
1057}
1058impl_len_slice!(i32);
1063
1064impl AltIntegerData for &[i32] {
1065 fn elt(&self, i: usize) -> i32 {
1066 self[i]
1067 }
1068
1069 fn as_slice(&self) -> Option<&[i32]> {
1070 Some(self)
1071 }
1072
1073 fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
1074 let end = (start + len).min(<[i32]>::len(self));
1075 let actual_len = end.saturating_sub(start);
1076 if actual_len > 0 {
1077 buf[..actual_len].copy_from_slice(&self[start..end]);
1078 }
1079 actual_len
1080 }
1081
1082 fn no_na(&self) -> Option<bool> {
1083 Some(!self.contains(&i32::MIN))
1085 }
1086
1087 fn sum(&self, _na_rm: bool) -> Option<i64> {
1088 if self.contains(&i32::MIN) {
1090 if _na_rm {
1091 Some(
1092 self.iter()
1093 .filter(|&&x| x != i32::MIN)
1094 .map(|&x| x as i64)
1095 .sum(),
1096 )
1097 } else {
1098 None }
1100 } else {
1101 Some(self.iter().map(|&x| x as i64).sum())
1102 }
1103 }
1104
1105 fn min(&self, _na_rm: bool) -> Option<i32> {
1106 if self.is_empty() {
1107 return None;
1108 }
1109 if _na_rm {
1110 self.iter().filter(|&&x| x != i32::MIN).copied().min()
1111 } else if self.contains(&i32::MIN) {
1112 None } else {
1114 self.iter().copied().min()
1115 }
1116 }
1117
1118 fn max(&self, _na_rm: bool) -> Option<i32> {
1119 if self.is_empty() {
1120 return None;
1121 }
1122 if _na_rm {
1123 self.iter().filter(|&&x| x != i32::MIN).copied().max()
1124 } else if self.contains(&i32::MIN) {
1125 None } else {
1127 self.iter().copied().max()
1128 }
1129 }
1130}
1131
1132impl_len_slice!(f64);
1133
1134impl AltRealData for &[f64] {
1135 fn elt(&self, i: usize) -> f64 {
1136 self[i]
1137 }
1138
1139 fn as_slice(&self) -> Option<&[f64]> {
1140 Some(self)
1141 }
1142
1143 fn no_na(&self) -> Option<bool> {
1144 Some(!self.iter().any(|x| x.to_bits() == NA_REAL.to_bits()))
1145 }
1146
1147 fn sum(&self, na_rm: bool) -> Option<f64> {
1148 let mut sum = 0.0;
1149 for &x in self.iter() {
1150 if x.to_bits() == NA_REAL.to_bits() {
1151 if !na_rm {
1152 return Some(NA_REAL);
1153 }
1154 } else if x.is_nan() {
1155 if !na_rm {
1156 return Some(f64::NAN);
1157 }
1158 } else {
1159 sum += x;
1160 }
1161 }
1162 Some(sum)
1163 }
1164
1165 fn min(&self, na_rm: bool) -> Option<f64> {
1166 let mut min = f64::INFINITY;
1167 let mut found = false;
1168 for &x in self.iter() {
1169 if x.to_bits() == NA_REAL.to_bits() {
1170 if !na_rm {
1171 return Some(NA_REAL);
1172 }
1173 } else if x.is_nan() {
1174 if !na_rm {
1175 return Some(f64::NAN);
1176 }
1177 } else {
1178 found = true;
1179 min = min.min(x);
1180 }
1181 }
1182 if found { Some(min) } else { None }
1183 }
1184
1185 fn max(&self, na_rm: bool) -> Option<f64> {
1186 let mut max = f64::NEG_INFINITY;
1187 let mut found = false;
1188 for &x in self.iter() {
1189 if x.to_bits() == NA_REAL.to_bits() {
1190 if !na_rm {
1191 return Some(NA_REAL);
1192 }
1193 } else if x.is_nan() {
1194 if !na_rm {
1195 return Some(f64::NAN);
1196 }
1197 } else {
1198 found = true;
1199 max = max.max(x);
1200 }
1201 }
1202 if found { Some(max) } else { None }
1203 }
1204}
1205
1206impl_len_slice!(u8);
1207
1208impl AltRawData for &[u8] {
1209 fn elt(&self, i: usize) -> u8 {
1210 self[i]
1211 }
1212
1213 fn as_slice(&self) -> Option<&[u8]> {
1214 Some(self)
1215 }
1216}
1217
1218impl_len_slice!(bool);
1219
1220impl AltLogicalData for &[bool] {
1221 fn elt(&self, i: usize) -> Logical {
1222 Logical::from_bool(self[i])
1223 }
1224
1225 fn no_na(&self) -> Option<bool> {
1226 Some(true) }
1228
1229 fn sum(&self, _na_rm: bool) -> Option<i64> {
1230 Some(self.iter().filter(|&&x| x).count() as i64)
1231 }
1232}
1233
1234impl_len_slice!(String);
1235
1236impl AltStringData for &[String] {
1237 fn elt(&self, i: usize) -> Option<&str> {
1238 Some(self[i].as_str())
1239 }
1240}
1241
1242impl_len_slice!(&str);
1243
1244impl AltStringData for &[&str] {
1245 fn elt(&self, i: usize) -> Option<&str> {
1246 Some(self[i])
1247 }
1248}
1249impl_len_array!(i32);
1269
1270impl<const N: usize> AltIntegerData for [i32; N] {
1271 fn elt(&self, i: usize) -> i32 {
1272 self[i]
1273 }
1274
1275 fn as_slice(&self) -> Option<&[i32]> {
1276 Some(self.as_slice())
1277 }
1278
1279 fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
1280 let end = (start + len).min(N);
1281 let actual_len = end.saturating_sub(start);
1282 if actual_len > 0 {
1283 buf[..actual_len].copy_from_slice(&self[start..end]);
1284 }
1285 actual_len
1286 }
1287
1288 fn no_na(&self) -> Option<bool> {
1289 Some(!self.contains(&i32::MIN))
1290 }
1291}
1292
1293impl_len_array!(f64);
1294
1295impl<const N: usize> AltRealData for [f64; N] {
1296 fn elt(&self, i: usize) -> f64 {
1297 self[i]
1298 }
1299
1300 fn as_slice(&self) -> Option<&[f64]> {
1301 Some(self.as_slice())
1302 }
1303
1304 fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
1305 let end = (start + len).min(N);
1306 let actual_len = end.saturating_sub(start);
1307 if actual_len > 0 {
1308 buf[..actual_len].copy_from_slice(&self[start..end]);
1309 }
1310 actual_len
1311 }
1312
1313 fn no_na(&self) -> Option<bool> {
1314 Some(!self.iter().any(|x| x.to_bits() == NA_REAL.to_bits()))
1315 }
1316}
1317
1318impl_len_array!(bool);
1319
1320impl<const N: usize> AltLogicalData for [bool; N] {
1321 fn elt(&self, i: usize) -> Logical {
1322 Logical::from_bool(self[i])
1323 }
1324
1325 fn no_na(&self) -> Option<bool> {
1326 Some(true) }
1328}
1329
1330impl_len_array!(u8);
1331
1332impl<const N: usize> AltRawData for [u8; N] {
1333 fn elt(&self, i: usize) -> u8 {
1334 self[i]
1335 }
1336
1337 fn as_slice(&self) -> Option<&[u8]> {
1338 Some(self.as_slice())
1339 }
1340
1341 fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
1342 let end = (start + len).min(N);
1343 let actual_len = end.saturating_sub(start);
1344 if actual_len > 0 {
1345 buf[..actual_len].copy_from_slice(&self[start..end]);
1346 }
1347 actual_len
1348 }
1349}
1350
1351impl_len_array!(String);
1352
1353impl<const N: usize> AltStringData for [String; N] {
1354 fn elt(&self, i: usize) -> Option<&str> {
1355 Some(self[i].as_str())
1356 }
1357}
1358impl_len_vec!(Rcomplex);
1363
1364impl AltComplexData for Vec<Rcomplex> {
1365 fn elt(&self, i: usize) -> Rcomplex {
1366 self[i]
1367 }
1368
1369 fn as_slice(&self) -> Option<&[Rcomplex]> {
1370 Some(self.as_slice())
1371 }
1372
1373 fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex]) -> usize {
1374 let end = (start + len).min(self.len());
1375 let actual_len = end.saturating_sub(start);
1376 if actual_len > 0 {
1377 buf[..actual_len].copy_from_slice(&self[start..end]);
1378 }
1379 actual_len
1380 }
1381}
1382
1383impl_dataptr_vec!(Rcomplex);
1384impl_len_boxed!(Rcomplex);
1389
1390impl AltComplexData for Box<[Rcomplex]> {
1391 fn elt(&self, i: usize) -> Rcomplex {
1392 self[i]
1393 }
1394
1395 fn as_slice(&self) -> Option<&[Rcomplex]> {
1396 Some(self.as_ref())
1397 }
1398
1399 fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex]) -> usize {
1400 let end = (start + len).min(self.len());
1401 let actual_len = end.saturating_sub(start);
1402 if actual_len > 0 {
1403 buf[..actual_len].copy_from_slice(&self[start..end]);
1404 }
1405 actual_len
1406 }
1407}
1408
1409impl_dataptr_boxed!(Rcomplex);
1410impl_len_array!(Rcomplex);
1415
1416impl<const N: usize> AltComplexData for [Rcomplex; N] {
1417 fn elt(&self, i: usize) -> Rcomplex {
1418 self[i]
1419 }
1420
1421 fn as_slice(&self) -> Option<&[Rcomplex]> {
1422 Some(self.as_slice())
1423 }
1424
1425 fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex]) -> usize {
1426 let end = (start + len).min(N);
1427 let actual_len = end.saturating_sub(start);
1428 if actual_len > 0 {
1429 buf[..actual_len].copy_from_slice(&self[start..end]);
1430 }
1431 actual_len
1432 }
1433}
1434macro_rules! impl_len_cow {
1444 ($elem:ty) => {
1445 impl AltrepLen for Cow<'static, [$elem]> {
1446 fn len(&self) -> usize {
1447 <[$elem]>::len(self)
1448 }
1449 }
1450 };
1451}
1452
1453macro_rules! impl_dataptr_cow {
1454 ($elem:ty) => {
1455 impl AltrepDataptr<$elem> for Cow<'static, [$elem]> {
1456 fn dataptr(&mut self, writable: bool) -> Option<*mut $elem> {
1457 if writable {
1458 Some(self.to_mut().as_mut_ptr())
1461 } else {
1462 Some(self.as_ptr().cast_mut())
1465 }
1466 }
1467
1468 fn dataptr_or_null(&self) -> Option<*const $elem> {
1469 Some(self.as_ptr())
1470 }
1471 }
1472 };
1473}
1474
1475macro_rules! impl_serialize_cow {
1476 ($elem:ty) => {
1477 impl AltrepSerialize for Cow<'static, [$elem]> {
1478 fn serialized_state(&self) -> SEXP {
1479 use crate::into_r::IntoR;
1480 self.clone().into_sexp()
1481 }
1482
1483 fn unserialize(state: SEXP) -> Option<Self> {
1484 use crate::from_r::TryFromSexp;
1485 Cow::<'static, [$elem]>::try_from_sexp(state).ok()
1486 }
1487 }
1488 };
1489}
1490
1491impl_len_cow!(i32);
1492
1493impl AltIntegerData for Cow<'static, [i32]> {
1494 fn elt(&self, i: usize) -> i32 {
1495 self[i]
1496 }
1497
1498 fn as_slice(&self) -> Option<&[i32]> {
1499 Some(self.as_ref())
1500 }
1501
1502 fn get_region(&self, start: usize, len: usize, buf: &mut [i32]) -> usize {
1503 let end = (start + len).min(<[i32]>::len(self));
1504 let actual_len = end.saturating_sub(start);
1505 if actual_len > 0 {
1506 buf[..actual_len].copy_from_slice(&self[start..end]);
1507 }
1508 actual_len
1509 }
1510
1511 fn no_na(&self) -> Option<bool> {
1512 Some(!self.contains(&i32::MIN))
1513 }
1514
1515 fn sum(&self, na_rm: bool) -> Option<i64> {
1516 let mut sum: i64 = 0;
1517 for &x in self.iter() {
1518 if x == i32::MIN {
1519 if !na_rm {
1520 return None;
1521 }
1522 } else {
1523 sum += x as i64;
1524 }
1525 }
1526 Some(sum)
1527 }
1528
1529 fn min(&self, na_rm: bool) -> Option<i32> {
1530 let mut min = i32::MAX;
1531 let mut found = false;
1532 for &x in self.iter() {
1533 if x == i32::MIN {
1534 if !na_rm {
1535 return None;
1536 }
1537 } else {
1538 found = true;
1539 min = min.min(x);
1540 }
1541 }
1542 if found { Some(min) } else { None }
1543 }
1544
1545 fn max(&self, na_rm: bool) -> Option<i32> {
1546 let mut max = i32::MIN + 1;
1547 let mut found = false;
1548 for &x in self.iter() {
1549 if x == i32::MIN {
1550 if !na_rm {
1551 return None;
1552 }
1553 } else {
1554 found = true;
1555 max = max.max(x);
1556 }
1557 }
1558 if found { Some(max) } else { None }
1559 }
1560}
1561
1562impl_dataptr_cow!(i32);
1563impl_serialize_cow!(i32);
1564
1565impl_len_cow!(f64);
1566
1567impl AltRealData for Cow<'static, [f64]> {
1568 fn elt(&self, i: usize) -> f64 {
1569 self[i]
1570 }
1571
1572 fn as_slice(&self) -> Option<&[f64]> {
1573 Some(self.as_ref())
1574 }
1575
1576 fn get_region(&self, start: usize, len: usize, buf: &mut [f64]) -> usize {
1577 let end = (start + len).min(<[f64]>::len(self));
1578 let actual_len = end.saturating_sub(start);
1579 if actual_len > 0 {
1580 buf[..actual_len].copy_from_slice(&self[start..end]);
1581 }
1582 actual_len
1583 }
1584
1585 fn no_na(&self) -> Option<bool> {
1586 Some(!self.iter().any(|x| x.to_bits() == NA_REAL.to_bits()))
1587 }
1588
1589 fn sum(&self, na_rm: bool) -> Option<f64> {
1590 let mut sum = 0.0;
1591 for &x in self.iter() {
1592 if x.to_bits() == NA_REAL.to_bits() {
1593 if !na_rm {
1594 return Some(NA_REAL);
1595 }
1596 } else if x.is_nan() {
1597 if !na_rm {
1598 return Some(f64::NAN);
1599 }
1600 } else {
1601 sum += x;
1602 }
1603 }
1604 Some(sum)
1605 }
1606
1607 fn min(&self, na_rm: bool) -> Option<f64> {
1608 let mut min = f64::INFINITY;
1609 let mut found = false;
1610 for &x in self.iter() {
1611 if x.to_bits() == NA_REAL.to_bits() {
1612 if !na_rm {
1613 return Some(NA_REAL);
1614 }
1615 } else if x.is_nan() {
1616 if !na_rm {
1617 return Some(f64::NAN);
1618 }
1619 } else {
1620 found = true;
1621 min = min.min(x);
1622 }
1623 }
1624 if found { Some(min) } else { None }
1625 }
1626
1627 fn max(&self, na_rm: bool) -> Option<f64> {
1628 let mut max = f64::NEG_INFINITY;
1629 let mut found = false;
1630 for &x in self.iter() {
1631 if x.to_bits() == NA_REAL.to_bits() {
1632 if !na_rm {
1633 return Some(NA_REAL);
1634 }
1635 } else if x.is_nan() {
1636 if !na_rm {
1637 return Some(f64::NAN);
1638 }
1639 } else {
1640 found = true;
1641 max = max.max(x);
1642 }
1643 }
1644 if found { Some(max) } else { None }
1645 }
1646}
1647
1648impl_dataptr_cow!(f64);
1649impl_serialize_cow!(f64);
1650
1651impl_len_cow!(u8);
1652
1653impl AltRawData for Cow<'static, [u8]> {
1654 fn elt(&self, i: usize) -> u8 {
1655 self[i]
1656 }
1657
1658 fn as_slice(&self) -> Option<&[u8]> {
1659 Some(self.as_ref())
1660 }
1661
1662 fn get_region(&self, start: usize, len: usize, buf: &mut [u8]) -> usize {
1663 let end = (start + len).min(<[u8]>::len(self));
1664 let actual_len = end.saturating_sub(start);
1665 if actual_len > 0 {
1666 buf[..actual_len].copy_from_slice(&self[start..end]);
1667 }
1668 actual_len
1669 }
1670}
1671
1672impl_dataptr_cow!(u8);
1673impl_serialize_cow!(u8);
1674
1675impl_len_cow!(Rcomplex);
1676
1677impl AltComplexData for Cow<'static, [Rcomplex]> {
1678 fn elt(&self, i: usize) -> Rcomplex {
1679 self[i]
1680 }
1681
1682 fn as_slice(&self) -> Option<&[Rcomplex]> {
1683 Some(self.as_ref())
1684 }
1685
1686 fn get_region(&self, start: usize, len: usize, buf: &mut [Rcomplex]) -> usize {
1687 let end = (start + len).min(<[Rcomplex]>::len(self));
1688 let actual_len = end.saturating_sub(start);
1689 if actual_len > 0 {
1690 buf[..actual_len].copy_from_slice(&self[start..end]);
1691 }
1692 actual_len
1693 }
1694}
1695
1696impl_dataptr_cow!(Rcomplex);
1697impl_serialize_cow!(Rcomplex);
1698#[cfg(test)]
1714mod tests {
1715 use super::*;
1716 use crate::altrep_data::AltRealData;
1717
1718 #[test]
1722 fn na_real_bit_pattern() {
1723 assert_eq!(NA_REAL.to_bits(), 0x7FF0_0000_0000_07A2);
1724 }
1725
1726 #[test]
1728 fn nan_is_not_na_real() {
1729 let nan = f64::NAN;
1730 assert!(nan.is_nan());
1731 assert_ne!(nan.to_bits(), NA_REAL.to_bits());
1732 }
1733
1734 #[test]
1741 fn vec_f64_no_na_with_regular_nan_is_true() {
1742 let v: Vec<f64> = vec![1.0, f64::NAN, 3.0];
1743 assert_eq!(AltRealData::no_na(&v), Some(true));
1744 }
1745
1746 #[test]
1748 fn vec_f64_no_na_with_na_real_is_false() {
1749 let v: Vec<f64> = vec![1.0, NA_REAL, 3.0];
1750 assert_eq!(AltRealData::no_na(&v), Some(false));
1751 }
1752
1753 #[test]
1755 fn vec_f64_no_na_all_finite_is_true() {
1756 let v: Vec<f64> = vec![1.0, 2.0, 3.0];
1757 assert_eq!(AltRealData::no_na(&v), Some(true));
1758 }
1759
1760 #[test]
1766 fn vec_f64_sum_na_propagates() {
1767 let v: Vec<f64> = vec![1.0, NA_REAL, 3.0];
1768 let result = AltRealData::sum(&v, false);
1769 assert!(result.is_some());
1770 let bits = result.unwrap().to_bits();
1771 assert_eq!(
1772 bits,
1773 NA_REAL.to_bits(),
1774 "sum with NA should return NA_real_"
1775 );
1776 }
1777
1778 #[test]
1780 fn vec_f64_sum_na_rm_skips_na() {
1781 let v: Vec<f64> = vec![1.0, NA_REAL, 3.0];
1782 let result = AltRealData::sum(&v, true);
1783 assert_eq!(result, Some(4.0));
1784 }
1785
1786 #[test]
1788 fn vec_f64_sum_nan_propagates_as_nan_not_na() {
1789 let v: Vec<f64> = vec![1.0, f64::NAN, 3.0];
1790 let result = AltRealData::sum(&v, false);
1791 assert!(result.is_some());
1792 let val = result.unwrap();
1793 assert!(val.is_nan(), "sum with NaN (not NA) should return NaN");
1794 assert_ne!(
1795 val.to_bits(),
1796 NA_REAL.to_bits(),
1797 "sum with regular NaN should NOT return NA_real_"
1798 );
1799 }
1800
1801 #[test]
1803 fn vec_f64_sum_nan_rm_skips_nan() {
1804 let v: Vec<f64> = vec![1.0, f64::NAN, 3.0];
1805 let result = AltRealData::sum(&v, true);
1806 assert_eq!(result, Some(4.0));
1807 }
1808
1809 #[test]
1814 fn box_f64_no_na_with_regular_nan_is_true() {
1815 let v: Box<[f64]> = vec![1.0, f64::NAN, 3.0].into_boxed_slice();
1816 assert_eq!(AltRealData::no_na(&v), Some(true));
1817 }
1818
1819 #[test]
1820 fn box_f64_no_na_with_na_real_is_false() {
1821 let v: Box<[f64]> = vec![1.0, NA_REAL, 3.0].into_boxed_slice();
1822 assert_eq!(AltRealData::no_na(&v), Some(false));
1823 }
1824
1825 #[test]
1830 fn slice_f64_no_na_with_regular_nan_is_true() {
1831 let data: &[f64] = &[1.0, f64::NAN, 3.0];
1832 assert_eq!(AltRealData::no_na(&data), Some(true));
1833 }
1834
1835 #[test]
1836 fn slice_f64_no_na_with_na_real_is_false() {
1837 let data: &[f64] = &[1.0, NA_REAL, 3.0];
1838 assert_eq!(AltRealData::no_na(&data), Some(false));
1839 }
1840
1841 #[test]
1846 fn array_f64_no_na_with_regular_nan_is_true() {
1847 let arr: [f64; 3] = [1.0, f64::NAN, 3.0];
1848 assert_eq!(AltRealData::no_na(&arr), Some(true));
1849 }
1850
1851 #[test]
1852 fn array_f64_no_na_with_na_real_is_false() {
1853 let arr: [f64; 3] = [1.0, NA_REAL, 3.0];
1854 assert_eq!(AltRealData::no_na(&arr), Some(false));
1855 }
1856
1857 #[test]
1862 fn cow_f64_no_na_with_regular_nan_is_true() {
1863 let v: Cow<'static, [f64]> = Cow::Owned(vec![1.0, f64::NAN, 3.0]);
1864 assert_eq!(AltRealData::no_na(&v), Some(true));
1865 }
1866
1867 #[test]
1868 fn cow_f64_no_na_with_na_real_is_false() {
1869 let v: Cow<'static, [f64]> = Cow::Owned(vec![1.0, NA_REAL, 3.0]);
1870 assert_eq!(AltRealData::no_na(&v), Some(false));
1871 }
1872
1873 }