use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_int, c_void}; #[link(name = "guile-3.0")] extern "C" { fn scm_init_guile(); fn scm_c_eval_string(expr: *const c_char) -> *mut c_void; fn scm_to_locale_string(scm_obj: *mut c_void) -> *const c_char; fn scm_is_string(scm_obj: *mut c_void) -> c_int; fn scm_object_to_string(scm_obj: *mut c_void, printer: *mut c_void) -> *mut c_void; } #[link(name = "guiledefs")] extern "C" { pub static scm_undefined: *mut c_void; pub static scm_unspecified: *mut c_void; fn defs_scm_is_eq(x: *mut c_void, y: *mut c_void) -> c_int; fn defs_scm_define_string(name: *const c_char, value: *const c_char); } /// Convert a scm object into a string using Guile-builtins fn string_from_scm(scm_obj: *mut c_void) -> Result { unsafe { if scm_obj.is_null() { return Err(()); } if defs_scm_is_eq(scm_obj, scm_unspecified) != 0 { return Ok(String::new()); } else if scm_is_string(scm_obj) != 0 { let res_str = CStr::from_ptr(scm_to_locale_string(scm_obj)) .to_string_lossy() .into_owned(); return Ok(res_str); } else { let res = scm_object_to_string(scm_obj, scm_undefined); if res.is_null() { return Err(()); } let res_str = CStr::from_ptr(scm_to_locale_string(res)) .to_string_lossy() .into_owned(); return Ok(res_str); } } } #[derive(Clone)] pub struct Guile {} impl Guile { pub fn new() -> Self { unsafe { scm_init_guile(); } Guile {} } pub fn evaluate_expression(&self, expr: &str) -> Result { unsafe { let c_expr = CString::new(expr).map_err(|_| ())?; let result = scm_c_eval_string(c_expr.as_ptr()); string_from_scm(result) } } pub fn define_string(&self, name: &str, value: &str) { let c_name = CString::new(name).expect("CString::new failed"); let c_value = CString::new(value).expect("CString::new failed"); unsafe { defs_scm_define_string(c_name.as_ptr(), c_value.as_ptr()); } } } impl Drop for Guile { fn drop(&mut self) { if let Err(e) = self.evaluate_expression("(exit)") { panic!("Error while exiting {:#?}", e); } } }