use bstr::BString;
use crate::{Axis, Channel};
use lexical::Error as LexicalError;
use std::{error::Error as StdError, fmt, io};
#[derive(Debug)]
pub struct LoadError {
kind: LoadErrorKind,
}
impl LoadError {
#[inline]
pub fn line(&self) -> Option<usize> {
match self.kind {
LoadErrorKind::Joints(ref e) => e.line(),
LoadErrorKind::Motion(ref e) => e.line(),
}
}
#[inline]
pub fn kind(&self) -> &LoadErrorKind {
&self.kind
}
#[inline]
pub fn into_kind(self) -> LoadErrorKind {
self.kind
}
}
impl<K: Into<LoadErrorKind>> From<K> for LoadError {
#[inline]
fn from(kind: K) -> Self {
LoadError { kind: kind.into() }
}
}
impl fmt::Display for LoadError {
#[inline]
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmtr, "{}: {}", self.description(), self.source().unwrap())
}
}
impl StdError for LoadError {
#[inline]
fn description(&self) -> &'static str {
match self.kind {
LoadErrorKind::Joints(_) => "Could not load hierarchy",
LoadErrorKind::Motion(_) => "Could not load motion",
}
}
#[inline]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self.kind {
LoadErrorKind::Joints(ref e) => Some(e),
LoadErrorKind::Motion(ref e) => Some(e),
}
}
}
#[derive(Debug)]
pub enum LoadErrorKind {
Joints(LoadJointsError),
Motion(LoadMotionError),
}
impl From<LoadJointsError> for LoadErrorKind {
#[inline]
fn from(e: LoadJointsError) -> Self {
LoadErrorKind::Joints(e)
}
}
impl From<LoadMotionError> for LoadErrorKind {
#[inline]
fn from(e: LoadMotionError) -> Self {
LoadErrorKind::Motion(e)
}
}
#[derive(Debug)]
pub enum LoadJointsError {
Io(io::Error),
MissingRoot,
MissingJointName {
line: usize,
},
UnexpectedChannelsSection {
line: usize,
},
ParseNumChannelsError {
error: Option<LexicalError>,
line: usize,
},
ParseChannelError {
error: ParseChannelError,
line: usize,
},
UnexpectedOffsetSection {
line: usize,
},
ParseOffsetError {
parse_float_error: LexicalError,
axis: Axis,
line: usize,
},
MissingOffsetAxis {
axis: Axis,
line: usize,
},
}
impl LoadJointsError {
#[inline]
pub fn line(&self) -> Option<usize> {
match *self {
LoadJointsError::MissingJointName { line }
| LoadJointsError::UnexpectedChannelsSection { line }
| LoadJointsError::ParseNumChannelsError { line, .. }
| LoadJointsError::ParseChannelError { line, .. }
| LoadJointsError::UnexpectedOffsetSection { line }
| LoadJointsError::ParseOffsetError { line, .. }
| LoadJointsError::MissingOffsetAxis { line, .. } => Some(line),
_ => None,
}
}
}
impl From<io::Error> for LoadJointsError {
#[inline]
fn from(e: io::Error) -> Self {
LoadJointsError::Io(e)
}
}
impl fmt::Display for LoadJointsError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
LoadJointsError::Io(ref e) => fmt::Display::fmt(&e, f),
LoadJointsError::MissingRoot => f.write_str("The root heirarchy could not be found"),
LoadJointsError::MissingJointName { line } => {
write!(f, "{}: the name is missing from the joints section", line)
}
LoadJointsError::UnexpectedChannelsSection { line } => write!(
f,
"{}: unexpectedly encountered a \"CHANNELS\" section",
line
),
LoadJointsError::ParseNumChannelsError { ref error, line } => match error {
Some(ref e) => write!(f, "{}: could not parse the number of channels: {}", line, e),
None => write!(f, "{}: could not find the number of channels", line),
},
LoadJointsError::ParseChannelError { ref error, line } => {
write!(f, "{}: could not parse channel: {}", line, error)
}
LoadJointsError::UnexpectedOffsetSection { line } => write!(
f,
"{}: unexpectedly encountered an \"OFFSET\" section",
line
),
LoadJointsError::ParseOffsetError {
ref parse_float_error,
axis,
line,
} => write!(
f,
"{}: could not parse the {}-axis offset: {}",
line, axis, parse_float_error
),
LoadJointsError::MissingOffsetAxis { axis, line } => {
write!(f, "{}: the {}-axis offset value is missing", line, axis)
}
}
}
}
impl StdError for LoadJointsError {
#[inline]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match *self {
LoadJointsError::Io(ref e) => Some(e),
LoadJointsError::ParseNumChannelsError { ref error, .. } => {
error.as_ref().map(|e| e as &(dyn StdError + 'static))
}
LoadJointsError::ParseChannelError { ref error, .. } => Some(error),
LoadJointsError::ParseOffsetError {
ref parse_float_error,
..
} => Some(parse_float_error),
_ => None,
}
}
}
#[derive(Debug)]
pub enum LoadMotionError {
Io(io::Error),
MissingMotionSection {
line: usize,
},
MissingNumFrames {
parse_error: Option<LexicalError>,
line: usize,
},
MissingFrameTime {
parse_error: Option<LexicalError>,
line: usize,
},
ParseMotionSection {
parse_error: LexicalError,
channel_index: usize,
line: usize,
},
MotionCountMismatch {
actual_total_motion_values: usize,
expected_total_motion_values: usize,
expected_num_frames: usize,
expected_num_clips: usize,
},
}
impl LoadMotionError {
pub fn line(&self) -> Option<usize> {
match *self {
LoadMotionError::MissingMotionSection { line }
| LoadMotionError::MissingNumFrames { line, .. }
| LoadMotionError::MissingFrameTime { line, .. }
| LoadMotionError::ParseMotionSection { line, .. } => Some(line),
_ => None,
}
}
}
impl fmt::Display for LoadMotionError {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
LoadMotionError::Io(ref e) => {
fmt::Display::fmt(e, fmtr)
}
LoadMotionError::MissingMotionSection {
line
} => {
write!(fmtr, "{}: {}", line, self.description())
}
LoadMotionError::MissingNumFrames { ref parse_error, line } => {
if let Some(ref e) = parse_error {
write!(fmtr, "{}: could not parse the num frames value: {}", line, e)
} else {
write!(fmtr, "{}: {}", line, self.description())
}
}
LoadMotionError::MissingFrameTime { ref parse_error, line } => {
if let Some(ref e) = parse_error {
write!(fmtr, "{}: could not parse the frame time: {}", line, e)
} else {
write!(fmtr, "{}: {}", line, self.description())
}
}
LoadMotionError::ParseMotionSection { ref parse_error, line, .. } => {
write!(fmtr, "{}: {} ({})", line, self.description(), parse_error)
}
LoadMotionError::MotionCountMismatch {
actual_total_motion_values,
expected_total_motion_values,
expected_num_frames,
expected_num_clips,
} => {
write!(
fmtr,
"expected to find {} motion values, found {} values (num frames = {}, num clips = {})",
expected_total_motion_values,
actual_total_motion_values,
expected_num_frames,
expected_num_clips)
}
}
}
}
impl StdError for LoadMotionError {
#[inline]
fn description(&self) -> &str {
match *self {
LoadMotionError::Io(ref e) => e.description(),
LoadMotionError::MissingMotionSection { .. } => {
"the 'MOTION' section of the bvh file is missing"
}
LoadMotionError::MissingNumFrames { .. } => {
"the number of frames section is missing from the bvh file"
}
LoadMotionError::MissingFrameTime { .. } => {
"the frame time is missing from the bvh file"
}
LoadMotionError::ParseMotionSection { .. } => "could not parse the motion value",
LoadMotionError::MotionCountMismatch { .. } => "unexpected number of motion values",
}
}
#[inline]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match *self {
LoadMotionError::Io(ref e) => Some(e),
LoadMotionError::MissingFrameTime {
parse_error: Some(ref e),
..
} => Some(e),
LoadMotionError::ParseMotionSection {
ref parse_error, ..
} => Some(parse_error),
LoadMotionError::MissingNumFrames {
parse_error: Some(ref e),
..
} => Some(e),
_ => None,
}
}
}
impl From<io::Error> for LoadMotionError {
#[inline]
fn from(e: io::Error) -> Self {
LoadMotionError::Io(e)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum SetMotionError<'a> {
BadFrame(usize),
BadChannel(&'a Channel),
}
impl fmt::Display for SetMotionError<'_> {
#[inline]
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
SetMotionError::BadFrame(frame) => write!(fmtr, "Frame {} was out of bounds", frame),
SetMotionError::BadChannel(channel) => write!(
fmtr,
"Channel {} of the bvh was out of bounds",
channel.motion_index
),
}
}
}
impl StdError for SetMotionError<'_> {
#[inline]
fn description(&self) -> &'static str {
match *self {
SetMotionError::BadFrame(_) => "The frame was out of bounds",
SetMotionError::BadChannel(_) => "The channel was out of bounds",
}
}
}
#[derive(Debug)]
pub struct ParseChannelError {
bad_string: BString,
}
impl ParseChannelError {
#[inline]
pub fn into_inner(self) -> BString {
self.bad_string
}
}
impl<S: Into<BString>> From<S> for ParseChannelError {
#[inline]
fn from(bad_string: S) -> Self {
ParseChannelError {
bad_string: bad_string.into(),
}
}
}
impl fmt::Display for ParseChannelError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {:?}", self.description(), &self.bad_string)
}
}
impl StdError for ParseChannelError {
#[inline]
fn description(&self) -> &'static str {
"The channel could not be parsed from the given string"
}
}