1use ::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 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);