sqlsync_reducer/
guest_ffi.rs1use std::{collections::BTreeMap, mem::MaybeUninit, panic, sync::Once};
2
3use serde::{de::DeserializeOwned, Serialize};
4
5use crate::types::LogRecord;
6
7pub type FFIBuf = Vec<u8>;
8pub type FFIBufPtr = *mut u8;
9pub type FFIBufLen = u32;
10
11pub fn fbm() -> &'static mut FFIBufManager {
12 static mut SINGLETON: MaybeUninit<FFIBufManager> = MaybeUninit::uninit();
13 static ONCE: Once = Once::new();
14 unsafe {
15 ONCE.call_once(|| {
16 let singleton = FFIBufManager::default();
17 SINGLETON.write(singleton);
18 });
19 SINGLETON.assume_init_mut()
20 }
21}
22
23#[derive(Default)]
24pub struct FFIBufManager {
25 bufs: BTreeMap<FFIBufPtr, FFIBufLen>,
27}
28
29impl FFIBufManager {
30 pub fn alloc(&mut self, len: FFIBufLen) -> FFIBufPtr {
31 let mut buf = Vec::with_capacity(len as usize);
32 let ptr = buf.as_mut_ptr();
33 self.bufs.insert(ptr, len);
34 std::mem::forget(buf);
35 ptr
36 }
37
38 pub unsafe fn dealloc(&mut self, ptr: FFIBufPtr) {
43 self.consume(ptr);
44 }
46
47 pub fn length(&self, ptr: FFIBufPtr) -> FFIBufLen {
48 *self.bufs.get(&ptr).unwrap()
49 }
50
51 pub unsafe fn consume(&mut self, ptr: FFIBufPtr) -> FFIBuf {
56 let len = self.bufs.remove(&ptr).unwrap();
57 Vec::from_raw_parts(ptr, len as usize, len as usize)
58 }
59
60 pub fn encode<T: Serialize>(&mut self, data: &T) -> Result<FFIBufPtr, bincode::Error> {
61 let mut buf = bincode::serialize(data)?;
62 let ptr = buf.as_mut_ptr();
63 self.bufs.insert(ptr, buf.len() as FFIBufLen);
64 std::mem::forget(buf);
65 Ok(ptr)
66 }
67
68 pub unsafe fn decode<T: DeserializeOwned>(
79 &mut self,
80 ptr: FFIBufPtr,
81 ) -> Result<T, bincode::Error> {
82 let buf = self.consume(ptr);
83 bincode::deserialize(&buf)
84 }
85}
86
87#[no_mangle]
88pub fn ffi_buf_allocate(length: FFIBufLen) -> FFIBufPtr {
89 fbm().alloc(length)
90}
91
92#[no_mangle]
97pub unsafe fn ffi_buf_deallocate(ptr: FFIBufPtr) {
98 fbm().dealloc(ptr)
99}
100
101#[no_mangle]
102pub fn ffi_buf_len(ptr: FFIBufPtr) -> FFIBufLen {
103 fbm().length(ptr)
104}
105
106extern "C" {
107 fn host_log(log_req: FFIBufPtr);
108}
109
110pub struct FFILogger;
111
112impl FFILogger {
113 pub fn init(&'static self, max_level: log::Level) -> Result<(), log::SetLoggerError> {
114 log::set_logger(self).map(|_| log::set_max_level(max_level.to_level_filter()))
115 }
116}
117
118impl log::Log for FFILogger {
119 fn enabled(&self, metadata: &log::Metadata) -> bool {
120 metadata.level() <= log::max_level()
121 }
122
123 fn log(&self, record: &log::Record) {
124 let record: LogRecord = record.into();
125 let record_ptr = fbm().encode(&record).unwrap();
126 unsafe { host_log(record_ptr) }
127 }
128
129 fn flush(&self) {
130 }
132}
133
134pub fn install_panic_hook() {
135 static SET_PANIC_HOOK: Once = Once::new();
136 SET_PANIC_HOOK.call_once(|| {
137 std::panic::set_hook(Box::new(panic_hook));
138 });
139}
140
141fn panic_hook(info: &panic::PanicInfo) {
142 let record: LogRecord = info.into();
143 let record_ptr = fbm().encode(&record).unwrap();
144 unsafe { host_log(record_ptr) }
145}