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 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 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 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}