macchiato_rhai_mini/
lib.rs

1use std::mem::ManuallyDrop;
2
3use getrandom::register_custom_getrandom;
4use getrandom::Error;
5
6// TODO: replace w/ call to imported function
7fn host_getrandom(_buf: &mut [u8]) -> Result<(), Error> {
8    Ok(())
9}
10
11register_custom_getrandom!(host_getrandom);
12
13use rhai::{Engine};
14use rhai::packages::Package;
15use rhai::packages::StandardPackage;
16
17// Create a vector of bytes, and return a pointer to 12 bytes of memory
18// containing the address of the pointer, the length, and the capacity,
19// each as 32 bit unsigned integers. Takes an argument `capacity` which
20// is the minimum capacity.
21//
22// https://github.com/rust-lang/rust/blob/e84902d35a4d3039c794e139eb12fba3624c5ff1/library/alloc/src/vec/mod.rs#L1086
23#[no_mangle]
24pub extern "C" fn new_vec(capacity: u32) -> u32 {
25    let vec: Vec<u8> = Vec::with_capacity(capacity.try_into().unwrap());
26    let mut vec_md = ManuallyDrop::new(vec);
27    let vec_contents_ptr = vec_md.as_mut_ptr() as u32;
28    let vec_box: Box<[u32; 3]> = Box::new([
29        vec_contents_ptr,
30        vec_md.len().try_into().unwrap(),
31        vec_md.capacity().try_into().unwrap()
32    ]);
33    let vec_ptr = Box::into_raw(vec_box) as *const () as u32;
34    return vec_ptr
35}
36
37// Delete a vector, freeing its memory, and that of its contents. To free
38// just the contents, resize it to 0.
39#[no_mangle]
40pub extern "C" fn delete_vec(vec: u32) {
41    let vec_ptr = vec as *mut [u32; 3];
42    let vec_box = unsafe { Box::from_raw(vec_ptr) };
43    let vec_arr = *vec_box;
44    let mut _vec: Vec<u8> = unsafe {
45        Vec::from_raw_parts(
46            vec_arr[0] as *mut u8,
47            vec_arr[1] as usize,
48            vec_arr[2] as usize
49        )
50    };
51    // Since the vec_box isn't converted into raw and ManuallyDrop isn't put
52    // into place for _vec, when they fall out of scope, it deletes:
53    //
54    // - vec_box, which was owned by the host
55    // - _vec, which contains a copy of the 12 bytes of data in vec_box, and
56    // thus is owned by this function
57    // - _vec's contents, which was owned by the host
58}
59
60// Resize a vector (change its capacity).
61#[no_mangle]
62pub extern "C" fn resize_vec(vec: i32, capacity: i32) {
63    let vec_ptr = vec as *mut [u32; 3];
64    let mut vec_box = unsafe { Box::from_raw(vec_ptr) };
65    let mut vec_val: Vec<u8> = unsafe {
66        Vec::from_raw_parts(
67            vec_box[0] as *mut u8,
68            vec_box[1] as usize,
69            vec_box[2] as usize
70        )
71    };
72    let capacity_usize: usize = capacity.try_into().unwrap();
73    if capacity_usize < vec_val.len() {
74        vec_val.shrink_to(capacity_usize - vec_val.len());
75    } else {
76        vec_val.reserve(capacity_usize - vec_val.len());
77    }
78    let vec_contents_ptr = vec_val.as_mut_ptr() as u32;
79    vec_box[0] = vec_contents_ptr.try_into().unwrap();
80    vec_box[2] = vec_val.capacity().try_into().unwrap();
81
82    let _vec_val_md = ManuallyDrop::new(vec_val);
83    let _vec_ptr_out = Box::into_raw(vec_box) as *const () as u32;
84}
85
86// extern "C" {
87//     fn log_number(number: u32);
88// }
89
90#[no_mangle]
91pub extern "C" fn run(input_vec: i32, output_vec: i32) {
92    // unsafe { log_number(1); }
93    let input_vec_ptr = input_vec as *mut [u32; 3];
94    let input_vec_box = unsafe { Box::from_raw(input_vec_ptr) };
95    let input_vec_val: Vec<u8> = unsafe {
96        Vec::from_raw_parts(
97            input_vec_box[0] as *mut u8,
98            input_vec_box[1] as usize,
99            input_vec_box[2] as usize
100        )
101    };
102
103    let mut engine = Engine::new_raw();
104    let package = StandardPackage::new();
105    package.register_into_engine(&mut engine);
106    let input = unsafe { std::str::from_utf8_unchecked(&input_vec_val) };
107    let eval_result = engine.eval::<String>(input);
108    let result = match eval_result {
109        Ok(result) => result,
110        Err(err) => ["Error".to_string(), err.to_string()].join(": "),
111    };
112
113    let output_vec_ptr = output_vec as *mut [u32; 3];
114    let mut output_vec_box = unsafe { Box::from_raw(output_vec_ptr) };
115    if output_vec_box[2] < result.len().try_into().unwrap() {
116        resize_vec(output_vec, result.len().try_into().unwrap());
117    }
118    let mut output_vec_val: Vec<u8> = unsafe {
119        Vec::from_raw_parts(
120            output_vec_box[0] as *mut u8,
121            output_vec_box[1] as usize,
122            output_vec_box[2] as usize
123        )
124    };
125    output_vec_val.resize(result.len().try_into().unwrap(), 0);
126    output_vec_val.copy_from_slice(result.as_bytes());
127    output_vec_box[1] = result.len().try_into().unwrap();
128
129    // ensure what is owned by the host deleted when it falls out of scope
130    let _input_vec_ptr_out = Box::into_raw(input_vec_box) as *const () as u32;
131    let _output_vec_ptr_out = Box::into_raw(output_vec_box) as *const () as u32;
132    let _input_vec_val_md = ManuallyDrop::new(input_vec_val);
133    let _output_vec_val_md = ManuallyDrop::new(output_vec_val);
134}