1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! BCF record and fields.
mod convert;
pub mod value;
pub use self::value::Value;
use std::{
convert::{TryFrom, TryInto},
io,
ops::{Deref, DerefMut},
};
use noodles_vcf as vcf;
/// A BCF record.
///
/// A `bcf::Record` wraps a raw byte buffer, and the fields should be considered immutable.
#[derive(Clone, Default, Eq, PartialEq)]
pub struct Record(Vec<u8>);
impl Record {
pub(crate) fn resize(&mut self, new_len: usize) {
self.0.resize(new_len, Default::default());
}
/// Returns the chromosome ID of the record.
///
/// The chromosome ID is the index of the associated contig in the VCF header.
///
/// # Examples
///
/// ```
/// # use std::io;
/// use noodles_bcf as bcf;
///
/// let record = bcf::Record::from(vec![
/// 0x08, 0x00, 0x00, 0x00, // CHROM
/// // ...
/// ]);
///
/// assert_eq!(record.chromosome_id()?, 8);
/// # Ok::<(), io::Error>(())
/// ```
pub fn chromosome_id(&self) -> io::Result<i32> {
const OFFSET: usize = 0;
let data = &self.0[OFFSET..OFFSET + 4];
data.try_into()
.map(i32::from_le_bytes)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
/// Returns the start position of this record.
///
/// Despite the BCF format using 0-based positions, this normalizes the value as a 1-based
/// position.
///
/// # Examples
///
/// ```
/// # use std::io;
/// use noodles_bcf as bcf;
/// use noodles_vcf as vcf;
///
/// let record = bcf::Record::from(vec![
/// 0x08, 0x00, 0x00, 0x00, // CHROM
/// 0x0c, 0x00, 0x00, 0x00, // POS
/// // ...
/// ]);
///
/// assert_eq!(record.position().map(i32::from)?, 13);
/// # Ok::<(), io::Error>(())
/// ```
pub fn position(&self) -> io::Result<vcf::record::Position> {
use vcf::record::Position;
const OFFSET: usize = 4;
let data = &self.0[OFFSET..OFFSET + 4];
data.try_into()
.map(i32::from_le_bytes)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|pos| {
Position::try_from(pos + 1)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
})
}
fn rlen(&self) -> io::Result<i32> {
const OFFSET: usize = 8;
let data = &self.0[OFFSET..OFFSET + 4];
data.try_into()
.map(i32::from_le_bytes)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
/// Returns the end position of this record.
///
/// This value is 1-based.
///
/// # Examples
///
/// ```
/// # use std::io;
/// use noodles_bcf as bcf;
/// use noodles_vcf as vcf;
///
/// let record = bcf::Record::from(vec![
/// 0x08, 0x00, 0x00, 0x00, // CHROM
/// 0x0c, 0x00, 0x00, 0x00, // POS
/// 0x05, 0x00, 0x00, 0x00, // rlen
/// // ...
/// ]);
///
/// assert_eq!(record.end().map(i32::from)?, 17);
/// # Ok::<(), io::Error>(())
/// ```
pub fn end(&self) -> io::Result<vcf::record::Position> {
use vcf::record::Position;
let start = self.position().map(i32::from)?;
let len = self.rlen()?;
let end = start + len - 1;
Position::try_from(end).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
}
}
impl Deref for Record {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0
}
}
impl DerefMut for Record {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl From<Vec<u8>> for Record {
fn from(data: Vec<u8>) -> Self {
Self(data)
}
}