133 lines
4.5 KiB
Rust
133 lines
4.5 KiB
Rust
//! Errors reported while building, loading, or validating a scenario.
|
|
|
|
use core::fmt;
|
|
|
|
/// The category of a scenario error.
|
|
///
|
|
/// 场景错误的类别。
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
#[non_exhaustive]
|
|
pub enum ScenarioErrorKind {
|
|
/// The scenario name is empty.
|
|
EmptyName,
|
|
/// A resource with the identifier already exists.
|
|
DuplicateResource,
|
|
/// A task with the identifier already exists.
|
|
DuplicateTask,
|
|
/// A requirement names a resource that is not in the scenario.
|
|
UnknownResource,
|
|
/// A precedence constraint names a task that is not in the scenario.
|
|
UnknownTask,
|
|
/// A resource in the scenario is itself not usable.
|
|
InvalidResource,
|
|
/// A task in the scenario is itself not usable.
|
|
InvalidTask,
|
|
/// A precedence constraint would close a cycle.
|
|
CyclicPrecedence,
|
|
/// A time limit is negative or not finite.
|
|
InvalidTimeLimit,
|
|
/// An epoch is negative or not finite.
|
|
InvalidEpoch,
|
|
/// A line has too few arguments for its keyword.
|
|
MissingArgument,
|
|
/// A line has an argument that cannot be read as the expected type.
|
|
BadArgument,
|
|
/// A line does not begin with a known keyword.
|
|
UnknownKeyword,
|
|
/// A keyword appears before the scenario header, or a required header is
|
|
/// missing.
|
|
MissingHeader,
|
|
/// A field appears more than once where only one is allowed.
|
|
DuplicateField,
|
|
}
|
|
|
|
impl fmt::Display for ScenarioErrorKind {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let text = match self {
|
|
Self::EmptyName => "the scenario name is empty",
|
|
Self::DuplicateResource => "a resource with that identifier exists",
|
|
Self::DuplicateTask => "a task with that identifier exists",
|
|
Self::UnknownResource => "the resource is not in the scenario",
|
|
Self::UnknownTask => "the task is not in the scenario",
|
|
Self::InvalidResource => "the resource is not usable",
|
|
Self::InvalidTask => "the task is not usable",
|
|
Self::CyclicPrecedence => "the precedence constraint closes a cycle",
|
|
Self::InvalidTimeLimit => "the time limit is not usable",
|
|
Self::InvalidEpoch => "the epoch is not usable",
|
|
Self::MissingArgument => "a line is missing an argument",
|
|
Self::BadArgument => "an argument cannot be read as the expected type",
|
|
Self::UnknownKeyword => "the line begins with an unknown keyword",
|
|
Self::MissingHeader => "the scenario header is missing or out of place",
|
|
Self::DuplicateField => "the field appears more than once",
|
|
};
|
|
f.write_str(text)
|
|
}
|
|
}
|
|
|
|
/// A failure while building, loading, or validating a scenario.
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct ScenarioError {
|
|
kind: ScenarioErrorKind,
|
|
detail: Option<String>,
|
|
line: Option<usize>,
|
|
}
|
|
|
|
impl ScenarioError {
|
|
/// Creates an error with the given category.
|
|
///
|
|
/// 用给定类别创建一个错误。
|
|
pub fn new(kind: ScenarioErrorKind) -> Self {
|
|
Self {
|
|
kind,
|
|
detail: None,
|
|
line: None,
|
|
}
|
|
}
|
|
|
|
/// Attaches a description of the values that caused the failure.
|
|
///
|
|
/// 附加对该失败所涉数值的说明。
|
|
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
|
|
self.detail = Some(detail.into());
|
|
self
|
|
}
|
|
|
|
/// Attaches the one based line number a load failure came from.
|
|
pub fn with_line(mut self, line: usize) -> Self {
|
|
self.line = Some(line);
|
|
self
|
|
}
|
|
|
|
/// Returns the category of this failure.
|
|
///
|
|
/// 返回该失败的类别。
|
|
pub fn kind(&self) -> ScenarioErrorKind {
|
|
self.kind
|
|
}
|
|
|
|
/// Returns the detail text attached to this error, if any.
|
|
///
|
|
/// 返回附加在该错误上的说明文本,若有。
|
|
pub fn detail(&self) -> Option<&str> {
|
|
self.detail.as_deref()
|
|
}
|
|
|
|
/// Returns the line number this failure came from, if any.
|
|
pub fn line(&self) -> Option<usize> {
|
|
self.line
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ScenarioError {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match (self.line, &self.detail) {
|
|
(Some(line), Some(detail)) => write!(f, "line {line}: {}: {detail}", self.kind),
|
|
(Some(line), None) => write!(f, "line {line}: {}", self.kind),
|
|
(None, Some(detail)) => write!(f, "{}: {detail}", self.kind),
|
|
(None, None) => write!(f, "{}", self.kind),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl core::error::Error for ScenarioError {}
|