Acord/core/src/ffi.rs

160 lines
4.3 KiB
Rust

use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::path::Path;
use crate::document::AcordDoc;
use crate::eval;
use crate::highlight;
use crate::persist;
fn cstr_to_str<'a>(ptr: *const c_char) -> Option<&'a str> {
if ptr.is_null() { return None; }
unsafe { CStr::from_ptr(ptr).to_str().ok() }
}
fn str_to_cstr(s: &str) -> *mut c_char {
CString::new(s).unwrap_or_default().into_raw()
}
#[no_mangle]
pub extern "C" fn acord_doc_new() -> *mut AcordDoc {
Box::into_raw(Box::new(AcordDoc::new()))
}
#[no_mangle]
pub extern "C" fn acord_doc_free(doc: *mut AcordDoc) {
if doc.is_null() { return; }
unsafe { drop(Box::from_raw(doc)); }
}
#[no_mangle]
pub extern "C" fn acord_doc_set_text(doc: *mut AcordDoc, text: *const c_char) {
let doc = match unsafe { doc.as_mut() } {
Some(d) => d,
None => return,
};
let text = match cstr_to_str(text) {
Some(s) => s,
None => return,
};
doc.set_text(text);
}
#[no_mangle]
pub extern "C" fn acord_doc_get_text(doc: *const AcordDoc) -> *mut c_char {
let doc = match unsafe { doc.as_ref() } {
Some(d) => d,
None => return std::ptr::null_mut(),
};
str_to_cstr(&doc.text)
}
#[no_mangle]
pub extern "C" fn acord_doc_evaluate(doc: *mut AcordDoc) -> *mut c_char {
let doc = match unsafe { doc.as_mut() } {
Some(d) => d,
None => return str_to_cstr("[]"),
};
let result = doc.evaluate();
let json = serde_json::to_string(&result).unwrap_or_else(|_| "[]".into());
str_to_cstr(&json)
}
#[no_mangle]
pub extern "C" fn acord_eval_line(text: *const c_char) -> *mut c_char {
let text = match cstr_to_str(text) {
Some(s) => s,
None => return str_to_cstr(""),
};
match eval::evaluate_line(text) {
Ok(result) => str_to_cstr(&result),
Err(e) => str_to_cstr(&format!("error: {}", e)),
}
}
#[no_mangle]
pub extern "C" fn acord_doc_save(doc: *const AcordDoc, path: *const c_char) -> bool {
let doc = match unsafe { doc.as_ref() } {
Some(d) => d,
None => return false,
};
let path = match cstr_to_str(path) {
Some(s) => s,
None => return false,
};
persist::save_to_file(&doc.text, Path::new(path)).is_ok()
}
#[no_mangle]
pub extern "C" fn acord_doc_load(path: *const c_char) -> *mut AcordDoc {
let path = match cstr_to_str(path) {
Some(s) => s,
None => return std::ptr::null_mut(),
};
match persist::load_from_file(Path::new(path)) {
Ok(text) => {
let mut doc = AcordDoc::new();
doc.set_text(&text);
Box::into_raw(Box::new(doc))
}
Err(_) => std::ptr::null_mut(),
}
}
#[no_mangle]
pub extern "C" fn acord_cache_save(doc: *const AcordDoc) -> *mut c_char {
let doc = match unsafe { doc.as_ref() } {
Some(d) => d,
None => return std::ptr::null_mut(),
};
let uuid = doc.uuid.clone();
match persist::cache_save(&uuid, &doc.text) {
Ok(_) => str_to_cstr(&uuid),
Err(_) => std::ptr::null_mut(),
}
}
#[no_mangle]
pub extern "C" fn acord_cache_load(uuid: *const c_char) -> *mut AcordDoc {
let uuid = match cstr_to_str(uuid) {
Some(s) => s,
None => return std::ptr::null_mut(),
};
match persist::cache_load(uuid) {
Ok(text) => {
let mut doc = AcordDoc::with_uuid(uuid.to_string());
doc.set_text(&text);
Box::into_raw(Box::new(doc))
}
Err(_) => std::ptr::null_mut(),
}
}
#[no_mangle]
pub extern "C" fn acord_list_notes() -> *mut c_char {
let notes = persist::list_notes();
let json = serde_json::to_string(&notes).unwrap_or_else(|_| "[]".into());
str_to_cstr(&json)
}
#[no_mangle]
pub extern "C" fn acord_highlight(source: *const c_char, lang: *const c_char) -> *mut c_char {
let source = match cstr_to_str(source) {
Some(s) => s,
None => return str_to_cstr("[]"),
};
let lang = match cstr_to_str(lang) {
Some(s) => s,
None => return str_to_cstr("[]"),
};
let spans = highlight::highlight_source(source, lang);
let json = serde_json::to_string(&spans).unwrap_or_else(|_| "[]".into());
str_to_cstr(&json)
}
#[no_mangle]
pub extern "C" fn acord_free_string(s: *mut c_char) {
if s.is_null() { return; }
unsafe { drop(CString::from_raw(s)); }
}