rustr/
rptr.rs

1//! R External Pointer type
2//!
3//!
4//!
5
6use ::rdll::*;
7use ::storage::*;
8use ::traits::*;
9use ::rtype::*;
10use error::{RResult, rerror};
11use error::REKind::{Other, NotCompatible};
12
13use std::default::Default;
14use std::any::*;
15use symbol::*;
16use std::marker::*;
17
18use util::*;
19
20pub type RPtr<Obj> = RPtrM<Obj, Preserve>;
21
22pub trait RDrop {
23    fn rdrop(_: SEXP);
24}
25
26#[derive(Debug)]
27pub struct RPtrM<Obj: Any, T: SEXPbucket> {
28    data: T,
29    obj: PhantomData<Obj>,
30    tag: SEXP,
31}
32
33pub struct RPtrParam<Obj: Any, T: SEXPbucket> {
34    drop: bool,
35    exit: bool,
36    tag: SEXP,
37    prot: SEXP,
38    obj: PhantomData<Obj>,
39    t: PhantomData<T>,
40    finalizer_func: ::std::option::Option<extern "C" fn(arg1: SEXP)>,
41}
42
43impl<Obj: Any, T: SEXPbucket> Default for RPtrParam<Obj, T> {
44    fn default() -> RPtrParam<Obj, T> {
45        unsafe {
46            let sym: Symbol = c_str(format!("{:?}", TypeId::of::<Obj>()).as_ref()).into();
47            RPtrParam {
48                drop: true,
49                exit: true,
50                tag: sym.s(),
51                prot: R_NilValue,
52                obj: PhantomData,
53                t: PhantomData,
54                finalizer_func: Some(finalizer_ptr::<Obj>),
55            }
56        }
57    }
58}
59
60
61impl<Obj: Any, T: SEXPbucket> RPtrParam<Obj, T> {
62    pub fn tag(mut self, tag_: SEXP) -> RPtrParam<Obj, T> {
63        self.tag = tag_;
64        self
65    }
66    pub fn prot(mut self, prot_: SEXP) -> RPtrParam<Obj, T> {
67        self.prot = prot_;
68        self
69    }
70    pub fn drop(mut self, finalizer_: bool) -> RPtrParam<Obj, T> {
71        self.drop = finalizer_;
72        self
73    }
74    pub fn finalizer(mut self,
75                     finalizer_: ::std::option::Option<extern "C" fn(arg1: SEXP)>)
76                     -> RPtrParam<Obj, T> {
77        self.finalizer_func = finalizer_;
78        self
79    }
80    pub fn onexit(mut self, exit: bool) -> RPtrParam<Obj, T> {
81        self.exit = exit;
82        self
83    }
84    pub fn done(self, ptr: Box<Obj>) -> RPtrM<Obj, T>
85        where T: SEXPbucket
86    {
87        let extptr: SEXP;
88        unsafe {
89            extptr = R_MakeExternalPtr(::std::mem::transmute(Box::into_raw(ptr)),
90                                       self.tag,
91                                       self.prot);
92        }
93
94        let res = RPtrM {
95            data: T::new(extptr),
96            obj: PhantomData,
97            tag: self.tag,
98        };
99        let onexit: Rboolean;
100        if self.exit {
101            onexit = Rboolean::TRUE;
102        } else {
103            onexit = Rboolean::FALSE;
104        }
105        if self.drop {
106            unsafe {
107                R_RegisterCFinalizerEx(extptr, self.finalizer_func, onexit);
108            }
109        }
110        res
111    }
112}
113
114impl<Obj: Any, T: SEXPbucket> RPtrM<Obj, T> {
115    pub fn init() -> RPtrParam<Obj, T> {
116        RPtrParam::default()
117    }
118    pub fn new(ptr: Box<Obj>) -> RPtrM<Obj, T> {
119        Self::init().done(ptr)
120    }
121    pub fn get(& mut self) -> RResult<&mut Obj> {
122        unsafe {
123            let res: *mut Obj = ::std::mem::transmute(R_ExternalPtrAddr(self.data.s()));
124            if res.is_null() {
125                return rerror(Other("external pointer is not valid".into()));
126            }
127            Ok(&mut *res)
128        }
129    }
130    pub unsafe fn uget(&mut self) -> *mut Obj {
131        ::std::mem::transmute(R_ExternalPtrAddr(self.data.s()))
132    }
133    //  An example release function.
134    //  User should impl this themselves, because finalizer_ptr::<Obj> may change.
135    //
136    // 	pub fn release(self){
137    // 		unsafe{
138    // 				let res : * mut Obj= ::std::mem::transmute(R_ExternalPtrAddr(self.data.s()));
139    // 				if res.is_null() != true {
140    // 					finalizer_ptr::<Obj>(self.data.s());
141    // 				}
142    // 				R_ClearExternalPtr(self.data.s());
143    // 		}
144    //    }
145
146    pub fn init_sexp(x: SEXP, tag: SEXP, prot: SEXP) -> RResult<RPtrM<Obj, T>> {
147        let tags: Symbol = c_str(format!("{:?}", TypeId::of::<Obj>()).as_ref()).into();
148        unsafe {
149            if RTYPEOF(x) != EXTPTRSXP || tags.s() != R_ExternalPtrTag(x) {
150                return rerror(NotCompatible(format!("expecting a {:?} pointer",
151                                                    TypeId::of::<Obj>())
152                                                .into()));
153            }
154            R_SetExternalPtrTag(x, tag);
155            R_SetExternalPtrProtected(x, prot);
156            let res = RPtrM {
157                data: T::new(x),
158                obj: PhantomData,
159                tag: tags.s(),
160            };
161            Ok(res)
162        }
163    }
164
165    pub fn get_tag(&self) -> SEXP {
166        unsafe { R_ExternalPtrTag(self.data.s()) }
167    }
168    pub fn set_tag(&self, x: SEXP) {
169        unsafe { R_SetExternalPtrTag(self.data.s(), x) };
170    }
171    pub fn get_prot(&self) -> SEXP {
172        unsafe { R_ExternalPtrProtected(self.data.s()) }
173    }
174    pub fn set_prot(&self, x: SEXP) {
175        unsafe { R_SetExternalPtrProtected(self.data.s(), x) };
176    }
177}
178
179pub extern "C" fn finalizer_ptr<Obj: Any>(x: SEXP) {
180    unsafe {
181        if RTYPEOF(x) == EXTPTRSXP {
182            Box::<Obj>::from_raw(::std::mem::transmute(R_ExternalPtrAddr(x)));
183        }
184    }
185}
186
187impl<Obj: Any, T: SEXPbucket> RNew for RPtrM<Obj, T> {
188    fn rnew(x: SEXP) -> RResult<RPtrM<Obj, T>> {
189        let tags: Symbol = c_str(format!("{:?}", TypeId::of::<Obj>()).as_ref()).into();
190        unsafe {
191            if RTYPEOF(x) != EXTPTRSXP || tags.s() != R_ExternalPtrTag(x) {
192                return rerror(NotCompatible(format!("expecting a {:?} pointer",
193                                                    TypeId::of::<Obj>())
194                                                .into()));
195            }
196            let res = RPtrM {
197                data: T::new(x),
198                obj: PhantomData,
199                tag: tags.s(),
200            };
201            Ok(res)
202        }
203    }
204}
205
206gen_traits_rptr!(RPtrM);