use std::{
fmt,
io::{self, Read},
};
use rbx_dom_weak::types::VariantType;
#[derive(Debug)]
pub struct DecodeError {
inner: Box<DecodeErrorImpl>,
}
impl DecodeError {
pub(crate) fn new_from_reader<R: Read>(
kind: DecodeErrorKind,
reader: &xml::EventReader<R>,
) -> DecodeError {
use xml::common::Position;
let pos = reader.position();
DecodeError {
inner: Box::new(DecodeErrorImpl {
kind,
line: (pos.row + 1) as usize,
column: pos.column as usize,
}),
}
}
pub fn line(&self) -> usize {
self.inner.line
}
pub fn column(&self) -> usize {
self.inner.column
}
}
impl fmt::Display for DecodeError {
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
write!(
output,
"line {}, column {}: {}",
self.inner.line, self.inner.column, self.inner.kind
)
}
}
impl std::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.kind.source()
}
}
#[derive(Debug)]
struct DecodeErrorImpl {
kind: DecodeErrorKind,
line: usize,
column: usize,
}
#[derive(Debug)]
pub(crate) enum DecodeErrorKind {
Xml(xml::reader::Error),
ParseFloat(std::num::ParseFloatError),
ParseInt(std::num::ParseIntError),
DecodeBase64(base64::DecodeError),
MigrationError(rbx_reflection::MigrationError),
TypeError(rbx_dom_weak::types::Error),
WrongDocVersion(String),
UnexpectedEof,
UnexpectedXmlEvent(xml::reader::XmlEvent),
MissingAttribute(&'static str),
UnknownProperty {
class_name: String,
property_name: String,
},
InvalidContent(&'static str),
NameMustBeString(VariantType),
UnsupportedPropertyConversion {
class_name: String,
property_name: String,
expected_type: VariantType,
actual_type: VariantType,
message: String,
},
}
impl fmt::Display for DecodeErrorKind {
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
use self::DecodeErrorKind::*;
match self {
Xml(err) => write!(output, "{err}"),
ParseFloat(err) => write!(output, "{err}"),
ParseInt(err) => write!(output, "{err}"),
DecodeBase64(err) => write!(output, "{err}"),
MigrationError(err) => write!(output, "{err}"),
TypeError(err) => write!(output, "{err}"),
WrongDocVersion(version) => {
write!(output, "Invalid version '{version}', expected version 4")
}
UnexpectedEof => write!(output, "Unexpected end-of-file"),
UnexpectedXmlEvent(event) => write!(output, "Unexpected XML event {event:?}"),
MissingAttribute(attribute_name) => {
write!(output, "Missing attribute '{attribute_name}'")
}
UnknownProperty {
class_name,
property_name,
} => write!(output, "Property {class_name}.{property_name} is unknown"),
InvalidContent(explain) => write!(output, "Invalid text content: {explain}"),
NameMustBeString(ty) => write!(
output,
"The 'Name' property must be of type String, but it was {ty:?}"
),
UnsupportedPropertyConversion {
class_name,
property_name,
expected_type,
actual_type,
message,
} => write!(
output,
"Property {class_name}.{property_name} is expected to be of type {expected_type:?}, but it was of type {actual_type:?} \
When trying to convert, this error occured: {message}"
),
}
}
}
impl std::error::Error for DecodeErrorKind {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::DecodeErrorKind::*;
match self {
Xml(err) => Some(err),
ParseFloat(err) => Some(err),
ParseInt(err) => Some(err),
DecodeBase64(err) => Some(err),
MigrationError(err) => Some(err),
_ => None,
}
}
}
impl From<xml::reader::Error> for DecodeErrorKind {
fn from(error: xml::reader::Error) -> DecodeErrorKind {
DecodeErrorKind::Xml(error)
}
}
impl From<std::num::ParseFloatError> for DecodeErrorKind {
fn from(error: std::num::ParseFloatError) -> DecodeErrorKind {
DecodeErrorKind::ParseFloat(error)
}
}
impl From<std::num::ParseIntError> for DecodeErrorKind {
fn from(error: std::num::ParseIntError) -> DecodeErrorKind {
DecodeErrorKind::ParseInt(error)
}
}
impl From<base64::DecodeError> for DecodeErrorKind {
fn from(error: base64::DecodeError) -> DecodeErrorKind {
DecodeErrorKind::DecodeBase64(error)
}
}
#[derive(Debug)]
pub struct EncodeError {
kind: Box<EncodeErrorKind>,
}
impl EncodeError {
pub(crate) fn new(kind: EncodeErrorKind) -> EncodeError {
EncodeError {
kind: Box::new(kind),
}
}
}
impl fmt::Display for EncodeError {
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
write!(output, "{}", self.kind)
}
}
impl std::error::Error for EncodeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.kind.source()
}
}
#[derive(Debug)]
pub(crate) enum EncodeErrorKind {
Io(io::Error),
Xml(xml::writer::Error),
Type(rbx_dom_weak::types::Error),
UnknownProperty {
class_name: String,
property_name: String,
},
UnsupportedPropertyType(VariantType),
UnsupportedPropertyConversion {
class_name: String,
property_name: String,
expected_type: VariantType,
actual_type: VariantType,
message: String,
},
UnsupportedFontStyle(rbx_dom_weak::types::FontStyle),
}
impl fmt::Display for EncodeErrorKind {
fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
use self::EncodeErrorKind::*;
match self {
Io(err) => write!(output, "{err}"),
Xml(err) => write!(output, "{err}"),
Type(err) => write!(output, "{err}"),
UnknownProperty {
class_name,
property_name,
} => write!(output, "Property {class_name}.{property_name} is unknown"),
UnsupportedPropertyType(ty) => {
write!(output, "Properties of type {ty:?} cannot be encoded yet")
}
UnsupportedPropertyConversion {
class_name,
property_name,
expected_type,
actual_type,
message,
} => write!(
output,
"Property {class_name}.{property_name} is expected to be of type {expected_type:?}, but it was of type {actual_type:?} \
When trying to convert the value, this error occured: {message}"
),
UnsupportedFontStyle(style) => write!(output, "Cannot serialize FontStyle of type {style:?}")
}
}
}
impl std::error::Error for EncodeErrorKind {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::EncodeErrorKind::*;
match self {
Io(err) => Some(err),
Xml(err) => Some(err),
Type(err) => Some(err),
UnknownProperty { .. }
| UnsupportedPropertyType(_)
| UnsupportedPropertyConversion { .. }
| UnsupportedFontStyle(_) => None,
}
}
}
impl From<xml::writer::Error> for EncodeErrorKind {
fn from(error: xml::writer::Error) -> EncodeErrorKind {
EncodeErrorKind::Xml(error)
}
}
impl From<io::Error> for EncodeErrorKind {
fn from(error: io::Error) -> EncodeErrorKind {
EncodeErrorKind::Io(error)
}
}
impl From<rbx_dom_weak::types::Error> for EncodeErrorKind {
fn from(error: rbx_dom_weak::types::Error) -> EncodeErrorKind {
EncodeErrorKind::Type(error)
}
}