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