Skip to main content

elm_rust_binding/
error.rs

1use std::{fmt::Display, path::PathBuf};
2
3/// Main error type for this crate.
4#[derive(Debug)]
5pub enum Error {
6    #[cfg(feature = "quickjs")]
7    RuntimeError(quickjs_runtime::jsutils::JsError),
8    /// JavaScript parsing or execution error.
9    NonF64Number(serde_json::Number),
10    SerdeJson(serde_json::Error),
11    // Could not infer elm types based on given rust input/output types.
12    TypeAnalysisError(serde_reflection::Error),
13    // Failed to read/write/delete files.
14    DiskIOError {
15        path: PathBuf,
16        source: std::io::Error,
17    },
18    // The qualified function name had the wrong format, or the Elm code did not compile.
19    InvalidElmCall(String),
20}
21
22/// A simple Result alias with the crate specific `Error` type.
23pub type Result<T> = std::result::Result<T, Box<Error>>;
24
25impl Error {
26    pub(crate) fn map_disk_error(path: PathBuf) -> impl FnOnce(std::io::Error) -> Error {
27        |source| Error::DiskIOError { path, source }
28    }
29}
30
31impl Display for Error {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        match self {
34            Error::RuntimeError(error) => error.fmt(f),
35            Error::TypeAnalysisError(error) => error.fmt(f),
36            Error::DiskIOError { path, source } => {
37                                        f.write_fmt(format_args!("DiskIOError at {path:?}: {source}"))
38                                    }
39            Error::InvalidElmCall(function_name) => f.write_fmt(format_args!("Invalid Elm Call {function_name}. Expected format is MyModule.MySubmodule.myMethod.")),
40            Error::SerdeJson(error) => error.fmt(f),
41            Error::NonF64Number(number) => f.write_fmt(format_args!("Non f64 number {number}")),
42        }
43    }
44}
45
46impl std::error::Error for Error {}
47
48#[cfg(feature = "quickjs")]
49impl From<quickjs_runtime::jsutils::JsError> for Box<Error> {
50    fn from(value: quickjs_runtime::jsutils::JsError) -> Self {
51        Box::new(Error::RuntimeError(value))
52    }
53}
54
55#[cfg(feature = "quickjs")]
56impl From<quickjs_runtime::values::JsValueFacade> for Box<Error> {
57    fn from(value: quickjs_runtime::values::JsValueFacade) -> Self {
58        Box::new(Error::RuntimeError(
59            quickjs_runtime::jsutils::JsError::new_string(format!(
60                "JS threw an Error (most likely a rejected promise): {value:?}"
61            )),
62        ))
63    }
64}
65
66impl From<serde_json::Error> for Box<Error> {
67    fn from(value: serde_json::Error) -> Self {
68        Box::new(Error::SerdeJson(value))
69    }
70}
71
72impl From<serde_reflection::Error> for Box<Error> {
73    fn from(value: serde_reflection::Error) -> Self {
74        Box::new(Error::TypeAnalysisError(value))
75    }
76}