extendr_api/wrapper/
macros.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/// Generates `impl` block and required traits for a vector type.
macro_rules! gen_vector_wrapper_impl {
    (
        vector_type: $type : ident,
        scalar_type: $scalar_type : ty,
        primitive_type: $primitive_type : ty,
        r_prefix: $r_prefix : ident,
        SEXP: $sexp : ident,
        doc_name: $doc_name : ident,
        altrep_constructor: $altrep_constructor : ident,
    ) => {

        impl Attributes for $type {}

        impl Default for $type {
            fn default() -> Self {
                $type::new(0)
            }
        }

        impl From<Option<$type>> for Robj {
            fn from(value: Option<$type>) -> Self {
                match value {
                    None => nil_value(),
                    Some(value) => value.into(),
                }
            }
        }

        impl $type {
            paste::paste!{
                #[doc = "Create a new vector of " $type:lower "."]
                #[doc = "```"]
                #[doc = "use extendr_api::prelude::*;"]
                #[doc = "test! {"]
                #[doc = "   let vec = " $type "::new(10);"]
                #[doc = "   assert_eq!(vec.is_" $r_prefix:lower "(), true);"]
                #[doc = "   assert_eq!(vec.len(), 10);"]
                #[doc = "}"]
                #[doc = "```"]
                pub fn new(len: usize) -> $type {
                    // TODO: Check if impacts performance.
                    let iter = (0..len).map(|_| <$primitive_type>::default());
                    <$type>::from_values(iter)
                }
            }
            paste::paste!{
                #[doc = "Wrapper for creating non-ALTREP " $doc_name " (" $sexp ") vectors from iterators."]
                #[doc = "The iterator must be exact."]
                #[doc = "If you want a more generalised constructor, use `iter.collect::<" $type ">()`."]
                pub fn from_values<V>(values: V) -> Self
                where
                    V: IntoIterator,
                    V::IntoIter: ExactSizeIterator,
                    V::Item: Into<$scalar_type>,
                {
                    single_threaded(|| {
                        let values: V::IntoIter = values.into_iter();

                        let mut robj = Robj::alloc_vector($sexp, values.len());
                        let dest: &mut [$scalar_type] = robj.as_typed_slice_mut().unwrap();

                        for (d, v) in dest.iter_mut().zip(values) {
                            *d = v.into();
                        }
                        Self { robj }
                    })
                }
            }

            paste::paste!{
                #[doc = "Wrapper for creating ALTREP " $doc_name " (" $sexp ") vectors from iterators."]
                #[doc = "The iterator must be exact, cloneable and implement Debug."]
                #[doc = "If you want a more generalised constructor, use `iter.collect::<" $type ">()`."]
                pub fn from_values_altrep<V>(values: V) -> Self
                where
                    V: IntoIterator,
                    V::IntoIter: ExactSizeIterator + std::fmt::Debug + Clone + 'static + std::any::Any,
                    V::Item: Into<$scalar_type>,
                {
                    single_threaded(|| {
                        let values: V::IntoIter = values.into_iter();

                        let robj =
                                  Altrep::$altrep_constructor(values)
                                .try_into()
                                .unwrap();
                        Self { robj }
                    })
                }
            }

            paste::paste! {
                #[doc = "Get a single element from the vector."]
                #[doc = "Note that this is very inefficient in a tight loop."]
                #[doc = "```"]
                #[doc = "use extendr_api::prelude::*;"]
                #[doc = "test! {"]
                #[doc = "   let vec = " $type "::new(10);"]
                #[doc = "   assert_eq!(vec.elt(0), <"$scalar_type ">::default());"]
                #[doc = "   assert_eq!(vec.elt(9), <"$scalar_type ">::default());"]
                #[doc = "   assert!(vec.elt(10).is_na());"]
                #[doc = "}"]
                #[doc = "```"]
                pub fn elt(&self, index: usize) -> $scalar_type {
                    // Defensive check for oob
                    // This check will not be needed in later releases of R
                    if(index >= self.len()) {
                        <$scalar_type>::na()
                    } else {
                        unsafe { [<$r_prefix _ELT>](self.get(), index as R_xlen_t).into() }
                    }
                }
            }

            paste::paste!{
                #[doc = "Return an iterator for a " $doc_name " object."]
                #[doc = "Forces ALTREP objects to manifest."]
                pub fn iter(&self) -> impl Iterator<Item = $scalar_type> {
                    self.as_robj().as_typed_slice().unwrap().iter().cloned()
                }
            }

            paste::paste!{
                #[doc = "Return a writable iterator for a " $doc_name " object."]
                #[doc = "Forces ALTREP objects to manifest."]
                pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut $scalar_type> {
                    self.as_robj_mut().as_typed_slice_mut().unwrap().iter_mut()
                }
            }
        }

        impl FromIterator<$scalar_type> for $type {
            /// A more generalised iterator collector for small vectors.
            /// Generates a non-ALTREP vector.
            fn from_iter<T: IntoIterator<Item = $scalar_type>>(iter: T) -> Self {
                // Collect into a vector first.
                // TODO: specialise for ExactSizeIterator.
                let values: Vec<$scalar_type> = iter.into_iter().collect();

                let mut robj = Robj::alloc_vector($sexp, values.len());
                let dest: &mut [$scalar_type] = robj.as_typed_slice_mut().unwrap();

                for (d, v) in dest.iter_mut().zip(values) {
                    *d = v;
                }

                $type { robj }
            }
        }
    }
}

pub(in crate::wrapper) use gen_vector_wrapper_impl;