#[cfg(feature = "std")]
extern crate std;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ErrorContext {
pub operation: &'static str,
pub hint: &'static str,
pub numeric_context: Option<usize>,
}
impl ErrorContext {
pub const fn new(operation: &'static str, hint: &'static str) -> Self {
Self {
operation,
hint,
numeric_context: None,
}
}
pub const fn with_numeric(operation: &'static str, hint: &'static str, value: usize) -> Self {
Self {
operation,
hint,
numeric_context: Some(value),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChartError {
InsufficientData,
InvalidRange,
InvalidData,
MemoryFull,
RenderingError,
InvalidConfiguration,
ConfigurationError,
RenderError(RenderError),
LayoutError(LayoutError),
DataError(DataError),
#[cfg(feature = "animations")]
AnimationError(AnimationError),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataError {
SeriesNotFound {
context: Option<ErrorContext>,
},
IndexOutOfBounds {
context: Option<ErrorContext>,
},
InvalidDataPoint {
context: Option<ErrorContext>,
},
ScalingError {
context: Option<ErrorContext>,
},
BufferFull {
context: Option<ErrorContext>,
},
InsufficientData {
context: Option<ErrorContext>,
},
}
impl DataError {
pub const fn buffer_full(operation: &'static str, capacity: usize) -> Self {
Self::BufferFull {
context: Some(ErrorContext::with_numeric(
operation,
"Increase buffer capacity or remove old data",
capacity,
)),
}
}
pub const fn insufficient_data(
operation: &'static str,
_required: usize,
found: usize,
) -> Self {
Self::InsufficientData {
context: Some(ErrorContext::with_numeric(
operation,
"Add more data points",
found,
)),
}
}
pub const fn index_out_of_bounds(
operation: &'static str,
_index: usize,
length: usize,
) -> Self {
Self::IndexOutOfBounds {
context: Some(ErrorContext::with_numeric(
operation,
"Check array bounds before accessing",
length,
)),
}
}
pub const fn invalid_data_point(operation: &'static str) -> Self {
Self::InvalidDataPoint {
context: Some(ErrorContext::new(
operation,
"Ensure data points contain valid finite values",
)),
}
}
pub const fn simple(kind: DataErrorKind) -> Self {
match kind {
DataErrorKind::SeriesNotFound => Self::SeriesNotFound { context: None },
DataErrorKind::IndexOutOfBounds => Self::IndexOutOfBounds { context: None },
DataErrorKind::InvalidDataPoint => Self::InvalidDataPoint { context: None },
DataErrorKind::ScalingError => Self::ScalingError { context: None },
DataErrorKind::BufferFull => Self::BufferFull { context: None },
DataErrorKind::InsufficientData => Self::InsufficientData { context: None },
}
}
}
impl DataError {
pub const SERIES_NOT_FOUND: Self = Self::SeriesNotFound { context: None };
pub const INDEX_OUT_OF_BOUNDS: Self = Self::IndexOutOfBounds { context: None };
pub const INVALID_DATA_POINT: Self = Self::InvalidDataPoint { context: None };
pub const SCALING_ERROR: Self = Self::ScalingError { context: None };
pub const BUFFER_FULL: Self = Self::BufferFull { context: None };
pub const INSUFFICIENT_DATA: Self = Self::InsufficientData { context: None };
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataErrorKind {
SeriesNotFound,
IndexOutOfBounds,
InvalidDataPoint,
ScalingError,
BufferFull,
InsufficientData,
}
#[cfg(feature = "animations")]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AnimationError {
InvalidDuration,
AnimationNotFound,
SchedulerFull,
InterpolationError,
InvalidState,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayoutError {
InsufficientSpace,
InvalidConfiguration,
PositioningFailed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RenderError {
DrawingFailed,
TextRenderingFailed,
ClippingFailed,
ColorConversionFailed,
}
impl From<&str> for DataError {
fn from(_msg: &str) -> Self {
DataError::simple(DataErrorKind::InvalidDataPoint)
}
}
impl From<DataError> for ChartError {
fn from(error: DataError) -> Self {
ChartError::DataError(error)
}
}
#[cfg(feature = "animations")]
impl From<AnimationError> for ChartError {
fn from(error: AnimationError) -> Self {
ChartError::AnimationError(error)
}
}
impl From<LayoutError> for ChartError {
fn from(_error: LayoutError) -> Self {
ChartError::InvalidConfiguration
}
}
impl From<RenderError> for ChartError {
fn from(_error: RenderError) -> Self {
ChartError::RenderingError
}
}
pub type ChartResult<T> = Result<T, ChartError>;
pub type DataResult<T> = Result<T, DataError>;
#[cfg(feature = "animations")]
pub type AnimationResult<T> = Result<T, AnimationError>;
pub type LayoutResult<T> = Result<T, LayoutError>;
pub type RenderResult<T> = Result<T, RenderError>;
#[cfg(feature = "std")]
impl std::error::Error for ChartError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ChartError::DataError(err) => Some(err),
ChartError::RenderError(err) => Some(err),
ChartError::LayoutError(err) => Some(err),
#[cfg(feature = "animations")]
ChartError::AnimationError(err) => Some(err),
_ => None,
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DataError {}
#[cfg(feature = "animations")]
#[cfg(feature = "std")]
impl std::error::Error for AnimationError {}
#[cfg(feature = "std")]
impl std::error::Error for LayoutError {}
#[cfg(feature = "std")]
impl std::error::Error for RenderError {}
impl core::fmt::Display for ChartError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ChartError::InsufficientData => write!(f, "Insufficient data to render the chart"),
ChartError::InvalidRange => write!(f, "Invalid range specified for axis or data"),
ChartError::InvalidData => write!(f, "Invalid data provided"),
ChartError::MemoryFull => write!(f, "Memory allocation failed or buffer is full"),
ChartError::RenderingError => write!(f, "Error occurred during rendering"),
ChartError::InvalidConfiguration => write!(f, "Invalid configuration provided"),
ChartError::ConfigurationError => write!(f, "Configuration error occurred"),
ChartError::RenderError(err) => write!(f, "Render error: {err}"),
ChartError::LayoutError(err) => write!(f, "Layout error: {err}"),
ChartError::DataError(err) => write!(f, "Data error: {err}"),
#[cfg(feature = "animations")]
ChartError::AnimationError(err) => write!(f, "Animation error: {err}"),
}
}
}
impl core::fmt::Display for DataError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
DataError::SeriesNotFound { context } => {
write!(f, "Requested data series was not found")?;
if let Some(ctx) = context {
write!(f, " during {} (hint: {})", ctx.operation, ctx.hint)?;
}
Ok(())
}
DataError::IndexOutOfBounds { context } => {
write!(f, "Index is out of bounds for the data collection")?;
if let Some(ctx) = context {
write!(f, " during {} (hint: {})", ctx.operation, ctx.hint)?;
if let Some(value) = ctx.numeric_context {
write!(f, " [length: {value}]")?;
}
}
Ok(())
}
DataError::InvalidDataPoint { context } => {
write!(f, "Invalid data point provided")?;
if let Some(ctx) = context {
write!(f, " during {} (hint: {})", ctx.operation, ctx.hint)?;
}
Ok(())
}
DataError::ScalingError { context } => {
write!(f, "Error occurred during data scaling")?;
if let Some(ctx) = context {
write!(f, " during {} (hint: {})", ctx.operation, ctx.hint)?;
}
Ok(())
}
DataError::BufferFull { context } => {
write!(f, "Buffer capacity exceeded")?;
if let Some(ctx) = context {
write!(f, " during {} (hint: {})", ctx.operation, ctx.hint)?;
if let Some(capacity) = ctx.numeric_context {
write!(f, " [capacity: {capacity}]")?;
}
}
Ok(())
}
DataError::InsufficientData { context } => {
write!(f, "Insufficient data to perform operation")?;
if let Some(ctx) = context {
write!(f, " during {} (hint: {})", ctx.operation, ctx.hint)?;
if let Some(found) = ctx.numeric_context {
write!(f, " [found: {found}]")?;
}
}
Ok(())
}
}
}
}
#[cfg(feature = "animations")]
impl core::fmt::Display for AnimationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
AnimationError::InvalidDuration => write!(f, "Invalid duration specified"),
AnimationError::AnimationNotFound => {
write!(f, "Animation with specified ID was not found")
}
AnimationError::SchedulerFull => write!(f, "Animation scheduler is full"),
AnimationError::InterpolationError => write!(f, "Error occurred during interpolation"),
AnimationError::InvalidState => write!(f, "Animation state is invalid"),
}
}
}
impl core::fmt::Display for LayoutError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
LayoutError::InsufficientSpace => write!(f, "Insufficient space for layout"),
LayoutError::InvalidConfiguration => write!(f, "Invalid layout configuration"),
LayoutError::PositioningFailed => write!(f, "Component positioning failed"),
}
}
}
impl core::fmt::Display for RenderError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
RenderError::DrawingFailed => write!(f, "Drawing operation failed"),
RenderError::TextRenderingFailed => write!(f, "Text rendering failed"),
RenderError::ClippingFailed => write!(f, "Clipping operation failed"),
RenderError::ColorConversionFailed => write!(f, "Color conversion failed"),
}
}
}