1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use anyhow::anyhow;

use crate::fst::CFst;
use crate::{get, wrap, RUSTFST_FFI_RESULT};

use ffi_convert::*;
use rustfst::algorithms::{shortest_path, shortest_path_with_config, ShortestPathConfig};
use rustfst::fst_impls::VectorFst;
use rustfst::semirings::TropicalWeight;

#[derive(AsRust, CReprOf, CDrop, RawPointerConverter)]
#[target_type(ShortestPathConfig)]
pub struct CShortestPathConfig {
    delta: f32,
    nshortest: usize,
    unique: bool,
}

#[no_mangle]
pub extern "C" fn fst_shortest_path_config_new(
    delta: libc::c_float,
    nshortest: libc::size_t,
    unique: bool,
    ptr: *mut *const CShortestPathConfig,
) -> RUSTFST_FFI_RESULT {
    wrap(|| {
        let config = CShortestPathConfig {
            delta,
            nshortest,
            unique,
        };
        unsafe { *ptr = config.into_raw_pointer() };
        Ok(())
    })
}

#[no_mangle]
pub extern "C" fn fst_shortest_path(
    ptr: *const CFst,
    res_fst: *mut *const CFst,
) -> RUSTFST_FFI_RESULT {
    wrap(|| {
        let fst = get!(CFst, ptr);
        let vec_fst: &VectorFst<TropicalWeight> = fst
            .downcast_ref()
            .ok_or_else(|| anyhow!("Could not downcast to vector FST"))?;
        let res: VectorFst<TropicalWeight> = shortest_path(vec_fst)?;
        unsafe { *res_fst = CFst(Box::new(res)).into_raw_pointer() };
        Ok(())
    })
}

#[no_mangle]
pub extern "C" fn fst_shortest_path_with_config(
    ptr: *const CFst,
    config: *const CShortestPathConfig,
    res_fst: *mut *const CFst,
) -> RUSTFST_FFI_RESULT {
    wrap(|| {
        let fst = get!(CFst, ptr);
        let vec_fst: &VectorFst<TropicalWeight> = fst
            .downcast_ref()
            .ok_or_else(|| anyhow!("Could not downcast to vector FST"))?;

        let config = unsafe {
            <CShortestPathConfig as ffi_convert::RawBorrow<CShortestPathConfig>>::raw_borrow(
                config,
            )?
        };
        let res: VectorFst<TropicalWeight> = shortest_path_with_config(vec_fst, config.as_rust()?)?;
        unsafe { *res_fst = CFst(Box::new(res)).into_raw_pointer() };
        Ok(())
    })
}