feat(generate)!: derive PartialEq + Eq on GenerateError
Some checks failed
CI / checks (push) Waiting to run
CI / sanitize (push) Failing after 15s
CI / build (push) Failing after 16s
CI / check-wasm-stdlib (push) Failing after 14s

Also use `IoError` more consistently throughout the rest of the project
where its straightforward to do so.

BREAKING CHANGE: Changes public error types for config, generate, and
loader crates.
This commit is contained in:
Will Lillis 2026-09-07 03:46:22 -04:00
parent badf2882c6
commit 072f68c829
9 changed files with 77 additions and 27 deletions

View file

@ -31,6 +31,16 @@ pub struct IoError {
pub path: Option<PathBuf>,
}
impl PartialEq for IoError {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
&& self.error.kind() == other.error.kind()
&& self.error.raw_os_error() == other.error.raw_os_error()
}
}
impl Eq for IoError {}
impl IoError {
fn new(error: std::io::Error, path: Option<&Path>) -> Self {
Self {

View file

@ -83,7 +83,7 @@ struct ParseTableBuilder<'a> {
pub type BuildTableResult<T> = Result<T, ParseTableBuilderError>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum ParseTableBuilderError {
#[error("Unresolved conflict for symbol sequence:\n\n{0}")]
Conflict(#[from] ConflictError),
@ -97,7 +97,7 @@ pub enum ParseTableBuilderError {
StateCount(usize),
}
#[derive(Default, Debug, Serialize, Error, Deserialize)]
#[derive(Default, Debug, Serialize, Error, Deserialize, PartialEq, Eq)]
pub struct ConflictError {
pub symbol_sequence: Vec<String>,
pub conflicting_lookahead: String,
@ -105,7 +105,7 @@ pub struct ConflictError {
pub possible_resolutions: Vec<Resolution>,
}
#[derive(Default, Debug, Serialize, Error, Deserialize)]
#[derive(Default, Debug, Serialize, Error, Deserialize, PartialEq, Eq)]
pub struct Interpretation {
pub preceding_symbols: Vec<String>,
pub variable_name: String,
@ -118,14 +118,14 @@ pub struct Interpretation {
pub requires_eof_lookahead: bool,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum Resolution {
Precedence { symbols: Vec<String> },
Associativity { symbols: Vec<String> },
AddConflict { symbols: Vec<String> },
}
#[derive(Debug, Serialize, Deserialize, Error)]
#[derive(Debug, Serialize, Deserialize, Error, PartialEq, Eq)]
pub struct AmbiguousExtraError {
pub parent_symbols: Vec<String>,
}

View file

@ -73,7 +73,7 @@ pub const PARSER_HEADER: &str = include_str!("parser.h.inc");
pub type GenerateResult<T> = Result<T, GenerateError>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum GenerateError {
#[error("Error with specified path -- {0}")]
GrammarPath(IoError),
@ -107,6 +107,16 @@ pub struct IoError {
pub path: Option<PathBuf>,
}
impl PartialEq for IoError {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
&& self.error.kind() == other.error.kind()
&& self.error.raw_os_error() == other.error.raw_os_error()
}
}
impl Eq for IoError {}
#[cfg(feature = "load")]
impl IoError {
fn new(error: std::io::Error, path: Option<&Path>) -> Self {
@ -163,7 +173,7 @@ impl<'de> Deserialize<'de> for IoError {
pub type LoadGrammarFileResult<T> = Result<T, LoadGrammarError>;
#[cfg(feature = "load")]
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum LoadGrammarError {
#[error("Path to a grammar file with `.js` or `.json` extension is required")]
InvalidPath,
@ -176,7 +186,7 @@ pub enum LoadGrammarError {
}
#[cfg(feature = "load")]
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum ParseVersionError {
#[error("{0}")]
Version(String),
@ -190,7 +200,7 @@ pub enum ParseVersionError {
pub type JSResult<T> = Result<T, JSError>;
#[cfg(feature = "load")]
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum JSError {
#[error("Failed to run `{runtime}` -- {error}")]
JSRuntimeSpawn { runtime: String, error: String },

View file

@ -590,7 +590,7 @@ pub fn get_supertype_symbol_map(
#[cfg(feature = "load")]
pub type SuperTypeCycleResult<T> = Result<T, SuperTypeCycleError>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub struct SuperTypeCycleError {
items: Vec<String>,
}

View file

@ -115,7 +115,7 @@ pub struct GrammarJSON {
pub type ParseGrammarResult<T> = Result<T, ParseGrammarError>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum ParseGrammarError {
#[error("{0}")]
Serialization(String),

View file

@ -48,7 +48,7 @@ use super::{
pub type PrepareGrammarResult<T> = Result<T, PrepareGrammarError>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
#[error(transparent)]
pub enum PrepareGrammarError {
ValidatePrecedences(#[from] ValidatePrecedenceError),

View file

@ -33,7 +33,7 @@ const ABI_VERSION_WITH_RESERVED_WORDS: usize = 15;
pub type RenderResult<T> = Result<T, RenderError>;
#[derive(Debug, Error, Serialize, Deserialize)]
#[derive(Debug, Error, Serialize, Deserialize, PartialEq, Eq)]
pub enum RenderError {
#[error("Parse table action count {0} exceeds maximum value of {max}", max=u16::MAX)]
ParseTable(usize),

View file

@ -89,7 +89,7 @@ pub enum LoaderError {
)]
LockFileTimeout(PathBuf),
#[error("Failed to execute curl for {0} -- {1}")]
Curl(String, std::io::Error),
Curl(String, IoError),
#[error("Failed to load language in current directory:\n{0}")]
CurrentDirectoryLoad(Box<Self>),
#[error("External file path {0} is outside of parser directory {1}")]
@ -120,8 +120,12 @@ pub enum LoaderError {
Symbol(SymbolError),
#[error(transparent)]
Tags(#[from] TagsError),
#[error("Failed to execute tar for {0} -- {1}")]
Tar(String, std::io::Error),
#[error(
"Failed to execute tar for {path} -- {error}",
path = .0.path.as_deref().unwrap_or_else(|| Path::new("")).display(),
error = .0.error,
)]
Tar(IoError),
#[error("Unknown scope '{0}'")]
UnknownScope(String),
#[error("Failed to download {tool} from {url}")]
@ -134,9 +138,9 @@ pub enum LoaderError {
#[error(transparent)]
Wasm(#[from] WasmError),
#[error("Failed to run wasi-sdk clang -- {0}")]
WasmCompiler(std::io::Error),
WasmCompiler(IoError),
#[error("Failed to run wasm-opt -- {0}")]
WasmOptimizer(std::io::Error),
WasmOptimizer(IoError),
#[error("wasi-sdk clang command failed: {0}")]
WasmCompilation(String),
#[error("wasm-opt command failed: {0}")]
@ -145,7 +149,7 @@ pub enum LoaderError {
#[derive(Debug, Error)]
pub struct CompilerError {
pub error: std::io::Error,
pub error: IoError,
pub command: Box<Command>,
}
@ -166,6 +170,16 @@ pub struct IoError {
pub path: Option<PathBuf>,
}
impl PartialEq for IoError {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
&& self.error.kind() == other.error.kind()
&& self.error.raw_os_error() == other.error.raw_os_error()
}
}
impl Eq for IoError {}
impl IoError {
fn new(error: std::io::Error, path: Option<&Path>) -> Self {
Self {
@ -1326,9 +1340,10 @@ impl Loader {
display_build_cmd(&command);
}
let compiler_path = PathBuf::from(command.get_program());
let output = command.output().map_err(|e| {
LoaderError::Compiler(CompilerError {
error: e,
error: IoError::new(e, Some(&compiler_path)),
command: Box::new(command),
})
})?;
@ -1457,7 +1472,7 @@ impl Loader {
let compile_output = compile_command
.output()
.map_err(LoaderError::WasmCompiler)?;
.map_err(|e| LoaderError::WasmCompiler(IoError::new(e, Some(&clang_exe))))?;
if self.verbose {
if !compile_output.stdout.is_empty() {
info!("stdout:{}", String::from_utf8_lossy(&compile_output.stdout));
@ -1483,7 +1498,9 @@ impl Loader {
display_build_cmd(&opt_command);
}
let opt_output = opt_command.output().map_err(LoaderError::WasmOptimizer)?;
let opt_output = opt_command
.output()
.map_err(|e| LoaderError::WasmOptimizer(IoError::new(e, Some(&wasm_opt_exe))))?;
if self.verbose {
if !opt_output.stdout.is_empty() {
info!("stdout:{}", String::from_utf8_lossy(&opt_output.stdout));
@ -1517,7 +1534,7 @@ impl Loader {
.arg("-C")
.arg(destination)
.status()
.map_err(|e| LoaderError::Tar(archive_path.to_string_lossy().to_string(), e))?;
.map_err(|e| LoaderError::Tar(IoError::new(e, Some(archive_path))))?;
if !status.success() {
return Err(LoaderError::Extraction(
@ -1712,7 +1729,7 @@ impl Loader {
.arg(&temp_tar_path)
.arg(url)
.status()
.map_err(|e| LoaderError::Curl(url.to_string(), e))?;
.map_err(|e| LoaderError::Curl(url.to_string(), IoError::new(e, None)))?;
if !status.success() {
Err(LoaderError::WasmToolDownload {

View file

@ -580,7 +580,15 @@ fn download_tool(
.arg(&temp_tar_path)
.arg(url)
.status()
.map_err(|e| LoaderError::Curl(url.to_string(), e))?;
.map_err(|e| {
LoaderError::Curl(
url.to_string(),
IoError {
error: e,
path: None,
},
)
})?;
if !status.success() {
Err(LoaderError::WasmToolDownload {
@ -620,7 +628,12 @@ fn extract_tar_gz_with_strip(archive_path: &Path, destination: &Path) -> Result<
.arg("-C")
.arg(destination)
.status()
.map_err(|e| LoaderError::Tar(archive_path.to_string_lossy().to_string(), e))?;
.map_err(|e| {
LoaderError::Tar(IoError {
error: e,
path: Some(archive_path.to_path_buf()),
})
})?;
if !status.success() {
Err(LoaderError::Extraction(
@ -684,7 +697,7 @@ fn ensure_wasi_libc_source_exists() -> Result<PathBuf> {
.arg(&archive_path)
.arg(&url)
.status()
.map_err(|error| LoaderError::Curl(url.clone(), error))?;
.map_err(|error| LoaderError::Curl(url.clone(), IoError { error, path: None }))?;
if !status.success() {
return Err(LoaderError::WasmToolDownload {
tool: "wasi-libc",