extendr_api/wrapper/
strings.rs
1use super::*;
2use extendr_ffi::{
3 R_xlen_t, SET_STRING_ELT, STRING_ELT, STRING_IS_SORTED, STRING_NO_NA, STRING_PTR_RO,
4};
5use std::convert::From;
6use std::iter::FromIterator;
7
8#[derive(PartialEq, Clone)]
9pub struct Strings {
10 pub(crate) robj: Robj,
11}
12
13impl Default for Strings {
14 fn default() -> Self {
15 Strings::new(0)
16 }
17}
18
19impl Strings {
20 pub fn new(size: usize) -> Strings {
30 let robj = Robj::alloc_vector(SEXPTYPE::STRSXP, size);
31 Self { robj }
32 }
33
34 pub fn from_values<V>(values: V) -> Self
44 where
45 V: IntoIterator,
46 V::IntoIter: ExactSizeIterator,
47 V::Item: AsRef<str>,
48 {
49 single_threaded(|| unsafe {
50 let values = values.into_iter();
51 let maxlen = values.len();
52 let mut robj = Robj::alloc_vector(SEXPTYPE::STRSXP, maxlen);
53 let sexp = robj.get_mut();
54 for (i, v) in values.into_iter().take(maxlen).enumerate() {
55 let v = v.as_ref();
56 let ch = str_to_character(v);
57 SET_STRING_ELT(sexp, i as R_xlen_t, ch);
58 }
59 Self { robj }
60 })
61 }
62
63 pub fn as_slice<'a>(&self) -> &'a [Rstr] {
65 unsafe {
66 let data = STRING_PTR_RO(self.robj.get()) as *const Rstr;
67 let len = self.robj.len();
68 std::slice::from_raw_parts(data, len)
69 }
70 }
71
72 pub fn elt(&self, i: usize) -> Rstr {
74 if i >= self.len() {
75 Rstr::na()
76 } else {
77 Robj::from_sexp(unsafe { STRING_ELT(self.get(), i as R_xlen_t) })
78 .try_into()
79 .unwrap()
80 }
81 }
82
83 pub fn set_elt(&mut self, i: usize, e: Rstr) {
85 single_threaded(|| unsafe {
86 if i < self.len() {
87 SET_STRING_ELT(self.robj.get_mut(), i as isize, e.get());
88 }
89 });
90 }
91
92 pub fn iter(&self) -> impl Iterator<Item = &Rstr> {
94 self.as_slice().iter()
95 }
96
97 pub fn is_sorted(&self) -> Rbool {
99 unsafe { STRING_IS_SORTED(self.get()).into() }
100 }
101
102 pub fn no_na(&self) -> Rbool {
104 unsafe { STRING_NO_NA(self.get()).into() }
105 }
106}
107
108impl Attributes for Strings {}
109
110impl<T: AsRef<str>> FromIterator<T> for Strings {
111 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
113 let iter_collect: Vec<_> = iter.into_iter().collect();
114 let len = iter_collect.len();
115
116 let mut robj = Strings::alloc_vector(SEXPTYPE::STRSXP, len);
117 crate::single_threaded(|| unsafe {
118 for (i, v) in iter_collect.into_iter().enumerate() {
119 SET_STRING_ELT(robj.get_mut(), i as isize, str_to_character(v.as_ref()));
120 }
121 Strings { robj }
122 })
123 }
124}
125
126impl<T> From<T> for Strings
127where
128 T: AsRef<str>,
129{
130 fn from(value: T) -> Self {
132 Strings::from_values([value.as_ref()])
133 }
134}
135
136impl Deref for Strings {
137 type Target = [Rstr];
138
139 fn deref(&self) -> &Self::Target {
140 self.as_slice()
141 }
142}
143
144impl std::fmt::Debug for Strings {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 if self.len() == 1 {
147 write!(f, "{:?}", self.elt(0))
148 } else {
149 f.debug_list().entries(self.iter()).finish()
150 }
151 }
152}
153
154impl From<Option<Strings>> for Robj {
155 fn from(value: Option<Strings>) -> Self {
156 match value {
157 Some(value_strings) => value_strings.into(),
158 None => nil_value(),
159 }
160 }
161}