extendr_api/io/
load.rs

1use super::PstreamFormat;
2use crate::{catch_r_error, error::Error, error::Result, robj::Robj};
3use extendr_ffi::{R_NilValue, R_Unserialize, R_inpstream_st, R_inpstream_t, SEXP};
4use std::io::Read;
5
6pub struct ReadHook {
7    func: Option<unsafe extern "C" fn(arg1: SEXP, arg2: SEXP) -> SEXP>,
8    data: SEXP,
9}
10
11pub trait Load {
12    /// Save an object in the R data format.
13    /// `version` should probably be 3.
14    fn load<P: AsRef<std::path::Path>>(
15        path: &P,
16        format: PstreamFormat,
17        hook: Option<ReadHook>,
18    ) -> Result<Robj> {
19        let mut reader = std::fs::File::open(path)
20            .map_err(|_| Error::Other(format!("could not open file {:?}", path.as_ref())))?;
21        Self::from_reader(&mut reader, format, hook)
22    }
23
24    /// Save an object in the R data format to a `Write` trait.
25    /// `version` should probably be 3.
26    fn from_reader<R: Read>(
27        reader: &mut R,
28        format: PstreamFormat,
29        hook: Option<ReadHook>,
30    ) -> Result<Robj> {
31        unsafe extern "C" fn inchar<R: Read>(arg1: R_inpstream_t) -> ::std::os::raw::c_int {
32            let reader = &mut *((*arg1).data as *mut R);
33            let buf: &mut [u8] = &mut [0_u8];
34            reader.read_exact(buf).map(|_| buf[0].into()).unwrap_or(-1)
35        }
36
37        unsafe extern "C" fn inbytes<R: Read>(
38            arg1: R_inpstream_t,
39            arg2: *mut ::std::os::raw::c_void,
40            arg3: ::std::os::raw::c_int,
41        ) {
42            let reader = &mut *((*arg1).data as *mut R);
43            let buf = std::slice::from_raw_parts_mut(arg2 as *mut u8, arg3 as usize);
44            reader.read_exact(buf).unwrap();
45        }
46
47        let read_ptr: *mut R = reader as &mut R;
48        let data = unsafe { std::mem::transmute(read_ptr) };
49
50        let (hook_func, hook_data) = if let Some(hook) = hook {
51            (hook.func, hook.data)
52        } else {
53            (None, unsafe { R_NilValue })
54        };
55
56        // let sexp = self.get();
57        // pub type R_inpstream_t = *mut R_inpstream_st;
58        let mut state = R_inpstream_st {
59            data,
60            type_: format,
61            InChar: Some(inchar::<R>),
62            InBytes: Some(inbytes::<R>),
63            InPersistHookFunc: hook_func,
64            InPersistHookData: hook_data,
65            native_encoding: [0; 64],
66            nat2nat_obj: std::ptr::null_mut(),
67            nat2utf8_obj: std::ptr::null_mut(),
68        };
69
70        Ok(Robj::from_sexp(catch_r_error(move || unsafe {
71            R_Unserialize(&mut state as R_inpstream_t)
72        })?))
73    }
74}
75
76impl Load for Robj {}