#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
use std::fmt;
use std::io;
use std::str::FromStr;
use failure::Fail;
use twiggy_ir as ir;
#[derive(Debug)]
pub struct Error {
inner: Box<ErrorInner>,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.inner)
}
}
impl failure::Fail for Error {
fn cause(&self) -> Option<&dyn failure::Fail> {
self.inner.cause()
}
fn backtrace(&self) -> Option<&failure::Backtrace> {
self.inner.backtrace()
}
}
#[derive(Debug, Fail)]
enum ErrorInner {
#[fail(display = "{}", _0)]
Msg(String),
#[fail(display = "I/O error: {}", _0)]
Io(#[cause] io::Error),
#[fail(display = "WASM error: {}", _0)]
Wasm(#[cause] wasmparser::BinaryReaderError),
#[fail(display = "formatting error: {}", _0)]
Fmt(#[cause] fmt::Error),
#[fail(display = "CSV error: {}", _0)]
Csv(#[cause] csv::Error),
#[fail(display = "Regex error: {}", _0)]
Regex(#[cause] regex::Error),
#[cfg(feature = "dwarf")]
#[fail(display = "Gimli error: {}", _0)]
Gimli(#[cause] gimli::Error),
}
impl<'a> From<&'a str> for Error {
fn from(msg: &'a str) -> Error {
Error::with_msg(msg)
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error {
inner: Box::new(ErrorInner::Io(e)),
}
}
}
impl From<wasmparser::BinaryReaderError> for Error {
fn from(e: wasmparser::BinaryReaderError) -> Error {
Error {
inner: Box::new(ErrorInner::Wasm(e)),
}
}
}
impl From<fmt::Error> for Error {
fn from(e: fmt::Error) -> Error {
Error {
inner: Box::new(ErrorInner::Fmt(e)),
}
}
}
impl From<csv::Error> for Error {
fn from(e: csv::Error) -> Error {
Error {
inner: Box::new(ErrorInner::Csv(e)),
}
}
}
impl From<regex::Error> for Error {
fn from(e: regex::Error) -> Error {
Error {
inner: Box::new(ErrorInner::Regex(e)),
}
}
}
#[cfg(feature = "dwarf")]
impl From<gimli::Error> for Error {
fn from(e: gimli::Error) -> Error {
Error {
inner: Box::new(ErrorInner::Gimli(e)),
}
}
}
impl Error {
pub fn with_msg<S: Into<String>>(msg: S) -> Error {
Error {
inner: Box::new(ErrorInner::Msg(msg.into())),
}
}
}
#[test]
fn size_of_error_is_one_word() {
use std::mem;
assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
}
pub trait Analyze {
type Data: Emit;
fn analyze(items: &mut ir::Items) -> Result<Self::Data, Error>;
}
#[derive(Clone, Copy, Debug)]
pub enum ParseMode {
Wasm,
#[cfg(feature = "dwarf")]
Dwarf,
Auto,
}
impl Default for ParseMode {
fn default() -> ParseMode {
ParseMode::Auto
}
}
impl FromStr for ParseMode {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
match s {
"wasm" => Ok(ParseMode::Wasm),
#[cfg(feature = "dwarf")]
"dwarf" => Ok(ParseMode::Dwarf),
"auto" => Ok(ParseMode::Auto),
_ => Err(Error::with_msg(format!("Unknown parse mode: {}", s))),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum OutputFormat {
#[cfg(feature = "emit_text")]
Text,
#[cfg(feature = "emit_csv")]
Csv,
#[cfg(feature = "emit_json")]
Json,
}
#[cfg(feature = "emit_text")]
#[cfg(feature = "emit_csv")]
#[cfg(feature = "emit_json")]
impl Default for OutputFormat {
fn default() -> OutputFormat {
OutputFormat::Text
}
}
impl FromStr for OutputFormat {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
match s {
#[cfg(feature = "emit_text")]
"text" => Ok(OutputFormat::Text),
#[cfg(feature = "emit_json")]
"json" => Ok(OutputFormat::Json),
#[cfg(feature = "emit_csv")]
"csv" => Ok(OutputFormat::Csv),
_ => Err(Error::with_msg(format!("Unknown output format: {}", s))),
}
}
}
pub trait Emit {
fn emit(
&self,
items: &ir::Items,
destination: &mut dyn io::Write,
format: OutputFormat,
) -> Result<(), Error> {
match format {
#[cfg(feature = "emit_text")]
OutputFormat::Text => self.emit_text(items, destination),
#[cfg(feature = "emit_csv")]
OutputFormat::Csv => self.emit_csv(items, destination),
#[cfg(feature = "emit_json")]
OutputFormat::Json => self.emit_json(items, destination),
}
}
#[cfg(feature = "emit_text")]
fn emit_text(&self, items: &ir::Items, destination: &mut dyn io::Write) -> Result<(), Error>;
#[cfg(feature = "emit_csv")]
fn emit_csv(&self, items: &ir::Items, destination: &mut dyn io::Write) -> Result<(), Error>;
#[cfg(feature = "emit_json")]
fn emit_json(&self, items: &ir::Items, destination: &mut dyn io::Write) -> Result<(), Error>;
}