extern crate log;
use log::*;
use ::std::slice;
use ::std::os::raw::c_char;
use crate::bindings::*;
pub const EDLIB_STATUS_OK : u32 = 0;
#[allow(dead_code)]
pub const EDLIB_STATUS_ERROR : u32 = 1;
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub enum EdlibAlignModeRs {
EDLIB_MODE_NW,
EDLIB_MODE_SHW,
EDLIB_MODE_HW
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub enum EdlibAlignTaskRs {
EDLIB_TASK_DISTANCE,
EDLIB_TASK_LOC,
EDLIB_TASK_PATH
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub enum EdlibCigarFormatRs {
EDLIB_CIGAR_STANDARD,
EDLIB_CIGAR_EXTENDED
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub enum EdlibEdopRs {
EDLIB_EDOP_MATCH,
EDLIB_EDOP_INSERT,
EDLIB_EDOP_DELETE,
EDLIB_EDOP_MISMATCH
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct EdlibEqualityPairRs {
first : ::std::os::raw::c_char,
second : ::std::os::raw::c_char,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct EdlibAlignConfigRs<'a> {
pub k : i32,
pub mode : EdlibAlignModeRs,
pub task : EdlibAlignTaskRs,
pub additionalequalities : &'a[EdlibEqualityPairRs],
}
impl <'a> EdlibAlignConfigRs<'a> {
pub fn new(k : i32, mode : EdlibAlignModeRs,
task : EdlibAlignTaskRs,
additionalequalities : &'a[EdlibEqualityPairRs]) -> Self {
EdlibAlignConfigRs{k, mode, task, additionalequalities}
}
}
impl <'a> Default for EdlibAlignConfigRs<'a> {
fn default() -> Self {
EdlibAlignConfigRs{ k:-1,
mode : EdlibAlignModeRs::EDLIB_MODE_NW,
task : EdlibAlignTaskRs::EDLIB_TASK_DISTANCE,
additionalequalities : &[]}
}
}
#[derive(Debug,Clone)]
pub struct EdlibAlignResultRs {
pub status : u32,
pub editDistance : i32,
pub endLocations : Option<Vec<i32>>,
pub startLocations : Option<Vec<i32>>,
pub numLocations : usize,
pub alignment : Option<Vec<u8>>,
pub alphabetLength : u32
}
impl EdlibAlignResultRs {
pub fn getDistance(&self) -> i32 {
return self.editDistance;
}
pub fn getEndLocations(&self) -> Option<&Vec<i32>> {
return self.endLocations.as_ref();
}
pub fn getStartLocations(&self) -> Option<&Vec<i32>> {
return self.startLocations.as_ref();
}
pub fn getAlignment(& self) -> Option<&Vec<u8>> {
return self.alignment.as_ref();
}
}
impl Default for EdlibAlignResultRs {
fn default() -> Self {
EdlibAlignResultRs{ status : EDLIB_STATUS_OK,
editDistance : 0,
endLocations : None,
startLocations : None,
numLocations : 0,
alignment : None,
alphabetLength : 0,
}
}
}
pub fn edlibAlignRs(query : &[u8], target : &[u8], config_rs : &EdlibAlignConfigRs) -> EdlibAlignResultRs {
let mut config_c = unsafe { edlibDefaultAlignConfig() };
config_c.k = config_rs.k as ::std::os::raw::c_int;
config_c.mode = match config_rs.mode {
EdlibAlignModeRs::EDLIB_MODE_NW => 0 as EdlibAlignMode,
EdlibAlignModeRs::EDLIB_MODE_SHW => 1 as EdlibAlignMode,
EdlibAlignModeRs::EDLIB_MODE_HW => 2 as EdlibAlignMode,
};
config_c.task = match config_rs.task {
EdlibAlignTaskRs::EDLIB_TASK_DISTANCE => 0 as EdlibAlignTask,
EdlibAlignTaskRs::EDLIB_TASK_LOC => 1 as EdlibAlignTask,
EdlibAlignTaskRs::EDLIB_TASK_PATH => 2 as EdlibAlignTask,
};
config_c.additionalEqualitiesLength = config_rs.additionalequalities.len() as ::std::os::raw::c_int;
if config_c.additionalEqualitiesLength > 0 {
config_c.additionalEqualities = config_rs.additionalequalities.as_ptr() as *const EdlibEqualityPair;
}
else {
config_c.additionalEqualities = ::std::ptr::null::<EdlibEqualityPair>();
}
trace!("avant call edlibAlign");
let res_c : EdlibAlignResult = unsafe { edlibAlign(query.as_ptr() as *const ::std::os::raw::c_char,
query.len() as ::std::os::raw::c_int,
target.as_ptr() as *const ::std::os::raw::c_char,
target.len() as ::std::os::raw::c_int,
config_c
)} ;
log::trace!("apres call edlibAlign");
let mut align_res_rs = EdlibAlignResultRs::default();
align_res_rs.status = res_c.status as u32;
align_res_rs.editDistance = res_c.editDistance as i32;
align_res_rs.numLocations = res_c.numLocations as usize;
if res_c.numLocations > 0 {
assert!(res_c.endLocations != std::ptr::null_mut());
let s_end = unsafe { slice::from_raw_parts(res_c.endLocations, res_c.numLocations as usize) };
assert_eq!(s_end.len(), align_res_rs.numLocations);
align_res_rs.endLocations = Some(s_end.to_vec());
if res_c.startLocations != std::ptr::null_mut() {
let s_start : &[::std::os::raw::c_int]= unsafe { slice::from_raw_parts(res_c.startLocations, res_c.numLocations as usize) };
assert_eq!(s_start.len(), align_res_rs.numLocations);
align_res_rs.startLocations = Some(s_start.to_vec());
}
}
if res_c.alignmentLength > 0 {
assert!(res_c.alignment != std::ptr::null_mut(), "null alignment pointer");
let s_align = unsafe { slice::from_raw_parts(res_c.alignment, res_c.alignmentLength as usize) };
align_res_rs.alignment = Some(s_align.to_vec());
}
align_res_rs.alphabetLength = res_c.alphabetLength as u32;
unsafe { edlibFreeAlignResult(res_c); };
trace!("exiting call edlibAlignRs ");
align_res_rs
}
extern "C" { fn free(s :*const c_char); }
pub fn edlibAlignmentToCigarRs(alignment : &[u8], cigarFormat : &EdlibCigarFormatRs) -> String {
let cigarstring : String;
unsafe {
let c_res : *const c_char = edlibAlignmentToCigar(alignment.as_ptr() , alignment.len() as i32 , *cigarFormat as u32);
assert!(c_res != std::ptr::null_mut(), "null cigar string returnd from C");
cigarstring = ::std::ffi::CStr::from_ptr(c_res).to_string_lossy().into_owned();
free(c_res);
}
cigarstring
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_distance_nw() {
env_logger::Builder::from_default_env().init();
trace!("test_distance_nw");
let query = "ACCTCTG";
let target = "ACTCTGAAA";
let align_res = edlibAlignRs(query.as_bytes(), target.as_bytes(), &EdlibAlignConfigRs::default());
assert_eq!(align_res.status, EDLIB_STATUS_OK);
assert_eq!(align_res.getDistance(), 4);
}
#[test]
fn test_distance_shw() {
env_logger::Builder::from_default_env();
trace!("test_distance_shw");
let query = "ACCTCTG";
let target = "ACTCTGAAA";
let mut config = EdlibAlignConfigRs::default();
config.mode = EdlibAlignModeRs::EDLIB_MODE_SHW;
let align_res = edlibAlignRs(query.as_bytes(), target.as_bytes(), &config);
assert_eq!(align_res.status, EDLIB_STATUS_OK);
assert_eq!(align_res.editDistance, 1);
}
#[test]
fn test_distance_hw() {
trace!("test_distance_hw");
let query = "ACCTCTG";
let target = "TTTTTTTTTTTTTTTTTTTTTACTCTGAAA";
let mut config = EdlibAlignConfigRs::default();
config.mode = EdlibAlignModeRs::EDLIB_MODE_HW;
let align_res = edlibAlignRs(query.as_bytes(), target.as_bytes(), &config);
assert_eq!(align_res.status, EDLIB_STATUS_OK);
assert_eq!(align_res.editDistance, 1);
}
#[test]
fn test_distance_hw_with_pair() {
trace!("test_distance_hw_with_pair");
let query = "ACCTCTG";
let target = "TTTTTTTTTTTTTTTTTTTTTNCTCTXAAA";
let mut equalitypairs = Vec::<EdlibEqualityPairRs>::new();
let pair = EdlibEqualityPairRs{ first:'A' as c_char, second:'N' as c_char};
equalitypairs.push(pair);
let pair = EdlibEqualityPairRs{ first:'G' as c_char, second:'X' as c_char};
equalitypairs.push(pair);
let mut config = EdlibAlignConfigRs::default();
config.mode = EdlibAlignModeRs::EDLIB_MODE_HW;
config.additionalequalities = &equalitypairs;
let align_res = edlibAlignRs(query.as_bytes(), target.as_bytes(), &config);
assert_eq!(align_res.status, EDLIB_STATUS_OK);
assert_eq!(align_res.editDistance, 1);
}
#[test]
fn test_path_hw() {
trace!("test_path_hw");
let query = "missing";
let target = "mississipi";
let mut config = EdlibAlignConfigRs::default();
config.mode = EdlibAlignModeRs::EDLIB_MODE_HW;
config.task = EdlibAlignTaskRs::EDLIB_TASK_PATH;
let align_res = edlibAlignRs(query.as_bytes(), target.as_bytes(), &config);
assert_eq!(align_res.status, EDLIB_STATUS_OK);
assert_eq!(align_res.editDistance, 2);
assert!(align_res.startLocations.is_some());
assert!(align_res.endLocations.is_some());
assert!(align_res.getAlignment().is_some());
let cigar = edlibAlignmentToCigarRs(align_res.alignment.as_ref().unwrap(), &EdlibCigarFormatRs::EDLIB_CIGAR_STANDARD);
println!(" cigar : {:?}", cigar);
assert_eq!(cigar, "5M2I");
let cigarx = edlibAlignmentToCigarRs(align_res.getAlignment().unwrap(), &EdlibCigarFormatRs::EDLIB_CIGAR_EXTENDED);
println!(" cigar : {:?}", cigarx);
assert_eq!(cigarx, "5=2I");
}
#[test]
fn test_distance_nw_with_max_k() {
trace!("test_distance_nw");
let query = "ACCTCTG";
let target = "ACTCTGAAA";
let mut config = EdlibAlignConfigRs::default();
config.k = 3;
let align_res = edlibAlignRs(query.as_bytes(), target.as_bytes(), &config);
assert_eq!(align_res.status, EDLIB_STATUS_OK);
assert_eq!(align_res.getDistance(), -1);
}
}