We need C bindings to extend css-inline accessibility to other languages that can work via C.
TODO:
Decide on the public API. Likely it is better to expose inline_to, so the caller is always responsible for managing their memory (otherwise we need to provide a separate function to deallocate the buffer we allocate during inlining with the inline function)
Allow the end-user to configure the inlining process - not yet sure what is the best way to achieve this. E.g. it could be a struct that could be constructed from the C side.
Generate a header file with proper extern declarations (cbindgen or similar as a starting point?)
Document the bindings, specifically focusing on how the caller should manage memory when using this C API.
Write tests in C that ensure our C API works and include them in CI
Notes:
The bindings crate could live in bindings/c
Validate the input from the C side (pointers should be not null)
Maybe we can use some negative values to encode erroneous situations? (e.g. -1 for null pointers, -2 for invalid UTF-8, etc)
Avoid allocating anything on our side
Do not forget the null-terminators (\0) in the output.
Consider using a custom Write impl
It can roughly look like this:
use libc::{c_char, c_int, size_t};
use std::ffi::CStr;
use std::ptr;
#[no_mangle]
pub extern "C" fn inline_to(input: *const c_char, output: *mut c_char, output_size: size_t) -> c_int {
let cstr = unsafe { CStr::from_ptr(input) }.to_str().expect("TODO: handle properly");
// ... Inline impl via `CSSInliner::inline_to`
}
// `Write` impl for a buffer coming from the C side?
use std::io::{self, Write};
struct CBuffer {
buffer: *mut c_char,
buffer_size: size_t,
pos: usize,
}
impl CBuffer {
fn new(buffer: *mut c_char, buffer_size: size_t) -> Self {
Self {
buffer,
buffer_size,
pos: 0,
}
}
}
impl Write for CBuffer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
...
}
fn flush(&mut self) -> io::Result<()> {
...
}
}
We need C bindings to extend
css-inline
accessibility to other languages that can work via C.TODO:
inline_to
, so the caller is always responsible for managing their memory (otherwise we need to provide a separate function to deallocate the buffer we allocate during inlining with theinline
function)extern
declarations (cbindgen
or similar as a starting point?)Notes:
bindings/c
-1
for null pointers,-2
for invalid UTF-8, etc)\0
) in the output.Write
implIt can roughly look like this:
cc @lobziik