rustr/vectorx/
charvec.rs

1use ::rdll::*;
2use ::storage::*;
3use ::traits::*;
4use ::rtype::*;
5use ::protect::stackp::*;
6use error::*;
7use error::REKind::NotCompatible;
8use std::ops::Range;
9use std::ffi::*;
10use util::c_str;
11
12
13pub type CharVec = CharVecM<Preserve>;
14
15impl<T: SEXPbucket> CharVecM<T> {
16    pub fn new(x: SEXP) -> RResult<CharVecM<T>> {
17        if RTYPEOF(x) != STRSXP {
18            return rerror(NotCompatible("expecting a string vector".into()));
19        }
20        Ok(CharVecM { data: T::new(x) })
21    }
22    pub fn alloc(x: usize) -> CharVecM<T> {
23        CharVecM { data: T::new(unsafe { Rf_allocVector(STRSXP, x as R_xlen_t) }) }
24    }
25    pub fn alloc_matrix(x: usize, y: usize) -> CharVecM<T> {
26        CharVecM {
27            data: T::new(unsafe {
28                Rf_allocMatrix(STRSXP,
29                               x as ::std::os::raw::c_int,
30                               y as ::std::os::raw::c_int)
31            }),
32        }
33    }
34    pub unsafe fn uat(&self, ind: usize) -> Result<String, IntoStringError> {
35        CStr::from_ptr(R_CHAR(STRING_ELT(self.s(), ind as R_xlen_t))).to_owned().into_string()
36    }
37    pub unsafe fn uset(&mut self, ind: usize, value: &str) {
38        SET_STRING_ELT(self.s(),
39                       ind as R_xlen_t,
40                       Shield::new(Rf_mkChar(c_str(value).as_ptr())).s())
41    }
42    pub fn at(&self, ind: usize) -> RResult<String> {
43        unsafe {
44            if Rf_xlength(self.s()) <= ind as R_xlen_t {
45                return rraise("index out of bound");
46            }
47            Ok(try!(CStr::from_ptr(R_CHAR(STRING_ELT(self.s(), ind as R_xlen_t)))
48                        .to_owned()
49                        .into_string()))
50        }
51    }
52    pub fn set(&mut self, ind: usize, value: &str) -> RResult<()> {
53        unsafe {
54            if Rf_xlength(self.s()) <= ind as R_xlen_t {
55                return rraise("index out of bound");
56            }
57
58            SET_STRING_ELT(self.s(),
59                           ind as R_xlen_t,
60                           Shield::new(Rf_mkChar(c_str(value).as_ptr())).s());
61            Ok(())
62        }
63    }
64    pub unsafe fn atc(&self, ind: usize) -> RResult<CString> {
65        if Rf_xlength(self.s()) <= ind as R_xlen_t {
66            return rraise("index out of bound");
67        }
68        Ok(CStr::from_ptr(R_CHAR(STRING_ELT(self.s(), ind as R_xlen_t))).to_owned())
69    }
70    pub unsafe fn uatc(&self, ind: usize) -> CString {
71        CStr::from_ptr(R_CHAR(STRING_ELT(self.s(), ind as R_xlen_t))).to_owned()
72    }
73    pub unsafe fn usetc<D:ToSEXP>(&mut self, ind: usize, value: D) {
74        SET_STRING_ELT(self.s(),
75                       ind as R_xlen_t,
76                      value.s())
77    }
78    pub fn setc<D:ToSEXP>(&mut self, ind: usize, value: D) -> RResult<()> {
79        unsafe {
80            if Rf_xlength(self.s()) <= ind as R_xlen_t {
81                return rraise("index out of bound");
82            }
83            if RTYPEOF(self.s()) == CHARSXP  || self.s() == R_NaString{
84                return rraise("not a CHARSXP");
85            }
86            SET_STRING_ELT(self.s(),
87                           ind as R_xlen_t,
88                           value.s());
89            Ok(())
90        }
91    }
92    pub fn range(&self, ind: Range<usize>) -> Option<Vec<CString>> {
93        unsafe {
94            if Rf_xlength(self.s()) <= ind.end as R_xlen_t {
95                return None;
96            }
97            let mut vecs = Vec::with_capacity((ind.end - ind.start) as usize);
98            for ii in ind {
99                vecs.push(CStr::from_ptr(R_CHAR(STRING_ELT(self.s(), ii as R_xlen_t))).to_owned());
100            }
101            Some(vecs)
102        }
103    }
104    pub fn is_duplicated(&self, from_last: bool) -> R_xlen_t {
105        let last = if from_last {
106            Rboolean::TRUE
107        } else {
108            Rboolean::FALSE
109        };
110        unsafe { Rf_any_duplicated(self.s(), last) }
111    }
112}
113
114
115#[cfg_attr(feature = "dev",allow(explicit_counter_loop))]
116impl<T: SEXPbucket, E: Into<CString> + Clone> From<Vec<E>> for CharVecM<T> {
117    fn from(x: Vec<E>) -> CharVecM<T> {
118        let size_x = x.len();
119        unsafe {
120            let rvec = Shield::new(Rf_allocVector(STRSXP, size_x as R_xlen_t));
121            let mut xs = 0;
122            for ii in x {
123                SET_STRING_ELT(rvec.s(), xs, Shield::new(Rf_mkChar(ii.into().as_ptr())).s());
124                xs += 1;
125            }
126            CharVecM { data: T::new(rvec.s()) }
127        }
128    }
129}
130
131impl<T: SEXPbucket> From<CharVecM<T>> for Vec<CString> {
132    fn from(x: CharVecM<T>) -> Vec<CString> {
133        unsafe {
134            let lens = Rf_xlength(x.s());
135            let mut vecs = Vec::with_capacity(lens as usize);
136            for ii in 0..lens {
137                vecs.push(CString::urnew(STRING_ELT(x.s(), ii)));
138            }
139            vecs
140        }
141    }
142}
143
144impl<T: SEXPbucket> URNew for CharVecM<T> {
145    unsafe fn urnew(x: SEXP) -> Self {
146        CharVecM { data: T::new(x) }
147    }
148}
149
150impl<T: SEXPbucket> RNew for CharVecM<T> {
151    fn rnew(x: SEXP) -> RResult<Self> {
152        Self::new(x)
153    }
154}
155
156impl<T: SEXPbucket> RSize for CharVecM<T> {
157    fn rsize(&self) -> R_xlen_t {
158        unsafe { Rf_xlength(self.s()) }
159    }
160}
161
162gen_traits_sexp!(CharVecM);
163
164
165impl<T: SEXPbucket> RName for CharVecM<T> {}
166impl<T: SEXPbucket> RDim for CharVecM<T> {
167    type Output = CString;
168}
169
170#[derive(Debug)]
171pub struct CharVecIter<T: SEXPbucket> {
172    size: R_xlen_t,
173    next: R_xlen_t,
174    ty: CharVecM<T>,
175}
176
177impl<T: SEXPbucket> Iterator for CharVecIter<T> {
178    // we will be counting with usize
179    type Item = CString;
180
181    // next() is the only required method
182    fn next(&mut self) -> Option<CString> {
183        // increment our count. This is why we started at zero.
184        // check to see if we've finished counting or not.
185        if self.next < self.size {
186            self.next += 1;
187            unsafe { Some(CString::urnew(STRING_ELT(self.ty.s(), self.next - 1))) }
188        } else {
189            None
190        }
191
192    }
193}
194
195impl<T: SEXPbucket> IntoIterator for CharVecM<T> {
196    type Item = CString;
197    type IntoIter = CharVecIter<T>;
198
199    fn into_iter(self) -> Self::IntoIter {
200        CharVecIter {
201            size: self.rsize(),
202            next: 0,
203            ty: self,
204        }
205    }
206}
207
208impl<T: SEXPbucket> ExactSizeIterator for CharVecIter<T> {
209    // We already have the number of iterations, so we can use it directly.
210    fn len(&self) -> usize {
211        self.size as usize
212    }
213}
214
215
216/// Create a CharVec
217///
218#[macro_export]
219macro_rules! charvec {
220    ($($tts:expr),*) => {
221      // count macro parameter learn from rust macro book	
222      {let size = <[()]>::len(&[$(replace_expr!($tts, ())),*]);
223      	
224      // init 
225      let mut res = CharVec::alloc(size as usize);
226	  unsafe{
227      let mut x = 0;
228      $(
229			// skip a warning message 
230			x += 1;
231			let xi = try!(::std::ffi::CString::new($tts));
232			let tmp : SEXP = $crate::protect::stackp::Shield::new(RCharM::<NoProtect>::from(xi).s()).s(); 
233      		res.usetc(x-1,tmp);
234      		
235      )*      
236	}
237      res
238      }
239    };
240    
241    ($($id:ident ~ $tts:expr),*) => {
242      // count macro parameter learn from rust macro book	
243      {let size = <[()]>::len(&[$(replace_expr!($tts, ())),*]);
244      	
245      // init 
246      let mut res = CharVec::alloc(size as usize);
247	  let mut name = CharVec::alloc(size as usize);
248	  unsafe{
249      let mut x = 0;
250      $(
251			// skip a warning message 
252			x += 1;
253			let xi = try!(::std::ffi::CString::new($tts));
254			let tmp : SEXP = $crate::protect::stackp::Shield::new(RCharM::<NoProtect>::from(xi).s()).s(); 
255      		res.usetc(x-1,tmp);
256      		name.uset(x-1, stringify!($id));
257      )*
258	}
259	  unsafe{Rf_setAttrib(res.s(), R_NamesSymbol,name.s());}
260      res
261      }
262    }
263}
264
265/// Create a CharVec with unsafe code
266///
267#[macro_export]
268macro_rules! ucharvec {
269    ($($tts:expr),*) => {
270      // count macro parameter learn from rust macro book	
271      {let size = <[()]>::len(&[$(replace_expr!($tts, ())),*]);
272      	
273      // init 
274      let mut res = CharVec::alloc(size as usize);
275      let mut x = 0;
276      $(
277			// skip a warning message 
278			x += 1;
279      		res.uset(x-1, $tts);
280      		
281      )*      
282      res
283      }
284    };
285        ($($id:ident ~ $tts:expr),*) => {
286      // count macro parameter learn from rust macro book	
287      {let size = <[()]>::len(&[$(replace_expr!($tts, ())),*]);
288      	
289      // init 
290      let mut res = CharVec::alloc(size as usize);
291	  let mut name = CharVec::alloc(size as usize);
292
293      let mut x = 0;
294      $(
295			// skip a warning message 
296			x += 1;
297      		res.uset(x-1, $tts);
298      		name.uset(x-1, stringify!($id));
299      )*
300	
301	  Rf_setAttrib(res.s(), R_NamesSymbol,name.s());
302      res
303      }
304    }
305}