use std::fmt;
use serde::{Deserialize, Serialize};
use crate::category::{Category, Termination};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Loc {
pub file: String,
pub line: u32,
pub col: u32,
}
impl fmt::Display for Loc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}:{}", self.file, self.line, self.col)
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
)]
pub struct FuncKey(pub String);
impl fmt::Display for FuncKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EdgeKind {
Static,
Drop,
Vtable,
FnPtr,
Generic,
Unresolved,
}
impl EdgeKind {
pub const ALL: [Self; 6] = [
Self::Static,
Self::Drop,
Self::Vtable,
Self::FnPtr,
Self::Generic,
Self::Unresolved,
];
#[must_use]
pub const fn is_exact(self) -> bool {
matches!(self, Self::Static | Self::Drop)
}
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::Static => "static",
Self::Drop => "drop",
Self::Vtable => "vtable",
Self::FnPtr => "fn-ptr",
Self::Generic => "generic",
Self::Unresolved => "unresolved",
}
}
#[must_use]
pub const fn assumed_category(self) -> Category {
match self {
Self::Vtable => Category::DynCall,
Self::FnPtr => Category::FnPointer,
Self::Generic => Category::GenericBound,
Self::Static | Self::Drop | Self::Unresolved => Category::Unknown,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum UnwindOrigin {
Site(u32),
Call(u32),
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Guard {
pub normal: bool,
pub origins: Vec<UnwindOrigin>,
}
impl Guard {
#[must_use]
pub const fn always() -> Self {
Self {
normal: true,
origins: Vec::new(),
}
}
#[must_use]
pub const fn is_dead(&self) -> bool {
!self.normal && self.origins.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PanicSite {
pub category: Category,
pub termination: Termination,
pub reason: String,
pub sink: Option<String>,
pub loc: Option<Loc>,
pub guard: Guard,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CallSite {
pub callee: Option<FuncKey>,
pub callee_display: String,
pub kind: EdgeKind,
pub loc: Option<Loc>,
pub guard: Guard,
#[serde(default)]
pub barrier: bool,
#[serde(default)]
pub candidate: bool,
#[serde(default)]
pub sig: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Reified {
pub key: FuncKey,
pub display: String,
pub sig: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Body {
pub key: FuncKey,
pub display: String,
pub krate: String,
pub loc: Option<Loc>,
pub sites: Vec<PanicSite>,
pub calls: Vec<CallSite>,
pub opaque: bool,
#[serde(default)]
pub foreign: bool,
pub local: bool,
}
impl Body {
#[must_use]
pub const fn unreadable(&self) -> Category {
if self.foreign {
Category::Foreign
} else {
Category::Unknown
}
}
#[must_use]
pub const fn opaque(key: FuncKey, display: String, krate: String) -> Self {
Self {
key,
display,
krate,
loc: None,
sites: Vec::new(),
calls: Vec::new(),
opaque: true,
foreign: false,
local: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum StdMode {
Shipped,
Full,
}
impl StdMode {
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::Shipped => "shipped",
Self::Full => "full",
}
}
#[must_use]
pub fn from_name(name: &str) -> Option<Self> {
[Self::Shipped, Self::Full]
.into_iter()
.find(|mode| mode.name() == name)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BuildConfig {
pub rustc: String,
pub profile: String,
pub debug_assertions: bool,
pub overflow_checks: bool,
pub std_mode: StdMode,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Artifact {
pub krate: String,
pub config: BuildConfig,
pub bodies: Vec<Body>,
#[serde(default)]
pub reified: Vec<Reified>,
}