-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmod.rs
87 lines (70 loc) · 2.47 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
mod altinteger;
mod altlogical;
mod altreal;
mod altstring;
pub use altinteger::*;
pub use altlogical::*;
pub use altreal::*;
pub use altstring::*;
use std::{collections::HashMap, sync::Mutex};
use once_cell::sync::OnceCell;
use savvy_ffi::{
altrep::{R_altrep_class_t, R_altrep_data1, R_new_altrep, MARK_NOT_MUTABLE},
R_NilValue, SEXP,
};
use crate::{protect::local_protect, IntoExtPtrSexp};
static ALTREP_CLASS_CATALOGUE: OnceCell<Mutex<HashMap<&'static str, R_altrep_class_t>>> =
OnceCell::new();
pub(crate) fn create_altrep_instance<T: IntoExtPtrSexp>(
x: T,
class_name: &'static str,
) -> crate::Result<SEXP> {
let sexp = x.into_external_pointer().0;
local_protect(sexp);
let catalogue_mutex = match ALTREP_CLASS_CATALOGUE.get() {
Some(catalogue_mutex) => catalogue_mutex,
None => return Err("ALTREP_CLASS_CATALOGUE is not initialized".into()),
};
let catalogue = match catalogue_mutex.lock() {
Ok(catalogue) => catalogue,
Err(e) => return Err(e.to_string().into()),
};
let class = match catalogue.get(class_name) {
Some(class) => class,
None => return Err("Failed to get the ALTREP class".into()),
};
let altrep = unsafe { R_new_altrep(*class, sexp, R_NilValue) };
local_protect(altrep);
unsafe { MARK_NOT_MUTABLE(altrep) };
Ok(altrep)
}
fn register_altrep_class(
class_name: &'static str,
class_t: R_altrep_class_t,
) -> crate::error::Result<()> {
// There's no way to let global
ALTREP_CLASS_CATALOGUE.get_or_init(|| Mutex::new(HashMap::new()));
let catalogue_mutex = match ALTREP_CLASS_CATALOGUE.get() {
Some(catalogue_mutex) => catalogue_mutex,
None => return Err("ALTREP_CLASS_CATALOGUE is not initialized".into()),
};
let mut catalogue = match catalogue_mutex.lock() {
Ok(catalogue) => catalogue,
Err(e) => return Err(e.to_string().into()),
};
let existing_entry = catalogue.insert(class_name, class_t);
if existing_entry.is_some() {
return Err(
"[WARN] ALTREP class {class_name} is already defined. Something seems wrong.".into(),
);
}
Ok(())
}
// Some helpers
#[allow(clippy::mut_from_ref)]
#[inline]
pub(crate) fn extract_self_from_altrep<T>(x: &SEXP) -> &mut T {
let x = unsafe { crate::get_external_pointer_addr(R_altrep_data1(*x)).unwrap() as *mut T };
let self_ = unsafe { x.as_mut() };
self_.expect("Failed to convert the external pointer to the Rust object")
}