#![deny(rustdoc::broken_intra_doc_links)]
#![deny(missing_docs)]
#![allow(clippy::redundant_field_names)]
#![forbid(unsafe_code)]
pub mod abbrev;
pub mod error;
pub mod parser;
pub mod record;
use std::io::{Seek, SeekFrom};
use llvm_bitcursor::BitCursor;
use llvm_support::BITCODE_WRAPPER_MAGIC;
use crate::error::Error;
use crate::parser::StreamEntry;
#[derive(Debug)]
pub struct BitcodeWrapper {
pub magic: u32,
pub version: u32,
pub offset: u32,
pub size: u32,
pub cpu_type: u32,
}
#[derive(Debug)]
pub struct Bitstream<T: AsRef<[u8]>> {
pub magic: u32,
parser: parser::StreamParser<T>,
}
impl<T: AsRef<[u8]>> Bitstream<T> {
fn from_cursor(mut cur: BitCursor<T>) -> Result<Self, Error> {
if cur.byte_len() % 4 != 0 {
return Err(Error::BadContainer("input is not 4-byte aligned".into()));
}
Ok(Self {
magic: cur.read_exact::<u32>().map_err(|e| {
Error::BadContainer(format!(
"bitstream should have begun with magic, but errored: {:?}",
e
))
})?,
parser: parser::StreamParser::new(cur),
})
}
pub fn from(inner: T) -> Result<(Option<BitcodeWrapper>, Self), Error> {
log::debug!("beginning intelligent parse");
let mut cur = BitCursor::new(&inner);
let magic = cur.read_exact::<u32>()?;
if magic == BITCODE_WRAPPER_MAGIC {
log::debug!("input looks like a bitcode wrapper!");
let (wrapper, parser) = Self::from_wrapped(inner)?;
Ok((Some(wrapper), parser))
} else {
log::debug!("input is probably a raw bitstream!");
Ok((None, Self::from_raw(inner)?))
}
}
pub fn from_raw(inner: T) -> Result<Self, Error> {
let cur = BitCursor::new(inner);
Self::from_cursor(cur)
}
pub fn from_wrapped(inner: T) -> Result<(BitcodeWrapper, Self), Error> {
let mut cur = BitCursor::new(&inner);
let wrapper = BitcodeWrapper {
magic: cur.read_exact::<u32>()?,
version: cur.read_exact::<u32>()?,
offset: cur.read_exact::<u32>()?,
size: cur.read_exact::<u32>()?,
cpu_type: cur.read_exact::<u32>()?,
};
let actual_length = (wrapper.size as usize) + 20;
let mut cur = BitCursor::new_with_len(inner, actual_length)?;
cur.seek(SeekFrom::Start(wrapper.offset.into()))
.map_err(|e| {
Error::StreamParse(format!("couldn't seek past bitcode wrapper: {:?}", e))
})?;
Ok((wrapper, Self::from_cursor(cur)?))
}
pub fn advance(&mut self) -> Result<StreamEntry, Error> {
self.parser.advance()
}
}
impl<T: AsRef<[u8]>> Iterator for Bitstream<T> {
type Item = Result<StreamEntry, Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.advance() {
Ok(entry) => Some(Ok(entry)),
Err(Error::Exhausted) => None,
Err(e) => Some(Err(e)),
}
}
}
#[cfg(test)]
mod tests {}