use std::convert::Infallible;
use std::{error, io, mem, result};
use crate::{pcp, sdf, usd, usda, usdc, usdz};
const INLINE_ERROR_BUDGET: usize = 64;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Path(#[from] sdf::PathParseError),
#[error(transparent)]
Data(#[from] sdf::DataError),
#[error(transparent)]
Cast(#[from] sdf::CastError),
#[error(transparent)]
Convert(Box<dyn error::Error + Send + Sync>),
#[error(transparent)]
Expr(#[from] sdf::ExprError),
#[error(transparent)]
PathExpr(#[from] sdf::EvalError),
#[error(transparent)]
Format(#[from] sdf::FormatError),
#[error(transparent)]
Export(#[from] sdf::ExportError),
#[error(transparent)]
Parse(Box<usda::ParseError>),
#[error(transparent)]
Read(#[from] usdc::ReadError),
#[error(transparent)]
Archive(Box<usdz::ArchiveError>),
#[error(transparent)]
PopulationMask(#[from] pcp::PopulationMaskError),
#[error(transparent)]
Query(#[from] pcp::QueryError),
#[error(transparent)]
Authoring(#[from] usd::StageAuthoringError),
#[error(transparent)]
NamespaceEdit(#[from] usd::NamespaceEditError),
#[error(transparent)]
ApplyApi(#[from] usd::ApplyApiError),
#[error(transparent)]
SchemaRegistry(Box<usd::SchemaRegistryError>),
#[error("failed to resolve asset path: {0}")]
UnresolvedAsset(String),
#[error("no file format registered for {0}")]
UnsupportedFormat(String),
}
impl Error {
pub fn convert(error: impl error::Error + Send + Sync + 'static) -> Self {
Self::Convert(Box::new(error))
}
}
pub type Result<T, E = Error> = result::Result<T, E>;
const _: () = assert!(mem::size_of::<Error>() <= INLINE_ERROR_BUDGET + mem::size_of::<usize>());
impl From<Infallible> for Error {
fn from(error: Infallible) -> Self {
match error {}
}
}
#[cfg(target_pointer_width = "64")]
const _: () = assert!(mem::size_of::<usda::ParseError>() > INLINE_ERROR_BUDGET);
impl From<usda::ParseError> for Error {
fn from(error: usda::ParseError) -> Self {
Self::Parse(Box::new(error))
}
}
#[cfg(target_pointer_width = "64")]
const _: () = assert!(mem::size_of::<usdz::ArchiveError>() > INLINE_ERROR_BUDGET);
impl From<usdz::ArchiveError> for Error {
fn from(error: usdz::ArchiveError) -> Self {
Self::Archive(Box::new(error))
}
}
#[cfg(target_pointer_width = "64")]
const _: () = assert!(mem::size_of::<usd::SchemaRegistryError>() > INLINE_ERROR_BUDGET);
impl From<usd::SchemaRegistryError> for Error {
fn from(error: usd::SchemaRegistryError) -> Self {
Self::SchemaRegistry(Box::new(error))
}
}
impl From<sdf::AuthoringError> for Error {
fn from(error: sdf::AuthoringError) -> Self {
Self::Authoring(error.into())
}
}
impl From<sdf::EditError> for Error {
fn from(error: sdf::EditError) -> Self {
Self::Authoring(error.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn transparent_display() {
let error = Error::from(sdf::Path::new("not a path").unwrap_err());
assert_eq!(
error.to_string(),
sdf::Path::new("not a path").unwrap_err().to_string(),
"the root error renders as the module error it wraps"
);
}
#[test]
fn nested_cause_stays_typed() {
let error = Error::from(pcp::QueryError::from(sdf::PathParseError {
input: "x".into(),
offset: 0,
reason: "test",
}));
let Error::Query(pcp::QueryError::Path(path_error)) = error else {
panic!("expected Query(Path), got: {error}");
};
assert_eq!(path_error.reason, "test");
}
}