use crate::kv::KvError; use wasm_bindgen::{JsCast, JsValue}; /// All possible Error variants that might be encountered while working with a Worker. #[derive(Debug)] #[non_exhaustive] pub enum Error { BadEncoding, BodyUsed, Json((String, u16)), JsError(String), #[cfg(feature = "http")] Http(http::Error), Infallible, Internal(JsValue), Io(std::io::Error), BindingError(String), RouteInsertError(matchit::InsertError), RouteNoDataError, RustError(String), SerdeJsonError(serde_json::Error), SerdeWasmBindgenError(serde_wasm_bindgen::Error), #[cfg(feature = "http")] StatusCode(http::status::InvalidStatusCode), #[cfg(feature = "d1")] D1(crate::d1::D1Error), Utf8Error(std::str::Utf8Error), #[cfg(feature = "timezone")] TimezoneError, KvError(KvError), } unsafe impl Sync for Error {} unsafe impl Send for Error {} #[cfg(feature = "http")] impl From for Error { fn from(value: http::Error) -> Self { Self::Http(value) } } #[cfg(feature = "http")] impl From for Error { fn from(value: http::status::InvalidStatusCode) -> Self { Self::StatusCode(value) } } #[cfg(feature = "http")] impl From for Error { fn from(value: http::header::InvalidHeaderName) -> Self { Self::RustError(format!("Invalid header name: {value:?}")) } } #[cfg(feature = "http")] impl From for Error { fn from(value: http::header::InvalidHeaderValue) -> Self { Self::RustError(format!("Invalid header value: {value:?}")) } } #[cfg(feature = "timezone")] impl From for Error { fn from(_value: chrono_tz::ParseError) -> Self { Self::RustError("Invalid timezone".to_string()) } } impl From for Error { fn from(value: std::str::Utf8Error) -> Self { Self::Utf8Error(value) } } impl From for Error { fn from(_value: core::convert::Infallible) -> Self { Error::Infallible } } impl From for Error { fn from(e: KvError) -> Self { Self::KvError(e) } } impl From for Error { fn from(e: url::ParseError) -> Self { Self::RustError(e.to_string()) } } impl From for Error { fn from(e: serde_urlencoded::de::Error) -> Self { Self::RustError(e.to_string()) } } impl From for Error { fn from(e: serde_wasm_bindgen::Error) -> Self { let val: JsValue = e.into(); val.into() } } #[cfg(feature = "d1")] impl From for Error { fn from(e: crate::d1::D1Error) -> Self { Self::D1(e) } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::BadEncoding => write!(f, "content-type mismatch"), Error::BodyUsed => write!(f, "body has already been read"), Error::Json((msg, status)) => write!(f, "{msg} (status: {status})"), Error::JsError(s) | Error::RustError(s) => { write!(f, "{s}") } #[cfg(feature = "http")] Error::Http(e) => write!(f, "http::Error: {e}"), Error::Infallible => write!(f, "infallible"), Error::Internal(_) => write!(f, "unrecognized JavaScript object"), Error::Io(e) => write!(f, "IO Error: {e}"), Error::BindingError(name) => write!(f, "no binding found for `{name}`"), Error::RouteInsertError(e) => write!(f, "failed to insert route: {e}"), Error::RouteNoDataError => write!(f, "route has no corresponding shared data"), Error::SerdeJsonError(e) => write!(f, "Serde Error: {e}"), Error::SerdeWasmBindgenError(e) => write!(f, "Serde Error: {e}"), #[cfg(feature = "http")] Error::StatusCode(e) => write!(f, "{e}"), #[cfg(feature = "d1")] Error::D1(e) => write!(f, "D1: {e:#?}"), Error::Utf8Error(e) => write!(f, "{e}"), #[cfg(feature = "timezone")] Error::TimezoneError => write!(f, "Timezone Error"), Error::KvError(KvError::JavaScript(s)) => write!(f, "js error: {s:?}"), Error::KvError(KvError::Serialization(s)) => { write!(f, "unable to serialize/deserialize: {s}") } Error::KvError(KvError::InvalidKvStore(s)) => write!(f, "invalid kv store: {s}"), } } } impl std::error::Error for Error {} // Not sure if the changes I've made here are good or bad... impl From for Error { fn from(v: JsValue) -> Self { match v.as_string().or_else(|| { v.dyn_ref::().map(|e| { format!( "Error: {} - Cause: {}", e.to_string(), e.cause() .as_string() .or_else(|| { Some(e.to_string().into()) }) .unwrap_or(String::from("N/A")) ) }) }) { Some(s) => Self::JsError(s), None => Self::Internal(v), } } } impl From for Error { fn from(error: std::io::Error) -> Self { Self::Io(error) } } impl From for JsValue { fn from(e: Error) -> Self { JsValue::from_str(&e.to_string()) } } impl From<&str> for Error { fn from(a: &str) -> Self { Error::RustError(a.to_string()) } } impl From for Error { fn from(a: String) -> Self { Error::RustError(a) } } impl From for Error { fn from(e: matchit::InsertError) -> Self { Error::RouteInsertError(e) } } impl From for Error { fn from(e: serde_json::Error) -> Self { Error::SerdeJsonError(e) } }