extendr_api/wrapper/
strings.rs1use 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 unsafe {
78 Robj::from_sexp(STRING_ELT(self.get(), i as R_xlen_t))
79 .try_into()
80 .unwrap()
81 }
82 }
83 }
84
85 pub fn set_elt(&mut self, i: usize, e: Rstr) {
87 single_threaded(|| unsafe {
88 if i < self.len() {
89 SET_STRING_ELT(self.robj.get_mut(), i as isize, e.get());
90 }
91 });
92 }
93
94 pub fn iter(&self) -> impl Iterator<Item = &Rstr> {
96 self.as_slice().iter()
97 }
98
99 pub fn is_sorted(&self) -> Rbool {
101 unsafe { STRING_IS_SORTED(self.get()).into() }
102 }
103
104 pub fn no_na(&self) -> Rbool {
106 unsafe { STRING_NO_NA(self.get()).into() }
107 }
108}
109
110impl Attributes for Strings {}
111
112impl<T: AsRef<str>> FromIterator<T> for Strings {
113 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
115 let iter_collect: Vec<_> = iter.into_iter().collect();
116 let len = iter_collect.len();
117
118 let mut robj = Strings::alloc_vector(SEXPTYPE::STRSXP, len);
119 crate::single_threaded(|| unsafe {
120 for (i, v) in iter_collect.into_iter().enumerate() {
121 SET_STRING_ELT(robj.get_mut(), i as isize, str_to_character(v.as_ref()));
122 }
123 Strings { robj }
124 })
125 }
126}
127
128impl<T> From<T> for Strings
129where
130 T: AsRef<str>,
131{
132 fn from(value: T) -> Self {
134 Strings::from_values([value.as_ref()])
135 }
136}
137
138impl Deref for Strings {
139 type Target = [Rstr];
140
141 fn deref(&self) -> &Self::Target {
142 self.as_slice()
143 }
144}
145
146impl std::fmt::Debug for Strings {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 if self.len() == 1 {
149 write!(f, "{:?}", self.elt(0))
150 } else {
151 f.debug_list().entries(self.iter()).finish()
152 }
153 }
154}
155
156impl From<Option<Strings>> for Robj {
157 fn from(value: Option<Strings>) -> Self {
158 match value {
159 Some(value_strings) => value_strings.into(),
160 None => nil_value(),
161 }
162 }
163}