sourmash/ffi/
nodegraph.rs

1use std::ffi::CStr;
2use std::os::raw::c_char;
3use std::slice;
4
5use crate::prelude::*;
6use crate::sketch::nodegraph::Nodegraph;
7
8use crate::ffi::minhash::SourmashKmerMinHash;
9use crate::ffi::utils::ForeignObject;
10
11pub struct SourmashNodegraph;
12
13impl ForeignObject for SourmashNodegraph {
14    type RustObject = Nodegraph;
15}
16
17#[no_mangle]
18pub unsafe extern "C" fn nodegraph_new() -> *mut SourmashNodegraph {
19    SourmashNodegraph::from_rust(Nodegraph::default())
20}
21
22#[no_mangle]
23pub unsafe extern "C" fn nodegraph_free(ptr: *mut SourmashNodegraph) {
24    SourmashNodegraph::drop(ptr);
25}
26
27#[no_mangle]
28pub unsafe extern "C" fn nodegraph_buffer_free(ptr: *mut u8, insize: usize) {
29    if ptr.is_null() {
30        return;
31    }
32    Vec::from_raw_parts(ptr, insize, insize);
33}
34
35#[no_mangle]
36pub unsafe extern "C" fn nodegraph_with_tables(
37    ksize: usize,
38    starting_size: usize,
39    n_tables: usize,
40) -> *mut SourmashNodegraph {
41    let ng = Nodegraph::with_tables(starting_size, n_tables, ksize);
42    SourmashNodegraph::from_rust(ng)
43}
44
45#[no_mangle]
46pub unsafe extern "C" fn nodegraph_count(ptr: *mut SourmashNodegraph, h: u64) -> bool {
47    let ng = SourmashNodegraph::as_rust_mut(ptr);
48    ng.count(h)
49}
50
51#[no_mangle]
52pub unsafe extern "C" fn nodegraph_count_kmer(
53    ptr: *mut SourmashNodegraph,
54    kmer: *const c_char,
55) -> bool {
56    let ng = SourmashNodegraph::as_rust_mut(ptr);
57
58    // FIXME use buffer + len instead of cstr
59    let c_str = {
60        assert!(!kmer.is_null());
61
62        CStr::from_ptr(kmer)
63    };
64
65    ng.count_kmer(c_str.to_bytes())
66}
67
68#[no_mangle]
69pub unsafe extern "C" fn nodegraph_get(ptr: *const SourmashNodegraph, h: u64) -> usize {
70    let ng = SourmashNodegraph::as_rust(ptr);
71    ng.get(h)
72}
73
74#[no_mangle]
75pub unsafe extern "C" fn nodegraph_get_kmer(
76    ptr: *const SourmashNodegraph,
77    kmer: *const c_char,
78) -> usize {
79    let ng = SourmashNodegraph::as_rust(ptr);
80
81    // FIXME use buffer + len instead of cstr
82    let c_str = {
83        assert!(!kmer.is_null());
84
85        CStr::from_ptr(kmer)
86    };
87
88    ng.get_kmer(c_str.to_bytes())
89}
90
91#[no_mangle]
92pub unsafe extern "C" fn nodegraph_expected_collisions(ptr: *const SourmashNodegraph) -> f64 {
93    let ng = SourmashNodegraph::as_rust(ptr);
94    ng.expected_collisions()
95}
96
97#[no_mangle]
98pub unsafe extern "C" fn nodegraph_ksize(ptr: *const SourmashNodegraph) -> usize {
99    let ng = SourmashNodegraph::as_rust(ptr);
100    ng.ksize()
101}
102
103#[no_mangle]
104pub unsafe extern "C" fn nodegraph_hashsizes(
105    ptr: *const SourmashNodegraph,
106    size: *mut usize,
107) -> *const u64 {
108    let ng = SourmashNodegraph::as_rust(ptr);
109    let st = ng.tablesizes();
110
111    let b = st.into_boxed_slice();
112    *size = b.len();
113
114    // FIXME: Use SourmashSlice_u64?
115    Box::into_raw(b) as *const u64
116}
117
118#[no_mangle]
119pub unsafe extern "C" fn nodegraph_ntables(ptr: *const SourmashNodegraph) -> usize {
120    let ng = SourmashNodegraph::as_rust(ptr);
121    ng.ntables()
122}
123
124#[no_mangle]
125pub unsafe extern "C" fn nodegraph_noccupied(ptr: *const SourmashNodegraph) -> usize {
126    let ng = SourmashNodegraph::as_rust(ptr);
127    ng.noccupied()
128}
129
130#[no_mangle]
131pub unsafe extern "C" fn nodegraph_matches(
132    ptr: *const SourmashNodegraph,
133    mh_ptr: *const SourmashKmerMinHash,
134) -> usize {
135    let ng = SourmashNodegraph::as_rust(ptr);
136    let mh = SourmashKmerMinHash::as_rust(mh_ptr);
137    ng.matches(mh)
138}
139
140#[no_mangle]
141pub unsafe extern "C" fn nodegraph_update(
142    ptr: *mut SourmashNodegraph,
143    optr: *const SourmashNodegraph,
144) {
145    let ng = SourmashNodegraph::as_rust_mut(ptr);
146    let ong = SourmashNodegraph::as_rust(optr);
147
148    // FIXME raise an exception properly
149    ong.update(ng).unwrap();
150}
151
152#[no_mangle]
153pub unsafe extern "C" fn nodegraph_update_mh(
154    ptr: *mut SourmashNodegraph,
155    optr: *const SourmashKmerMinHash,
156) {
157    let ng = SourmashNodegraph::as_rust_mut(ptr);
158    let mh = SourmashKmerMinHash::as_rust(optr);
159
160    mh.update(ng).unwrap();
161}
162
163ffi_fn! {
164unsafe fn nodegraph_from_path(filename: *const c_char) -> Result<*mut SourmashNodegraph> {
165    // FIXME use buffer + len instead of c_str
166    let c_str = {
167        assert!(!filename.is_null());
168
169        CStr::from_ptr(filename)
170    };
171
172    let (mut input, _) = niffler::from_path(c_str.to_str()?)?;
173    let ng = Nodegraph::from_reader(&mut input)?;
174
175    Ok(SourmashNodegraph::from_rust(ng))
176}
177}
178
179ffi_fn! {
180unsafe fn nodegraph_from_buffer(ptr: *const c_char, insize: usize) -> Result<*mut SourmashNodegraph> {
181    // FIXME use SourmashSlice_u8?
182    let buf = {
183        assert!(!ptr.is_null());
184        slice::from_raw_parts(ptr as *mut u8, insize)
185    };
186
187    let ng = Nodegraph::from_reader(buf)?;
188
189    Ok(SourmashNodegraph::from_rust(ng))
190}
191}
192
193ffi_fn! {
194unsafe fn nodegraph_save(ptr: *const SourmashNodegraph, filename: *const c_char) -> Result<()> {
195    let ng = SourmashNodegraph::as_rust(ptr);
196
197    // FIXME use buffer + len instead of c_str
198    let c_str = {
199        assert!(!filename.is_null());
200
201        CStr::from_ptr(filename)
202    };
203
204    ng.save(c_str.to_str()?)?;
205
206    Ok(())
207}
208}
209
210ffi_fn! {
211unsafe fn nodegraph_to_buffer(ptr: *const SourmashNodegraph, compression: u8, size: *mut usize) -> Result<*const u8> {
212    let ng = SourmashNodegraph::as_rust(ptr);
213
214    let mut buffer = vec![];
215    {
216      let mut writer = if compression > 0 {
217          let level = match compression {
218            1 => niffler::compression::Level::One,
219            2 => niffler::compression::Level::Two,
220            3 => niffler::compression::Level::Three,
221            4 => niffler::compression::Level::Four,
222            5 => niffler::compression::Level::Five,
223            6 => niffler::compression::Level::Six,
224            7 => niffler::compression::Level::Seven,
225            8 => niffler::compression::Level::Eight,
226            _ => niffler::compression::Level::Nine,
227          };
228
229          niffler::get_writer(Box::new(&mut buffer),
230                              niffler::compression::Format::Gzip,
231                              level)?
232      } else {
233          Box::new(&mut buffer)
234      };
235      ng.save_to_writer(&mut writer)?;
236    }
237
238    let b = buffer.into_boxed_slice();
239    *size = b.len();
240
241    // FIXME use SourmashSlice_u8?
242    Ok(Box::into_raw(b) as *const u8)
243}
244}