pub mod attributes;
pub mod identification;
pub mod module;
pub mod strtab;
pub mod symtab;
pub mod type_table;
use std::convert::TryFrom;
use llvm_constants::{IrBlockId, ReservedBlockId};
use thiserror::Error;
pub use self::attributes::*;
pub use self::identification::*;
pub use self::module::*;
pub use self::strtab::*;
pub use self::symtab::*;
pub use self::type_table::*;
use crate::map::{MapCtx, MapCtxError, Mappable};
use crate::record::RecordMapError;
use crate::unroll::UnrolledBlock;
#[non_exhaustive]
#[derive(Debug, Error)]
pub enum BlockMapError {
#[error("error while mapping record")]
BadRecord(#[from] RecordMapError),
#[error("invalid mapping context")]
BadContext(#[from] MapCtxError),
#[error("error while mapping block: {0}")]
BadBlockMap(String),
#[error("expected exactly one record of code {0} in block {1:?}")]
BlockRecordMismatch(u64, BlockId),
#[error("expected exactly one block of ID {0:?} in block {1:?}")]
BlockBlockMismatch(BlockId, BlockId),
#[error("error while mapping type table")]
BadTypeTable(#[from] TypeTableError),
#[error("error while mapping attributes")]
BadAttributes(#[from] AttributeError),
#[error("unsupported: {0}")]
Unsupported(String),
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum BlockId {
Reserved(ReservedBlockId),
Ir(IrBlockId),
Unknown(u64),
}
impl From<u64> for BlockId {
fn from(value: u64) -> Self {
ReservedBlockId::try_from(value).map_or_else(
|_| IrBlockId::try_from(value).map_or_else(|_| BlockId::Unknown(value), BlockId::Ir),
BlockId::Reserved,
)
}
}
pub(crate) trait IrBlock: Sized {
const BLOCK_ID: IrBlockId;
fn try_map_inner(block: &UnrolledBlock, ctx: &mut MapCtx) -> Result<Self, BlockMapError>;
}
impl<T: IrBlock> Mappable<UnrolledBlock> for T {
type Error = BlockMapError;
fn try_map(block: &UnrolledBlock, ctx: &mut MapCtx) -> Result<Self, Self::Error> {
if block.id != BlockId::Ir(T::BLOCK_ID) {
return Err(BlockMapError::BadBlockMap(format!(
"can't map {:?} into {:?}",
block.id,
Identification::BLOCK_ID
)));
}
IrBlock::try_map_inner(block, ctx)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_blockid_from_u64() {
assert_eq!(
BlockId::from(0),
BlockId::Reserved(ReservedBlockId::BlockInfo)
);
assert_eq!(
BlockId::from(7),
BlockId::Reserved(ReservedBlockId::Reserved7)
);
assert_eq!(BlockId::from(8), BlockId::Ir(IrBlockId::Module));
assert_eq!(BlockId::from(2384629342), BlockId::Unknown(2384629342));
}
}