use std::fmt;
#[derive(Debug)]
pub enum SchemaError {
InvalidKind {
detail: String,
},
InvalidProperty {
detail: String,
},
KindMismatch {
expected: &'static str,
found: &'static str,
},
ValueTooLong {
max_len: usize,
found: usize,
},
ValueOutOfRange {
detail: String,
},
NullNotAllowed {
field: String,
},
EmptyStringNotAllowed {
field: String,
},
EngineAssigned {
field: Option<String>,
},
DuplicateName {
name: String,
},
InvalidName {
detail: String,
},
UnsupportedVersion {
found: u64,
supported: u64,
},
Parse {
detail: String,
},
Io(std::io::Error),
}
impl fmt::Display for SchemaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidKind { detail } => write!(f, "invalid field kind: {detail}"),
Self::InvalidProperty { detail } => write!(f, "invalid field property: {detail}"),
Self::KindMismatch { expected, found } => {
write!(f, "expected a {expected} value, found a {found} value")
}
Self::ValueTooLong { max_len, found } => write!(
f,
"text value exceeds the maximum length of {max_len} characters (found {found})"
),
Self::ValueOutOfRange { detail } => write!(f, "value out of range: {detail}"),
Self::NullNotAllowed { field } => {
write!(
f,
"field {field:?} does not allow null: the field is required"
)
}
Self::EmptyStringNotAllowed { field } => {
write!(
f,
"field {field:?} does not allow zero-length (empty) strings"
)
}
Self::EngineAssigned { field: Some(field) } => write!(
f,
"autonumber field {field:?} is engine-assigned; user-provided values are rejected"
),
Self::EngineAssigned { field: None } => {
write!(
f,
"autonumber values are engine-assigned; user-provided values are rejected"
)
}
Self::DuplicateName { name } => {
write!(
f,
"duplicate name {name:?}: object names are case-insensitive"
)
}
Self::InvalidName { detail } => write!(f, "invalid name: {detail}"),
Self::UnsupportedVersion { found, supported } => write!(
f,
"schema document version {found} is not supported — this DataCraft \
reads and writes versions up to {supported}"
),
Self::Parse { detail } => write!(f, "malformed schema document: {detail}"),
Self::Io(e) => write!(f, "schema document I/O error: {e}"),
}
}
}
impl From<std::io::Error> for SchemaError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl std::error::Error for SchemaError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn io_errors_chain_their_source() {
let io: SchemaError = std::io::Error::other("disk full").into();
assert!(std::error::Error::source(&io).is_some());
assert!(io.to_string().contains("disk full"));
let parse = SchemaError::Parse {
detail: "bad".to_owned(),
};
assert!(std::error::Error::source(&parse).is_none());
assert!(parse.to_string().contains("bad"));
}
}