apsis-rs/crates/orbit/apsis-tle/src/field.rs

141 lines
4.5 KiB
Rust

//! The error type and result alias for element parsing.
use core::fmt;
/// The category of a parse failure.
///
/// 解析失败的类别。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ElementErrorKind {
/// A line is shorter than the format requires.
///
/// 某行短于格式要求的长度。
TooShort,
/// A fixed width field does not contain a well formed value.
///
/// 某定宽字段不含良构的数值。
InvalidField,
/// The checksum at the end of a line does not match the line contents.
///
/// 行末校验和与该行内容不符。
Checksum,
/// The two lines carry different element set numbers.
///
/// 两行携带不同的根数集编号。
MismatchedElementSet,
/// A character where a digit or a specific symbol was expected.
///
/// 期望数字或特定符号处出现了其他字符。
UnexpectedCharacter,
}
impl fmt::Display for ElementErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = match self {
Self::TooShort => "line is too short",
Self::InvalidField => "field is not well formed",
Self::Checksum => "line checksum does not match",
Self::MismatchedElementSet => "element set numbers differ between lines",
Self::UnexpectedCharacter => "unexpected character",
};
f.write_str(text)
}
}
/// A failure while parsing a two-line element set.
///
/// The error records which line failed and, where applicable, which columns
/// were being read, so that a caller can point at the offending text. Line
/// numbers are one based and column ranges are the one based inclusive
/// range from the format definition.
///
/// 解析两线根数集时的失败。
///
/// 该错误记录哪一行失败,并在适用时记录当时正在读取的列,使调用方能指出有问题的
/// 文本。行号从一开始,列区间为格式定义中从一开始的含两端区间。
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ElementError {
kind: ElementErrorKind,
line: usize,
columns: Option<(usize, usize)>,
detail: Option<String>,
}
impl ElementError {
/// Creates an error with the given kind, line number, and columns.
///
/// The line number is one based. The column range is the one based
/// inclusive range that was being read, if the failure is tied to a
/// field.
///
/// 用给定类别、行号与列区间创建错误。
///
/// 行号从一开始。列区间为当时正在读取的从一开始的含两端区间,当失败与某个
/// 字段相关时给出。
pub fn new(kind: ElementErrorKind, line: usize, columns: Option<(usize, usize)>) -> Self {
Self {
kind,
line,
columns,
detail: None,
}
}
/// Attaches a description of the offending text.
///
/// 附加对有问题的文本的说明。
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
/// Returns the category of this failure.
///
/// 返回该失败的类别。
pub fn kind(&self) -> ElementErrorKind {
self.kind
}
/// Returns the one based number of the line that failed.
///
/// 返回失败行的从一而行号。
pub fn line(&self) -> usize {
self.line
}
/// Returns the one based inclusive column range that failed, if any.
///
/// 返回失败的从一开始的含两端列区间,若有。
pub fn columns(&self) -> Option<(usize, usize)> {
self.columns
}
/// Returns the detail text attached to this error, if any.
///
/// 返回附加在该错误上的说明文本,若有。
pub fn detail(&self) -> Option<&str> {
self.detail.as_deref()
}
}
impl fmt::Display for ElementError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "line {}: {}", self.line, self.kind)?;
if let Some((first, last)) = self.columns {
write!(f, " (columns {first}-{last})")?;
}
if let Some(detail) = &self.detail {
write!(f, ": {detail}")?;
}
Ok(())
}
}
impl core::error::Error for ElementError {}
/// A [`Result`](core::result::Result) whose error type is [`ElementError`].
///
/// 错误类型为 [`ElementError`] 的 [`Result`](core::result::Result)。
pub type Result<T> = core::result::Result<T, ElementError>;