libsql_bindgen/
lib.rs

1use core::ffi::{c_char, c_void, CStr};
2
3pub use libsql_bindgen_macros::libsql_bindgen;
4
5static SQLITE_TEXT: u8 = 3;
6static SQLITE_BLOB: u8 = 4;
7static SQLITE_NULL: u8 = 5;
8
9// Type translation from Wasm pointers to strings, blobs and nulls
10pub trait FromLibSQL {
11    fn from_libsql_type(wasm_ptr: i32) -> Self;
12}
13
14// Type translation from strings, blobs and nulls to Wasm pointers
15pub trait IntoLibSQL {
16    fn into_libsql_type(self) -> i32;
17}
18
19impl FromLibSQL for &str {
20    fn from_libsql_type(wasm_ptr: i32) -> Self {
21        let raw_ptr = wasm_ptr as *const c_char;
22        unsafe {
23            if *raw_ptr != SQLITE_TEXT as c_char {
24                "???"
25            } else {
26                match CStr::from_ptr(raw_ptr.offset(1)).to_str() {
27                    Ok(s) => s,
28                    Err(_) => "!!!",
29                }
30            }
31        }
32    }
33}
34
35impl IntoLibSQL for &str {
36    fn into_libsql_type(self) -> i32 {
37        let mut mem: Vec<u8> = vec![0; self.len() + 2];
38        mem[0] = SQLITE_TEXT;
39        mem[1..=self.len()].copy_from_slice(self.as_bytes());
40        mem[self.len() + 1] = 0;
41        let ptr = mem.as_ptr() as i32;
42        std::mem::forget(mem);
43        ptr
44    }
45}
46
47impl FromLibSQL for String {
48    fn from_libsql_type(wasm_ptr: i32) -> Self {
49        <&str>::from_libsql_type(wasm_ptr).to_owned()
50    }
51}
52
53impl IntoLibSQL for String {
54    fn into_libsql_type(self) -> i32 {
55        self.as_str().into_libsql_type()
56    }
57}
58
59impl FromLibSQL for &mut [u8] {
60    fn from_libsql_type(wasm_ptr: i32) -> Self {
61        let raw_ptr = wasm_ptr as *const c_void;
62        if unsafe { *(raw_ptr as *const c_char) != SQLITE_BLOB as c_char } {
63            &mut []
64        } else {
65            let size = unsafe {
66                u32::from_be_bytes(
67                    core::slice::from_raw_parts(raw_ptr.offset(1) as *const u8, 4)
68                        .try_into()
69                        .unwrap_or([0_u8, 0_u8, 0_u8, 0_u8]),
70                )
71            };
72            unsafe { core::slice::from_raw_parts_mut(raw_ptr.offset(5) as *mut u8, size as usize) }
73        }
74    }
75}
76
77impl IntoLibSQL for Vec<u8> {
78    fn into_libsql_type(self) -> i32 {
79        let mut mem: Vec<u8> = vec![0; self.len() + 5];
80        mem[0] = SQLITE_BLOB;
81        mem[1..5].copy_from_slice(&u32::to_be_bytes(self.len() as u32));
82        mem[5..].copy_from_slice(&self);
83        let ptr = mem.as_ptr() as i32;
84        std::mem::forget(mem);
85        ptr
86    }
87}
88
89impl<T: FromLibSQL> FromLibSQL for Option<T> {
90    fn from_libsql_type(wasm_ptr: i32) -> Self {
91        let raw_ptr = wasm_ptr as *const c_char;
92        unsafe {
93            if *raw_ptr == SQLITE_NULL as c_char {
94                None
95            } else {
96                Some(<T>::from_libsql_type(wasm_ptr))
97            }
98        }
99    }
100}
101
102#[no_mangle]
103pub unsafe extern "C" fn libsql_malloc(size: usize) -> usize {
104    let buffer = Vec::<u8>::with_capacity(size);
105    let ptr = Vec::leak(buffer);
106    ptr.as_ptr() as usize
107}