rustfst_ffi/
lib.rs

1#![allow(clippy::single_component_path_imports)]
2
3pub mod algorithms;
4pub mod fst;
5pub mod iterators;
6pub mod string_path;
7pub mod string_paths_iterator;
8pub mod symbol_table;
9pub mod tr;
10pub mod trs;
11
12use std::cell::RefCell;
13use std::ffi::CString;
14use std::sync::Arc;
15
16use anyhow::Result;
17use ffi_convert::{CReprOf, RawPointerConverter};
18
19#[cfg(feature = "rustfst-state-label-u32")]
20pub type CLabel = libc::c_uint;
21#[cfg(not(feature = "rustfst-state-label-u32"))]
22pub type CLabel = libc::size_t;
23
24#[cfg(feature = "rustfst-state-label-u32")]
25pub type CStateId = libc::c_uint;
26#[cfg(not(feature = "rustfst-state-label-u32"))]
27pub type CStateId = libc::size_t;
28
29#[repr(C)]
30#[allow(non_camel_case_types)]
31#[derive(Debug, PartialEq, Eq)]
32pub enum RUSTFST_FFI_RESULT {
33    /// The function returned successfully
34    RUSTFST_FFI_RESULT_OK = 0,
35    /// The function returned an error
36    RUSTFST_FFI_RESULT_KO = 1,
37}
38
39thread_local! {
40    pub(crate) static LAST_ERROR: RefCell<Option<String>> = const { RefCell::new(None) };
41}
42
43pub fn wrap<F: FnOnce() -> Result<()>>(func: F) -> RUSTFST_FFI_RESULT {
44    match func() {
45        Ok(_) => RUSTFST_FFI_RESULT::RUSTFST_FFI_RESULT_OK,
46        Err(e) => {
47            let msg = format!("{:#?}", e);
48            if std::env::var("AMSTRAM_FFI_ERROR_STDERR").is_ok() {
49                eprintln!("{}", msg);
50            }
51            LAST_ERROR.with(|p| *p.borrow_mut() = Some(msg));
52            RUSTFST_FFI_RESULT::RUSTFST_FFI_RESULT_KO
53        }
54    }
55}
56
57/// # Safety
58///
59/// Should never happen
60#[no_mangle]
61pub unsafe extern "C" fn rustfst_ffi_get_last_error(
62    error: *mut *mut ::libc::c_char,
63) -> RUSTFST_FFI_RESULT {
64    wrap(move || {
65        LAST_ERROR.with(|msg| {
66            let string = msg
67                .borrow_mut()
68                .take()
69                .unwrap_or_else(|| "No error message".to_string());
70            let result: *const ::libc::c_char =
71                std::ffi::CString::c_repr_of(string)?.into_raw_pointer();
72            unsafe { *error = result as _ }
73            Ok(())
74        })
75    })
76}
77
78#[allow(clippy::missing_safety_doc)]
79#[no_mangle]
80pub unsafe extern "C" fn rustfst_destroy_string(string: *mut libc::c_char) -> RUSTFST_FFI_RESULT {
81    wrap(|| {
82        CString::drop_raw_pointer(string)?;
83        Ok(())
84    })
85}
86
87macro_rules! get_mut {
88    ($typ:ty,$opaque:ident) => {{
89        &mut unsafe { <$typ as ffi_convert::RawBorrowMut<$typ>>::raw_borrow_mut($opaque) }?.0
90    }};
91}
92
93macro_rules! get {
94    ($typ:ty,$opaque:ident) => {{
95        &unsafe { <$typ as ffi_convert::RawBorrow<$typ>>::raw_borrow($opaque) }?.0
96    }};
97}
98
99use crate::symbol_table::CSymbolTable;
100pub(crate) use get;
101pub(crate) use get_mut;
102use rustfst::SymbolTable;
103
104pub(crate) fn get_symt(symt: *const CSymbolTable) -> Result<Option<&'static Arc<SymbolTable>>> {
105    if symt.is_null() {
106        return Ok(None);
107    }
108    Ok(Some(get!(CSymbolTable, symt)))
109}