1use std::{ffi::{c_void, c_char, CString, CStr}, str};
2
3use crate::{Root, View};
4
5#[repr(C)]
7pub struct CRoot {
8 wrapped: *mut c_void,
10 render_json: extern "C" fn(*const CRoot) -> *const c_char,
13 fire_event_json: extern "C" fn(*const CRoot, *const c_char, *const c_char),
15 set_update_callback: extern "C" fn(*const CRoot, extern "C" fn(*const c_char)),
17}
18
19extern "C" fn render_json_impl<T>(c_root: *const CRoot) -> *const c_char where T: View {
20 unsafe {
21 let root = (*c_root).wrapped as *mut Root<T>;
22 let json = (*root).render_json();
23 let c_string = CString::new(json).expect("Could not convert JSON to C string");
24 c_string.into_raw()
25 }
26}
27
28extern "C" fn fire_event_json_impl<T>(c_root: *const CRoot, raw_id_path_json: *const c_char, raw_event_json: *const c_char) where T: View {
29 unsafe {
30 let root = (*c_root).wrapped as *mut Root<T>;
31 let id_path_json = str::from_utf8(CStr::from_ptr(raw_id_path_json).to_bytes()).expect("Could not decode id path JSON");
32 let event_json = str::from_utf8(CStr::from_ptr(raw_event_json).to_bytes()).expect("Could not decode event JSON");
33 (*root).fire_event_json(id_path_json, event_json)
34 }
35}
36
37extern "C" fn set_update_callback_impl<T>(c_root: *const CRoot, update_callback: extern "C" fn(*const c_char)) where T: View {
38 unsafe {
39 let root = (*c_root).wrapped as *mut Root<T>;
40 (*root).set_update_callback(move |update| {
41 let update_json = serde_json::to_string(update).expect("Could not encode update to JSON");
42 let update_json_c_string = CString::new(update_json).expect("Could not convert update JSON to C string");
43 update_callback(update_json_c_string.as_ptr())
44 });
45 }
46}
47
48impl<T> From<Box<Root<T>>> for CRoot where T: View {
49 fn from(value: Box<Root<T>>) -> Self {
50 Self {
51 wrapped: Box::into_raw(value) as *mut c_void,
52 render_json: render_json_impl::<T>,
53 fire_event_json: fire_event_json_impl::<T>,
54 set_update_callback: set_update_callback_impl::<T>,
55 }
56 }
57}
58
59impl Drop for CRoot {
60 fn drop(&mut self) {
61 unsafe {
62 drop(Box::from_raw(self.wrapped as *mut c_void));
63 }
64 }
65}