d4_bigwig/
lib.rs

1mod bigwig_sys;
2
3use bigwig_sys::*;
4use std::ffi::{CStr, CString};
5use std::os::unix::ffi::OsStrExt;
6use std::path::Path;
7
8pub struct BigWigFile(*mut bigWigFile_t);
9
10impl Drop for BigWigFile {
11    fn drop(&mut self) {
12        unsafe {
13            bwClose(self.0);
14        }
15    }
16}
17
18pub struct BigWigInterval {
19    pub begin: u32,
20    pub end: u32,
21    pub value: f32,
22}
23
24pub struct BigWigIntervalIter {
25    result: *mut bwOverlappingIntervals_t,
26    idx: isize,
27}
28
29impl Drop for BigWigIntervalIter {
30    fn drop(&mut self) {
31        unsafe {
32            bwDestroyOverlappingIntervals(self.result);
33        }
34    }
35}
36
37impl Iterator for BigWigIntervalIter {
38    type Item = BigWigInterval;
39    fn next(&mut self) -> Option<BigWigInterval> {
40        let size = unsafe { *self.result }.l;
41        if size as isize <= self.idx {
42            return None;
43        }
44        let begin = unsafe { *self.result.as_ref().unwrap().start.offset(self.idx) };
45        let end = unsafe { *self.result.as_ref().unwrap().end.offset(self.idx) };
46        let value = unsafe { *self.result.as_ref().unwrap().value.offset(self.idx) };
47
48        self.idx += 1;
49        Some(BigWigInterval { begin, end, value })
50    }
51}
52
53impl BigWigFile {
54    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, std::io::Error> {
55        let handle = unsafe {
56            let path_buf = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
57            let mod_buf = CString::new("r").unwrap();
58            bwOpen(
59                path_buf.as_ptr() as *mut _,
60                None,
61                mod_buf.as_ptr() as *mut _,
62            )
63        };
64
65        if handle.is_null() {
66            return Err(std::io::Error::new(
67                std::io::ErrorKind::Other,
68                "Cannot open BW file",
69            ));
70        }
71        Ok(BigWigFile(handle))
72    }
73
74    pub fn chroms(&self) -> Vec<(String, usize)> {
75        let chrom_info = unsafe { (*self.0).cl.as_ref().unwrap() };
76
77        let mut ret = Vec::with_capacity(chrom_info.nKeys as usize);
78
79        for i in 0..chrom_info.nKeys as isize {
80            let (name, size) = unsafe {
81                let ptr = *chrom_info.chrom.offset(i);
82                let str = CStr::from_ptr(ptr);
83                let name = str.to_string_lossy();
84
85                let size = *chrom_info.len.offset(i) as usize;
86                (name.to_string(), size)
87            };
88
89            ret.push((name, size));
90        }
91        ret
92    }
93
94    pub fn query_range(&self, chrom: &str, left: u32, right: u32) -> Option<BigWigIntervalIter> {
95        let str = CString::new(chrom).unwrap();
96        let chrom = str.as_ptr();
97        let handle = unsafe { bwGetOverlappingIntervals(self.0 as _, chrom as _, left, right) };
98        if handle.is_null() {
99            return None;
100        }
101        Some(BigWigIntervalIter {
102            result: handle,
103            idx: 0,
104        })
105    }
106}