use std::ffi::CStr;
use std::os::raw::c_char;
use std::slice;
use crate::prelude::*;
use crate::sketch::nodegraph::Nodegraph;
use crate::ffi::minhash::SourmashKmerMinHash;
use crate::ffi::utils::ForeignObject;
pub struct SourmashNodegraph;
impl ForeignObject for SourmashNodegraph {
type RustObject = Nodegraph;
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_new() -> *mut SourmashNodegraph {
unsafe { SourmashNodegraph::from_rust(Nodegraph::default()) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_free(ptr: *mut SourmashNodegraph) {
unsafe { SourmashNodegraph::drop(ptr) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_buffer_free(ptr: *mut u8, insize: usize) {
if ptr.is_null() {
return;
}
unsafe { Vec::from_raw_parts(ptr, insize, insize) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_with_tables(
ksize: usize,
starting_size: usize,
n_tables: usize,
) -> *mut SourmashNodegraph {
let ng = Nodegraph::with_tables(starting_size, n_tables, ksize);
unsafe { SourmashNodegraph::from_rust(ng) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_count(ptr: *mut SourmashNodegraph, h: u64) -> bool {
let ng = unsafe { SourmashNodegraph::as_rust_mut(ptr) };
ng.count(h)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_count_kmer(
ptr: *mut SourmashNodegraph,
kmer: *const c_char,
) -> bool {
let ng = unsafe { SourmashNodegraph::as_rust_mut(ptr) };
let c_str = {
assert!(!kmer.is_null());
unsafe { CStr::from_ptr(kmer) }
};
ng.count_kmer(c_str.to_bytes())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_get(ptr: *const SourmashNodegraph, h: u64) -> usize {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
ng.get(h)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_get_kmer(
ptr: *const SourmashNodegraph,
kmer: *const c_char,
) -> usize {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
let c_str = {
assert!(!kmer.is_null());
unsafe { CStr::from_ptr(kmer) }
};
ng.get_kmer(c_str.to_bytes())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_expected_collisions(ptr: *const SourmashNodegraph) -> f64 {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
ng.expected_collisions()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_ksize(ptr: *const SourmashNodegraph) -> usize {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
ng.ksize()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_hashsizes(
ptr: *const SourmashNodegraph,
size: *mut usize,
) -> *const u64 {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
let st = ng.tablesizes();
let b = st.into_boxed_slice();
unsafe { *size = b.len() };
Box::into_raw(b) as *const u64
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_ntables(ptr: *const SourmashNodegraph) -> usize {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
ng.ntables()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_noccupied(ptr: *const SourmashNodegraph) -> usize {
let ng = unsafe { SourmashNodegraph::as_rust(ptr) };
ng.noccupied()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_matches(
ptr: *const SourmashNodegraph,
mh_ptr: *const SourmashKmerMinHash,
) -> usize {
unsafe {
let ng = SourmashNodegraph::as_rust(ptr);
let mh = SourmashKmerMinHash::as_rust(mh_ptr);
ng.matches(mh)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_update(
ptr: *mut SourmashNodegraph,
optr: *const SourmashNodegraph,
) {
unsafe {
let ng = SourmashNodegraph::as_rust_mut(ptr);
let ong = SourmashNodegraph::as_rust(optr);
ong.update(ng).unwrap();
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nodegraph_update_mh(
ptr: *mut SourmashNodegraph,
optr: *const SourmashKmerMinHash,
) {
unsafe {
let ng = SourmashNodegraph::as_rust_mut(ptr);
let mh = SourmashKmerMinHash::as_rust(optr);
mh.update(ng).unwrap();
}
}
ffi_fn! {
unsafe fn nodegraph_from_path(filename: *const c_char) -> Result<*mut SourmashNodegraph> {
let c_str = {
assert!(!filename.is_null());
CStr::from_ptr(filename)
};
let (mut input, _) = niffler::from_path(c_str.to_str()?)?;
let ng = Nodegraph::from_reader(&mut input)?;
Ok(SourmashNodegraph::from_rust(ng))
}
}
ffi_fn! {
unsafe fn nodegraph_from_buffer(ptr: *const c_char, insize: usize) -> Result<*mut SourmashNodegraph> {
let buf = {
assert!(!ptr.is_null());
slice::from_raw_parts(ptr as *mut u8, insize)
};
let ng = Nodegraph::from_reader(buf)?;
Ok(SourmashNodegraph::from_rust(ng))
}
}
ffi_fn! {
unsafe fn nodegraph_save(ptr: *const SourmashNodegraph, filename: *const c_char) -> Result<()> {
let ng = SourmashNodegraph::as_rust(ptr);
let c_str = {
assert!(!filename.is_null());
CStr::from_ptr(filename)
};
ng.save(c_str.to_str()?)?;
Ok(())
}
}
ffi_fn! {
unsafe fn nodegraph_to_buffer(ptr: *const SourmashNodegraph, compression: u8, size: *mut usize) -> Result<*const u8> {
let ng = SourmashNodegraph::as_rust(ptr);
let mut buffer = vec![];
{
let mut writer = if compression > 0 {
let level = match compression {
1 => niffler::compression::Level::One,
2 => niffler::compression::Level::Two,
3 => niffler::compression::Level::Three,
4 => niffler::compression::Level::Four,
5 => niffler::compression::Level::Five,
6 => niffler::compression::Level::Six,
7 => niffler::compression::Level::Seven,
8 => niffler::compression::Level::Eight,
_ => niffler::compression::Level::Nine,
};
niffler::get_writer(Box::new(&mut buffer),
niffler::compression::Format::Gzip,
level)?
} else {
Box::new(&mut buffer)
};
ng.save_to_writer(&mut writer)?;
}
let b = buffer.into_boxed_slice();
*size = b.len();
Ok(Box::into_raw(b) as *const u8)
}
}