rustr/
rweak.rs

1//! R Weak Reference type
2//!
3//!
4
5use ::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
56// boil
57
58gen_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    //  An example release function.
170    //  User should impl this themselves, because finalizer_ptr::<Obj> may change.
171    //
172    // 	pub fn release(self){
173    // 		unsafe{
174    // 				let res : * mut Obj= ::std::mem::transmute(R_ExternalPtrAddr(self.data.s()));
175    // 				if res.is_null() != true {
176    // 					finalizer_ptr::<Obj>(self.data.s());
177    // 				}
178    // 				R_ClearExternalPtr(self.data.s());
179    // 		}
180    //    }
181
182    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}