use crate::model::property::PropertyType;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug)]
#[non_exhaustive]
pub struct Error {
#[cfg(all(feature = "std", feature = "unstable"))]
backtrace: std::backtrace::Backtrace,
pub kind: ErrorKind,
}
impl Error {
pub(crate) fn from_kind(kind: ErrorKind) -> Error {
Error {
#[cfg(all(feature = "std", feature = "unstable"))]
backtrace: std::backtrace::Backtrace::capture(),
kind,
}
}
pub(crate) fn bad_magic() -> Error {
Error::from_kind(ErrorKind::BadMagic)
}
pub(crate) fn unknown_block(name: String) -> Error {
Error::from_kind(ErrorKind::UnknownBlock(name))
}
pub(crate) fn unknown_class(id: i32) -> Error {
Error::from_kind(ErrorKind::UnknownClass(id))
}
pub(crate) fn unknown_instance(inst: i32) -> Error {
Error::from_kind(ErrorKind::UnknownInstance(inst))
}
pub(crate) fn unknown_cframe(id: u8) -> Error {
Error::from_kind(ErrorKind::UnknownCFrame(id))
}
pub(crate) fn unknown_property(id: u8) -> Error {
Error::from_kind(ErrorKind::UnknownProperty(id))
}
pub(crate) fn unknown_variant(id: i32) -> Error {
Error::from_kind(ErrorKind::UnknownVariant(id))
}
#[cfg(feature = "mesh-format")]
pub(crate) fn unknown_mesh(id: i32) -> Error {
Error::from_kind(ErrorKind::UnknownMesh(id))
}
pub(crate) fn wrong_property_type(
name: String,
extra: Option<(PropertyType, PropertyType)>,
) -> Error {
Error::from_kind(ErrorKind::WrongPropertyType(name, extra))
}
pub(crate) fn missing_property(name: String) -> Error {
Error::from_kind(ErrorKind::MissingProperty(name))
}
pub(crate) fn unconsumed_properties(ty: String, remaining: Vec<String>) -> Error {
Error::from_kind(ErrorKind::UnconsumedProperties(ty, remaining))
}
pub(crate) fn inconsistent_tree() -> Error {
Error::from_kind(ErrorKind::InconsistentTree)
}
pub(crate) fn invalid_string() -> Error {
Error::from_kind(ErrorKind::InvalidString)
}
pub(crate) fn invalid_lz4() -> Error {
Error::from_kind(ErrorKind::InvalidLz4)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "RBXM Ser/De Error: {}", self.kind)?;
#[cfg(all(feature = "std", feature = "unstable"))]
{
writeln!(f, "{}", self.backtrace)?;
}
Ok(())
}
}
#[cfg(feature = "std")]
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::from_kind(ErrorKind::IoError(err))
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.kind {
ErrorKind::IoError(err) => Some(err),
_ => None,
}
}
#[cfg(feature = "unstable")]
fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
Some(&self.backtrace)
}
}
#[derive(Debug)]
pub enum ErrorKind {
BadMagic,
UnknownBlock(String),
UnknownClass(i32),
UnknownInstance(i32),
UnknownCFrame(u8),
UnknownProperty(u8),
UnknownVariant(i32),
UnknownMesh(i32),
WrongPropertyType(String, Option<(PropertyType, PropertyType)>),
MissingProperty(String),
UnconsumedProperties(String, Vec<String>),
InconsistentTree,
IoError(
#[cfg(feature = "std")] std::io::Error,
#[cfg(not(feature = "std"))] &'static str,
),
InvalidString,
InvalidLz4,
}
impl fmt::Display for ErrorKind {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
ErrorKind::BadMagic => "Invalid File Magic".to_string(),
ErrorKind::UnknownBlock(block) => format!("Unrecognized data-block type `{block}`"),
ErrorKind::UnknownClass(id) => format!("Reference to unknown class with ID `{id}`"),
ErrorKind::UnknownInstance(id) => {
format!("Reference to unknown instance with ID `{id}`")
}
ErrorKind::UnknownCFrame(id) => format!("Unknown CFrame type `{id}`"),
ErrorKind::UnknownProperty(id) => format!("Unknown property type `{id}`"),
ErrorKind::UnknownVariant(id) => format!("Unknown enum variant with ID `{id}`"),
ErrorKind::UnknownMesh(id) => format!("Unknown physics mesh kind with ID `{id}`"),
ErrorKind::WrongPropertyType(prop_name, tys) => match tys {
Some((expected, actual)) => {
format!(
"Property {} was the wrong type. Expected {}, got {}",
prop_name,
expected.name(),
actual.name()
)
}
None => format!("Property {prop_name} was of a wrong type"),
},
ErrorKind::MissingProperty(prop_name) => format!("Property {prop_name} was missing"),
ErrorKind::UnconsumedProperties(class_name, prop_names) => format!(
"Instance type {class_name} had unexpected properties with names {prop_names:?}"
),
ErrorKind::InconsistentTree => {
String::from("RBXM parent->child relationships were inconsistent")
}
ErrorKind::IoError(err) => format!("Error in IO: {err}"),
ErrorKind::InvalidString => "String contained invalid UTF data".to_string(),
ErrorKind::InvalidLz4 => "LZ4 block couldn't be deserialized".to_string(),
};
write!(fmt, "{msg}")
}
}