use std::{num, fmt, error::Error};
use crate::{
ContextHandle, Contextual, Face, AtomID, NodeID, PortID, LinkID, ForkID, JoinID, Multiplicity,
Capacity,
};
#[derive(Clone, Debug)]
pub enum AcesErrorKind {
ContextMismatch,
PolynomialFaceMismatch,
HarcNotAForkMismatch(JoinID),
HarcNotAJoinMismatch(ForkID),
NodeMissingForID(NodeID),
AtomMissingForID(AtomID),
PortMissingForID(PortID),
LinkMissingForID(LinkID),
HarcMissingForID(AtomID),
ForkMissingForID(ForkID),
JoinMissingForID(JoinID),
BottomAtomAccess,
AtomicsNotOrdered,
NodeMissingForPort(Face),
NodeMissingForLink(Face),
NodeMissingForFork(Face),
NodeMissingForJoin(Face),
FiringNodeMissing(Face),
FiringNodeDuplicated(Face),
IncoherentStructure(String, u32, (Face, String, String)),
LeakedInhibitor(NodeID, Multiplicity),
StateUnderflow(NodeID, Multiplicity, Multiplicity),
StateOverflow(NodeID, Multiplicity, Multiplicity),
CapacityOverflow(NodeID, Capacity, Multiplicity),
MultiplicityOverflow(String),
ParseIntError(num::ParseIntError),
ParseFloatError(num::ParseFloatError),
EmptyClauseRejectedByFormula(String),
EmptyClauseRejectedBySolver(String),
EmptyCausesOfInternalNode(String),
EmptyEffectsOfInternalNode(String),
UnlistedAtomicInMonomial,
IncoherencyLeak,
NoModelToInhibit,
UnknownScriptFormat,
}
impl fmt::Display for AcesErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use AcesErrorKind::*;
match self {
ContextMismatch => write!(f, "Context mismatch"),
PolynomialFaceMismatch => {
write!(f, "Attempt to combine polynomials attached to opposite faces")
}
HarcNotAForkMismatch(join_id) => write!(f, "Expected fork, but harc is {:?}", join_id),
HarcNotAJoinMismatch(fork_id) => write!(f, "Expected join, but harc is {:?}", fork_id),
NodeMissingForID(node_id) => write!(f, "There is no node with {:?}", node_id),
AtomMissingForID(atom_id) => write!(f, "There is no atom with {:?}", atom_id),
PortMissingForID(port_id) => write!(f, "There is no port with {:?}", port_id),
LinkMissingForID(link_id) => write!(f, "There is no link with {:?}", link_id),
HarcMissingForID(harc_id) => write!(f, "There is no harc with {:?}", harc_id),
ForkMissingForID(fork_id) => write!(f, "There is no fork with {:?}", fork_id),
JoinMissingForID(join_id) => write!(f, "There is no join with {:?}", join_id),
BottomAtomAccess => write!(f, "Attempt to access the bottom atom"),
AtomicsNotOrdered => write!(f, "Atomics have to be given in strictly increasing order"),
NodeMissingForPort(face) => write!(
f,
"Missing node for {} port",
if *face == Face::Tx { "sending" } else { "receiving" }
),
NodeMissingForLink(face) => write!(
f,
"Missing {} node for link",
if *face == Face::Tx { "sending" } else { "receiving" }
),
NodeMissingForFork(face) => write!(
f,
"Missing {} node for fork",
if *face == Face::Tx { "sending" } else { "receiving" }
),
NodeMissingForJoin(face) => write!(
f,
"Missing {} node for join",
if *face == Face::Tx { "sending" } else { "receiving" }
),
FiringNodeMissing(face) => write!(
f,
"Missing {} node in firing component",
if *face == Face::Tx { "sending" } else { "receiving" }
),
FiringNodeDuplicated(face) => write!(
f,
"Duplicated {} node in firing component",
if *face == Face::Tx { "sending" } else { "receiving" }
),
IncoherentStructure(ces_name, num_thin_links, (face, tx_name, rx_name)) => {
if *num_thin_links == 1 {
write!(
f,
"Structure '{}' is incoherent; there is one thin link: ({} {} {})",
ces_name, tx_name, face, rx_name
)
} else {
write!(
f,
"Structure '{}' is incoherent; there are thin links: ({} {} {}) and {} \
more..",
ces_name,
tx_name,
face,
rx_name,
*num_thin_links - 1,
)
}
}
LeakedInhibitor(node_id, tokens_before) => {
write!(f, "Leaked inhibitor at {:?} firing from {} tokens", node_id, tokens_before)
}
StateUnderflow(node_id, tokens_before, num_tokens) => write!(
f,
"State underflow at {:?} after subtracting {} from {}",
node_id, num_tokens, tokens_before
),
StateOverflow(node_id, tokens_before, num_tokens) => write!(
f,
"State overflow at {:?} after adding {} to {}",
node_id, num_tokens, tokens_before
),
CapacityOverflow(node_id, capacity, num_tokens) => {
write!(f, "Capacity overflow at {:?} set to {} > {}", node_id, num_tokens, capacity)
}
MultiplicityOverflow(when_happened) => {
write!(f, "Multiplicity overflow when {}", when_happened)
}
ParseIntError(err) => err.fmt(f),
ParseFloatError(err) => err.fmt(f),
EmptyClauseRejectedByFormula(name) => {
write!(f, "Empty {} clause rejected by formula", name)
}
EmptyClauseRejectedBySolver(name) => {
write!(f, "Empty {} clause rejected by solver", name)
}
EmptyCausesOfInternalNode(name) => {
write!(f, "Empty cause polynomial of internal node '{}'", name)
}
EmptyEffectsOfInternalNode(name) => {
write!(f, "Empty effect polynomial of internal node '{}'", name)
}
UnlistedAtomicInMonomial => write!(f, "Monomial contains an unlisted atomic"),
IncoherencyLeak => write!(f, "Unexpected incoherence of a c-e structure"),
NoModelToInhibit => write!(f, "Attempt to inhibit a nonexistent model"),
UnknownScriptFormat => write!(f, "Unrecognized script format"),
}
}
}
impl AcesErrorKind {
pub fn with_context(self, context: &ContextHandle) -> AcesError {
AcesError { context: Some(context.clone()), kind: self }
}
}
impl From<num::ParseIntError> for AcesErrorKind {
#[inline]
fn from(kind: num::ParseIntError) -> Self {
AcesErrorKind::ParseIntError(kind)
}
}
impl From<num::ParseFloatError> for AcesErrorKind {
#[inline]
fn from(kind: num::ParseFloatError) -> Self {
AcesErrorKind::ParseFloatError(kind)
}
}
#[derive(Clone, Debug)]
pub struct AcesError {
context: Option<ContextHandle>,
kind: AcesErrorKind,
}
impl From<AcesErrorKind> for AcesError {
#[inline]
fn from(kind: AcesErrorKind) -> Self {
AcesError { context: None, kind }
}
}
impl fmt::Display for AcesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use AcesErrorKind::*;
if let Some(ref ctx) = self.context {
match self.kind {
HarcNotAForkMismatch(join_id) => {
write!(f, "Expected fork, but harc is a join {}", join_id.with(ctx))
}
HarcNotAJoinMismatch(fork_id) => {
write!(f, "Expected join, but harc is a fork {}", fork_id.with(ctx))
}
LeakedInhibitor(node_id, tokens_before) => write!(
f,
"Leaked inhibitor at node \"{}\" firing from {} tokens",
node_id.with(ctx),
tokens_before
),
StateUnderflow(node_id, tokens_before, num_tokens) => write!(
f,
"State underflow at node \"{}\" after subtracting {} from {}",
node_id.with(ctx),
num_tokens,
tokens_before
),
StateOverflow(node_id, tokens_before, num_tokens) => write!(
f,
"State overflow at node \"{}\" after adding {} to {}",
node_id.with(ctx),
num_tokens,
tokens_before
),
CapacityOverflow(node_id, capacity, num_tokens) => write!(
f,
"Capacity overflow at node \"{}\" set to {} > {}",
node_id.with(ctx),
num_tokens,
capacity
),
ref kind => kind.fmt(f),
}
} else {
self.kind.fmt(f)
}
}
}
impl Error for AcesError {}