use std::borrow::{Borrow, BorrowMut};
use std::f32;
use std::ffi;
use std::fmt;
use std::i32;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr;
use std::rc::Rc;
use std::slice;
use std::str;
use bio_types::genome;
use derive_new::new;
use crate::bcf::header::{HeaderView, Id};
use crate::bcf::Error;
use crate::errors::Result;
use crate::htslib;
const MISSING_INTEGER: i32 = i32::MIN;
const VECTOR_END_INTEGER: i32 = i32::MIN + 1;
const MISSING_FLOAT: u32 = 0x7F80_0001;
const VECTOR_END_FLOAT: u32 = 0x7F80_0002;
pub trait Numeric {
fn is_missing(&self) -> bool;
fn missing() -> Self;
}
impl Numeric for f32 {
fn is_missing(&self) -> bool {
self.to_bits() == MISSING_FLOAT
}
fn missing() -> f32 {
MISSING_FLOAT as f32
}
}
impl Numeric for i32 {
fn is_missing(&self) -> bool {
*self == MISSING_INTEGER
}
fn missing() -> i32 {
MISSING_INTEGER
}
}
trait NumericUtils {
fn is_vector_end(&self) -> bool;
}
impl NumericUtils for f32 {
fn is_vector_end(&self) -> bool {
self.to_bits() == VECTOR_END_FLOAT
}
}
impl NumericUtils for i32 {
fn is_vector_end(&self) -> bool {
*self == VECTOR_END_INTEGER
}
}
#[derive(Debug)]
pub struct Buffer {
inner: *mut ::std::os::raw::c_void,
len: i32,
}
impl Buffer {
pub fn new() -> Self {
Buffer {
inner: ptr::null_mut(),
len: 0,
}
}
}
impl Drop for Buffer {
fn drop(&mut self) {
unsafe {
::libc::free(self.inner as *mut ::libc::c_void);
}
}
}
#[derive(new, Debug)]
pub struct BufferBacked<'a, T: 'a + fmt::Debug, B: Borrow<Buffer> + 'a> {
value: T,
buffer: B,
#[new(default)]
phantom: PhantomData<&'a B>,
}
impl<'a, T: 'a + fmt::Debug, B: Borrow<Buffer> + 'a> Deref for BufferBacked<'a, T, B> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<'a, T: 'a + fmt::Debug + fmt::Display, B: Borrow<Buffer> + 'a> fmt::Display
for BufferBacked<'a, T, B>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.value, f)
}
}
#[derive(Debug)]
pub struct Record {
pub inner: *mut htslib::bcf1_t,
header: Rc<HeaderView>,
}
impl Record {
pub(crate) fn new(header: Rc<HeaderView>) -> Self {
let inner = unsafe {
let inner = htslib::bcf_init();
htslib::bcf_unpack(inner, htslib::BCF_UN_ALL as i32);
inner
};
Record { inner, header }
}
pub fn unpack(&mut self) {
unsafe { htslib::bcf_unpack(self.inner, htslib::BCF_UN_ALL as i32) };
}
pub fn header(&self) -> &HeaderView {
self.header.as_ref()
}
pub(crate) fn set_header(&mut self, header: Rc<HeaderView>) {
self.header = header;
}
pub fn inner(&self) -> &htslib::bcf1_t {
unsafe { &*self.inner }
}
pub fn inner_mut(&mut self) -> &mut htslib::bcf1_t {
unsafe { &mut *self.inner }
}
pub fn rid(&self) -> Option<u32> {
match self.inner().rid {
-1 => None,
rid => Some(rid as u32),
}
}
pub fn set_rid(&mut self, rid: Option<u32>) {
match rid {
Some(rid) => self.inner_mut().rid = rid as i32,
None => self.inner_mut().rid = -1,
}
}
pub fn pos(&self) -> i64 {
self.inner().pos
}
pub fn set_pos(&mut self, pos: i64) {
self.inner_mut().pos = pos;
}
pub fn id(&self) -> Vec<u8> {
if self.inner().d.id.is_null() {
b".".to_vec()
} else {
let id = unsafe { ffi::CStr::from_ptr(self.inner().d.id) };
id.to_bytes().to_vec()
}
}
pub fn set_id(&mut self, id: &[u8]) -> Result<()> {
let c_str = ffi::CString::new(id).unwrap();
if unsafe {
htslib::bcf_update_id(self.header().inner, self.inner, c_str.as_ptr() as *mut i8)
} == 0
{
Ok(())
} else {
Err(Error::BcfSetValues)
}
}
pub fn clear_id(&mut self) -> Result<()> {
let c_str = ffi::CString::new(&b"."[..]).unwrap();
if unsafe {
htslib::bcf_update_id(self.header().inner, self.inner, c_str.as_ptr() as *mut i8)
} == 0
{
Ok(())
} else {
Err(Error::BcfSetValues)
}
}
pub fn push_id(&mut self, id: &[u8]) -> Result<()> {
let c_str = ffi::CString::new(id).unwrap();
if unsafe { htslib::bcf_add_id(self.header().inner, self.inner, c_str.as_ptr() as *mut i8) }
== 0
{
Ok(())
} else {
Err(Error::BcfSetValues)
}
}
pub fn filters(&self) -> Filters<'_> {
Filters::new(self)
}
pub fn has_filter(&self, flt_id: Id) -> bool {
if *flt_id == 0 && self.inner().d.n_flt == 0 {
return true;
}
for i in 0..(self.inner().d.n_flt as isize) {
if unsafe { *self.inner().d.flt.offset(i) } == *flt_id as i32 {
return true;
}
}
false
}
pub fn set_filters(&mut self, flt_ids: &[Id]) {
let mut flt_ids: Vec<i32> = flt_ids.iter().map(|x| **x as i32).collect();
unsafe {
htslib::bcf_update_filter(
self.header().inner,
self.inner,
flt_ids.as_mut_ptr(),
flt_ids.len() as i32,
);
}
}
pub fn push_filter(&mut self, flt_id: Id) {
unsafe {
htslib::bcf_add_filter(self.header().inner, self.inner, *flt_id as i32);
}
}
pub fn remove_filter(&mut self, flt_id: Id, pass_on_empty: bool) {
unsafe {
htslib::bcf_remove_filter(
self.header().inner,
self.inner,
*flt_id as i32,
pass_on_empty as i32,
);
}
}
pub fn alleles(&self) -> Vec<&[u8]> {
unsafe { htslib::bcf_unpack(self.inner, htslib::BCF_UN_ALL as i32) };
let n = self.inner().n_allele() as usize;
let dec = self.inner().d;
let alleles = unsafe { slice::from_raw_parts(dec.allele, n) };
(0..n)
.map(|i| unsafe { ffi::CStr::from_ptr(alleles[i]).to_bytes() })
.collect()
}
pub fn set_alleles(&mut self, alleles: &[&[u8]]) -> Result<()> {
let cstrings: Vec<ffi::CString> = alleles
.iter()
.map(|vec| ffi::CString::new(*vec).unwrap())
.collect();
let mut ptrs: Vec<*const i8> = cstrings
.iter()
.map(|cstr| cstr.as_ptr() as *const i8)
.collect();
if unsafe {
htslib::bcf_update_alleles(
self.header().inner,
self.inner,
ptrs.as_mut_ptr(),
alleles.len() as i32,
)
} == 0
{
Ok(())
} else {
Err(Error::BcfSetValues)
}
}
pub fn qual(&self) -> f32 {
self.inner().qual
}
pub fn set_qual(&mut self, qual: f32) {
self.inner_mut().qual = qual;
}
pub fn info<'a>(&'a self, tag: &'a [u8]) -> Info<'a, Buffer> {
self.info_shared_buffer(tag, Buffer::new())
}
pub fn info_shared_buffer<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b>(
&'a self,
tag: &'a [u8],
buffer: B,
) -> Info<'a, B> {
Info {
record: self,
tag,
buffer,
}
}
pub fn sample_count(&self) -> u32 {
self.inner().n_sample()
}
pub fn allele_count(&self) -> u32 {
self.inner().n_allele()
}
pub fn push_genotypes(&mut self, genotypes: &[GenotypeAllele]) -> Result<()> {
let encoded: Vec<i32> = genotypes.iter().map(|gt| i32::from(*gt)).collect();
self.push_format_integer(b"GT", &encoded)
}
pub fn genotypes(&self) -> Result<Genotypes<'_, Buffer>> {
self.genotypes_shared_buffer(Buffer::new())
}
pub fn genotypes_shared_buffer<'a, B>(&self, buffer: B) -> Result<Genotypes<'a, B>>
where
B: BorrowMut<Buffer> + Borrow<Buffer> + 'a,
{
Ok(Genotypes {
encoded: self.format_shared_buffer(b"GT", buffer).integer()?,
})
}
pub fn format<'a>(&'a self, tag: &'a [u8]) -> Format<'a, Buffer> {
self.format_shared_buffer(tag, Buffer::new())
}
pub fn format_shared_buffer<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b>(
&'a self,
tag: &'a [u8],
buffer: B,
) -> Format<'a, B> {
Format::new(self, tag, buffer)
}
pub fn push_format_integer(&mut self, tag: &[u8], data: &[i32]) -> Result<()> {
self.push_format(tag, data, htslib::BCF_HT_INT)
}
pub fn push_format_float(&mut self, tag: &[u8], data: &[f32]) -> Result<()> {
self.push_format(tag, data, htslib::BCF_HT_REAL)
}
pub fn push_format_char(&mut self, tag: &[u8], data: &[u8]) -> Result<()> {
self.push_format(tag, data, htslib::BCF_HT_STR)
}
fn push_format<T>(&mut self, tag: &[u8], data: &[T], ht: u32) -> Result<()> {
let tag_c_str = ffi::CString::new(tag).unwrap();
unsafe {
if htslib::bcf_update_format(
self.header().inner,
self.inner,
tag_c_str.as_ptr() as *mut i8,
data.as_ptr() as *const ::std::os::raw::c_void,
data.len() as i32,
ht as i32,
) == 0
{
Ok(())
} else {
Err(Error::BcfSetTag {
tag: str::from_utf8(tag).unwrap().to_owned(),
})
}
}
}
pub fn push_format_string<D: Borrow<[u8]>>(&mut self, tag: &[u8], data: &[D]) -> Result<()> {
assert!(
!data.is_empty(),
"given string data must have at least 1 element"
);
let c_data = data
.iter()
.map(|s| ffi::CString::new(s.borrow()).unwrap())
.collect::<Vec<ffi::CString>>();
let c_ptrs = c_data
.iter()
.map(|s| s.as_ptr() as *mut i8)
.collect::<Vec<*mut i8>>();
let tag_c_str = ffi::CString::new(tag).unwrap();
unsafe {
if htslib::bcf_update_format_string(
self.header().inner,
self.inner,
tag_c_str.as_ptr() as *mut i8,
c_ptrs.as_slice().as_ptr() as *mut *const i8,
data.len() as i32,
) == 0
{
Ok(())
} else {
Err(Error::BcfSetTag {
tag: str::from_utf8(tag).unwrap().to_owned(),
})
}
}
}
pub fn push_info_integer(&mut self, tag: &[u8], data: &[i32]) -> Result<()> {
self.push_info(tag, data, htslib::BCF_HT_INT)
}
pub fn clear_info_integer(&mut self, tag: &[u8]) -> Result<()> {
self.push_info::<i32>(tag, &[], htslib::BCF_HT_INT)
}
pub fn push_info_float(&mut self, tag: &[u8], data: &[f32]) -> Result<()> {
self.push_info(tag, data, htslib::BCF_HT_REAL)
}
pub fn clear_info_float(&mut self, tag: &[u8]) -> Result<()> {
self.push_info::<u8>(tag, &[], htslib::BCF_HT_REAL)
}
fn push_info<T>(&mut self, tag: &[u8], data: &[T], ht: u32) -> Result<()> {
let tag_c_str = ffi::CString::new(tag).unwrap();
unsafe {
if htslib::bcf_update_info(
self.header().inner,
self.inner,
tag_c_str.as_ptr() as *mut i8,
data.as_ptr() as *const ::std::os::raw::c_void,
data.len() as i32,
ht as i32,
) == 0
{
Ok(())
} else {
Err(Error::BcfSetTag {
tag: str::from_utf8(tag).unwrap().to_owned(),
})
}
}
}
pub fn push_info_flag(&mut self, tag: &[u8]) -> Result<()> {
self.push_info_string_impl(tag, &[b""], htslib::BCF_HT_FLAG)
}
pub fn clear_info_flag(&mut self, tag: &[u8]) -> Result<()> {
self.push_info_string_impl(tag, &[], htslib::BCF_HT_FLAG)
}
pub fn push_info_string(&mut self, tag: &[u8], data: &[&[u8]]) -> Result<()> {
self.push_info_string_impl(tag, data, htslib::BCF_HT_STR)
}
pub fn clear_info_string(&mut self, tag: &[u8]) -> Result<()> {
self.push_info_string_impl(tag, &[], htslib::BCF_HT_STR)
}
fn push_info_string_impl(&mut self, tag: &[u8], data: &[&[u8]], ht: u32) -> Result<()> {
let mut buf: Vec<u8> = Vec::new();
for (i, &s) in data.iter().enumerate() {
if i > 0 {
buf.extend(b",");
}
buf.extend(s);
}
let c_str = ffi::CString::new(buf).unwrap();
let len = if ht == htslib::BCF_HT_FLAG {
data.len()
} else {
c_str.to_bytes().len()
};
let tag_c_str = ffi::CString::new(tag).unwrap();
unsafe {
if htslib::bcf_update_info(
self.header().inner,
self.inner,
tag_c_str.as_ptr() as *mut i8,
c_str.as_ptr() as *const ::std::os::raw::c_void,
len as i32,
ht as i32,
) == 0
{
Ok(())
} else {
Err(Error::BcfSetTag {
tag: str::from_utf8(tag).unwrap().to_owned(),
})
}
}
}
pub fn trim_alleles(&mut self) -> Result<()> {
match unsafe { htslib::bcf_trim_alleles(self.header().inner, self.inner) } {
-1 => Err(Error::BcfRemoveAlleles),
_ => Ok(()),
}
}
pub fn remove_alleles(&mut self, remove: &[bool]) -> Result<()> {
let rm_set = unsafe { htslib::kbs_init(remove.len() as u64) };
for (i, &r) in remove.iter().enumerate() {
if r {
unsafe {
htslib::kbs_insert(rm_set, i as i32);
}
}
}
let ret = unsafe { htslib::bcf_remove_allele_set(self.header().inner, self.inner, rm_set) };
unsafe {
htslib::kbs_destroy(rm_set);
}
match ret {
-1 => Err(Error::BcfRemoveAlleles),
_ => Ok(()),
}
}
pub fn desc(&self) -> String {
if let Some(rid) = self.rid() {
if let Ok(contig) = self.header.rid2name(rid) {
return format!("{}:{}", str::from_utf8(contig).unwrap(), self.pos());
}
}
"".to_owned()
}
}
impl genome::AbstractLocus for Record {
fn contig(&self) -> &str {
str::from_utf8(
self.header()
.rid2name(self.rid().expect("rid not set"))
.expect("unable to find rid in header"),
)
.expect("unable to interpret contig name as UTF-8")
}
fn pos(&self) -> u64 {
self.pos() as u64
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GenotypeAllele {
Unphased(i32),
Phased(i32),
UnphasedMissing,
PhasedMissing,
}
impl GenotypeAllele {
pub fn from_encoded(encoded: i32) -> Self {
match (encoded, encoded & 1) {
(0, 0) => GenotypeAllele::UnphasedMissing,
(1, 1) => GenotypeAllele::PhasedMissing,
(e, 1) => GenotypeAllele::Phased((e >> 1) - 1),
(e, 0) => GenotypeAllele::Unphased((e >> 1) - 1),
_ => panic!("unexpected phasing type"),
}
}
pub fn index(self) -> Option<u32> {
match self {
GenotypeAllele::Unphased(i) | GenotypeAllele::Phased(i) => Some(i as u32),
GenotypeAllele::UnphasedMissing | GenotypeAllele::PhasedMissing => None,
}
}
}
impl fmt::Display for GenotypeAllele {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.index() {
Some(a) => write!(f, "{}", a),
None => write!(f, "."),
}
}
}
impl From<GenotypeAllele> for i32 {
fn from(allele: GenotypeAllele) -> i32 {
let (allele, phased) = match allele {
GenotypeAllele::UnphasedMissing => (-1, 0),
GenotypeAllele::PhasedMissing => (-1, 1),
GenotypeAllele::Unphased(a) => (a, 0),
GenotypeAllele::Phased(a) => (a, 1),
};
allele + 1 << 1 | phased
}
}
custom_derive! {
#[derive(NewtypeDeref, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Genotype(Vec<GenotypeAllele>);
}
impl fmt::Display for Genotype {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let &Genotype(ref alleles) = self;
write!(f, "{}", alleles[0])?;
for a in &alleles[1..] {
let sep = match a {
GenotypeAllele::Phased(_) | GenotypeAllele::PhasedMissing => '|',
GenotypeAllele::Unphased(_) | GenotypeAllele::UnphasedMissing => '/',
};
write!(f, "{}{}", sep, a)?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct Genotypes<'a, B>
where
B: Borrow<Buffer> + 'a,
{
encoded: BufferBacked<'a, Vec<&'a [i32]>, B>,
}
impl<'a, B: Borrow<Buffer> + 'a> Genotypes<'a, B> {
pub fn get(&self, i: usize) -> Genotype {
let igt = self.encoded[i];
Genotype(
igt.iter()
.map(|&e| GenotypeAllele::from_encoded(e))
.collect(),
)
}
}
impl Drop for Record {
fn drop(&mut self) {
unsafe { htslib::bcf_destroy(self.inner) };
}
}
unsafe impl Send for Record {}
unsafe impl Sync for Record {}
#[derive(Debug)]
pub struct Info<'a, B: BorrowMut<Buffer> + Borrow<Buffer>> {
record: &'a Record,
tag: &'a [u8],
buffer: B,
}
impl<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b> Info<'a, B> {
pub fn desc(&self) -> String {
str::from_utf8(self.tag).unwrap().to_owned()
}
fn data(&mut self, data_type: u32) -> Result<Option<(usize, i32)>> {
let mut n: i32 = self.buffer.borrow().len;
let c_str = ffi::CString::new(self.tag).unwrap();
let ret = unsafe {
htslib::bcf_get_info_values(
self.record.header().inner,
self.record.inner,
c_str.as_ptr() as *mut i8,
&mut self.buffer.borrow_mut().inner,
&mut n,
data_type as i32,
)
};
self.buffer.borrow_mut().len = n;
match ret {
-1 => Err(Error::BcfUndefinedTag { tag: self.desc() }),
-2 => Err(Error::BcfUnexpectedType { tag: self.desc() }),
-3 => Ok(None),
ret => Ok(Some((n as usize, ret))),
}
}
pub fn integer(mut self) -> Result<Option<BufferBacked<'b, &'b [i32], B>>> {
self.data(htslib::BCF_HT_INT).map(|data| {
data.map(|(n, ret)| {
let values =
unsafe { slice::from_raw_parts(self.buffer.borrow().inner as *const i32, n) };
BufferBacked::new(&values[..ret as usize], self.buffer)
})
})
}
pub fn float(mut self) -> Result<Option<BufferBacked<'b, &'b [f32], B>>> {
self.data(htslib::BCF_HT_REAL).map(|data| {
data.map(|(n, ret)| {
let values =
unsafe { slice::from_raw_parts(self.buffer.borrow().inner as *const f32, n) };
BufferBacked::new(&values[..ret as usize], self.buffer)
})
})
}
pub fn flag(&mut self) -> Result<bool> {
self.data(htslib::BCF_HT_FLAG).map(|data| match data {
Some((_, ret)) => ret == 1,
None => false,
})
}
pub fn string(mut self) -> Result<Option<BufferBacked<'b, Vec<&'b [u8]>, B>>> {
self.data(htslib::BCF_HT_STR).map(|data| {
data.map(|(_, ret)| {
BufferBacked::new(
unsafe {
slice::from_raw_parts(self.buffer.borrow().inner as *const u8, ret as usize)
}
.split(|c| *c == b',')
.map(|s| {
s.split(|c| *c == 0u8)
.next()
.expect("Bug: returned string should not be empty.")
})
.collect(),
self.buffer,
)
})
})
}
}
unsafe impl<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b> Send for Info<'a, B> {}
unsafe impl<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b> Sync for Info<'a, B> {}
fn trim_slice<T: PartialEq + NumericUtils>(s: &[T]) -> &[T] {
s.split(|v| v.is_vector_end())
.next()
.expect("Bug: returned slice should not be empty.")
}
#[derive(Debug)]
pub struct Format<'a, B: BorrowMut<Buffer> + Borrow<Buffer>> {
record: &'a Record,
tag: &'a [u8],
inner: *mut htslib::bcf_fmt_t,
buffer: B,
}
impl<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b> Format<'a, B> {
fn new(record: &'a Record, tag: &'a [u8], buffer: B) -> Format<'a, B> {
let c_str = ffi::CString::new(tag).unwrap();
let inner = unsafe {
htslib::bcf_get_fmt(
record.header().inner,
record.inner,
c_str.as_ptr() as *mut i8,
)
};
Format {
record,
tag,
inner,
buffer,
}
}
pub fn desc(&self) -> String {
str::from_utf8(self.tag).unwrap().to_owned()
}
pub fn inner(&self) -> &htslib::bcf_fmt_t {
unsafe { &*self.inner }
}
pub fn inner_mut(&mut self) -> &mut htslib::bcf_fmt_t {
unsafe { &mut *self.inner }
}
fn values_per_sample(&self) -> usize {
self.inner().n as usize
}
fn data(&mut self, data_type: u32) -> Result<(usize, i32)> {
let mut n: i32 = self.buffer.borrow().len;
let c_str = ffi::CString::new(self.tag).unwrap();
let ret = unsafe {
htslib::bcf_get_format_values(
self.record.header().inner,
self.record.inner,
c_str.as_ptr() as *mut i8,
&mut self.buffer.borrow_mut().inner,
&mut n,
data_type as i32,
)
};
self.buffer.borrow_mut().len = n;
match ret {
-1 => Err(Error::BcfUndefinedTag { tag: self.desc() }),
-2 => Err(Error::BcfUnexpectedType { tag: self.desc() }),
-3 => Err(Error::BcfMissingTag {
tag: self.desc(),
record: self.record.desc(),
}),
ret => Ok((n as usize, ret)),
}
}
pub fn integer(mut self) -> Result<BufferBacked<'b, Vec<&'b [i32]>, B>> {
self.data(htslib::BCF_HT_INT).map(|(n, _)| {
BufferBacked::new(
unsafe { slice::from_raw_parts(self.buffer.borrow_mut().inner as *const i32, n) }
.chunks(self.values_per_sample())
.map(|s| trim_slice(s))
.collect(),
self.buffer,
)
})
}
pub fn float(mut self) -> Result<BufferBacked<'b, Vec<&'b [f32]>, B>> {
self.data(htslib::BCF_HT_REAL).map(|(n, _)| {
BufferBacked::new(
unsafe { slice::from_raw_parts(self.buffer.borrow_mut().inner as *const f32, n) }
.chunks(self.values_per_sample())
.map(|s| trim_slice(s))
.collect(),
self.buffer,
)
})
}
pub fn string(mut self) -> Result<BufferBacked<'b, Vec<&'b [u8]>, B>> {
self.data(htslib::BCF_HT_STR).map(|(n, _)| {
BufferBacked::new(
unsafe { slice::from_raw_parts(self.buffer.borrow_mut().inner as *const u8, n) }
.chunks(self.values_per_sample())
.map(|s| {
s.split(|c| *c == 0u8)
.next()
.expect("Bug: returned string should not be empty.")
})
.collect(),
self.buffer,
)
})
}
}
unsafe impl<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b> Send for Format<'a, B> {}
unsafe impl<'a, 'b, B: BorrowMut<Buffer> + Borrow<Buffer> + 'b> Sync for Format<'a, B> {}
#[derive(Debug)]
pub struct Filters<'a> {
record: &'a Record,
idx: i32,
}
impl<'a> Filters<'a> {
pub fn new(record: &'a Record) -> Self {
Filters { record, idx: 0 }
}
}
impl<'a> Iterator for Filters<'a> {
type Item = Id;
fn next(&mut self) -> Option<Id> {
if self.record.inner().d.n_flt <= self.idx {
None
} else {
let i = self.idx as isize;
self.idx += 1;
Some(Id(unsafe { *self.record.inner().d.flt.offset(i) } as u32))
}
}
}