hfst_sys/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5#![cfg(docsrs)]
6#![feature(builtin_syntax)]
7
8include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
9
10#[cfg(test)]
11mod tests {
12    use super::*;
13    use std::{os::raw::c_char, str::Utf8Error};
14
15    /// Length of c string
16    fn strlen(s: *const c_char) -> usize {
17        let mut len = 0;
18        while unsafe { *s.add(len) } != 0 {
19            len += 1;
20        }
21        len
22    }
23
24    /// Make a String from a c string
25    fn c_charptr_to_string(s: *const c_char) -> String {
26        let len = strlen(s);
27        unsafe { String::from_raw_parts(s as *mut u8, len, len) }
28    }
29
30    fn c_charptr_as_str<'a>(s: *const c_char) -> Result<&'a str, Utf8Error> {
31        unsafe {
32            std::str::from_utf8(
33                std::slice::from_raw_parts(s as *const u8, strlen(s))
34            )
35        }
36    }
37
38    fn c_charptr_as_str_unchecked<'a>(s: *const c_char) -> &'a str {
39        unsafe {
40            std::str::from_utf8_unchecked(
41                std::slice::from_raw_parts(s as *const u8, strlen(s))
42            )
43        }
44    }
45
46    trait RemoveAts {
47        fn remove_ats(self) -> String;
48    }
49
50    impl RemoveAts for &str {
51        fn remove_ats(self) -> String {
52            remove_ats(self)
53        }
54    }
55
56    /// Remove everything between '@' from `s`.
57    /// E.g.
58    /// "@_____@HEY@____@THERE" => "HEYTHERE"
59    fn remove_ats(s: &str) -> String {
60        let at_positions = s
61            .char_indices()
62            .filter_map(|(pos, ch)| (ch == '@').then_some(pos as i64));
63
64        let it = std::iter::once(-1i64)
65            .chain(at_positions)
66            .chain(std::iter::once(s.len() as i64));
67
68        let mut out = String::new();
69        let mut every_other = false;
70        let mut a: usize = 0;
71
72        for el in it {
73            if every_other {
74                out.push_str(&s[a..el as usize]);
75            } else {
76                a = (el + 1) as usize;
77            }
78            every_other = !every_other;
79        }
80
81        out
82    }
83
84    #[test]
85    #[ignore]
86    fn open_read_close() -> Result<(), String> {
87        let path = "/usr/share/giella/sme/analyser-dict-gt-desc.hfstol\0";
88        let path = path.as_ptr() as *const c_char;
89        let input_stream = unsafe { hfst_input_stream(path) };
90        if input_stream.is_null() {
91            return Err(format!("input_stream was NULL"));
92        }
93        assert!(unsafe { !hfst_input_stream_is_bad(input_stream) });
94
95        let tr = unsafe { hfst_transducer_from_stream(input_stream) };
96        assert!(!tr.is_null());
97
98        let mut expected_analyses = std::collections::HashMap::new();
99        expected_analyses.insert("viessat+V+IV+Imprt+Du1", false);
100        expected_analyses.insert("viessut+V+IV+Imprt+Du1", false);
101        expected_analyses.insert("viessut+V+IV+Imprt+Du2", false);
102        expected_analyses.insert("viessut+V+IV+Ind+Prs+Sg3", false);
103        expected_analyses.insert("viessut+V+IV+PrsPrc", false);
104        expected_analyses.insert("viessu+N+Sg+Nom", false);
105
106        let lookup_str = "viessu\0".as_ptr() as *const c_char;
107        let lookup = unsafe { hfst_lookup(tr, lookup_str) };
108        let iter = unsafe { hfst_lookup_iterator(lookup) };
109
110        unsafe {
111            let mut w = 0.0f32;
112            let mut s: *mut c_char = std::ptr::null_mut();
113            while !hfst_lookup_iterator_done(iter) {
114                hfst_lookup_iterator_value(
115                    iter,
116                    &raw mut s,
117                    &mut w,
118                );
119
120                let seen_analysis = c_charptr_as_str_unchecked(s).remove_ats();
121                println!("{}", seen_analysis);
122                let Some(v) = expected_analyses.get_mut(seen_analysis.as_str()) else {
123                    panic!("got an analysis we did not expect: {}", seen_analysis);
124                };
125                *v = true;
126
127                hfst_lookup_iterator_next(iter);
128            }
129        }
130        
131        let all_seen = expected_analyses.into_values().all(|seen| seen == true);
132        assert!(all_seen);
133
134        unsafe { hfst_input_stream_close(input_stream) };
135        Ok(())
136    }
137}