use std::error::Error;
use std::fmt;
use thiserror::Error;
use super::{Context, ContextBindingError, SuspendedContext};
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
#[non_exhaustive]
pub enum ContextSuspensionReason {
#[error("a Context binding scope is active")]
BindingScopeActive,
#[error("the Context is not the current Context")]
NotCurrent,
#[error("a Dear ImGui frame is still open")]
FrameOpen,
}
#[derive(Debug, Error)]
#[error("failed to suspend Context: {reason}")]
pub struct ContextSuspensionError {
owner: Context,
reason: ContextSuspensionReason,
}
impl ContextSuspensionError {
pub(super) fn new(owner: Context, reason: ContextSuspensionReason) -> Self {
Self { owner, reason }
}
pub fn reason(&self) -> ContextSuspensionReason {
self.reason
}
pub fn owner(&self) -> &Context {
&self.owner
}
pub fn owner_mut(&mut self) -> &mut Context {
&mut self.owner
}
pub fn into_owner(self) -> Context {
self.owner
}
pub fn into_parts(self) -> (Context, ContextSuspensionReason) {
(self.owner, self.reason)
}
}
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
#[non_exhaustive]
pub enum ContextActivationReason {
#[error("another Context is already active")]
ContextAlreadyActive,
#[error("a Context binding scope is active")]
BindingScopeActive,
}
#[derive(Debug, Error)]
#[error("failed to activate suspended Context: {reason}")]
pub struct ContextActivationError {
owner: SuspendedContext,
reason: ContextActivationReason,
}
impl ContextActivationError {
pub(super) fn new(owner: SuspendedContext, reason: ContextActivationReason) -> Self {
Self { owner, reason }
}
pub fn reason(&self) -> ContextActivationReason {
self.reason
}
pub fn owner(&self) -> &SuspendedContext {
&self.owner
}
pub fn owner_mut(&mut self) -> &mut SuspendedContext {
&mut self.owner
}
pub fn into_owner(self) -> SuspendedContext {
self.owner
}
pub fn into_parts(self) -> (SuspendedContext, ContextActivationReason) {
(self.owner, self.reason)
}
}
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
#[non_exhaustive]
pub enum ContextScopeError {
#[error("failed to activate suspended Context: {0}")]
Activation(#[source] ContextActivationReason),
#[error("active Context closure returned success with an open frame")]
FrameLeftOpen,
#[error("suspended Context became unavailable: {0}")]
ContextUnavailable(#[source] ContextBindingError),
}
impl ContextScopeError {
pub fn activation_reason(self) -> Option<ContextActivationReason> {
match self {
Self::Activation(reason) => Some(reason),
_ => None,
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ScopedActivationError<E> {
Scope(ContextScopeError),
Closure(E),
}
impl<E> From<ContextScopeError> for ScopedActivationError<E> {
fn from(error: ContextScopeError) -> Self {
Self::Scope(error)
}
}
impl<E> ScopedActivationError<E> {
pub fn map_closure<F>(self, f: impl FnOnce(E) -> F) -> ScopedActivationError<F> {
match self {
Self::Scope(error) => ScopedActivationError::Scope(error),
Self::Closure(error) => ScopedActivationError::Closure(f(error)),
}
}
pub fn scope_error(&self) -> Option<ContextScopeError> {
match self {
Self::Scope(error) => Some(*error),
_ => None,
}
}
pub fn activation_reason(&self) -> Option<ContextActivationReason> {
self.scope_error()
.and_then(ContextScopeError::activation_reason)
}
pub fn closure_error(&self) -> Option<&E> {
match self {
Self::Closure(error) => Some(error),
_ => None,
}
}
pub fn into_closure_error(self) -> Result<E, ContextScopeError> {
match self {
Self::Closure(error) => Ok(error),
Self::Scope(error) => Err(error),
}
}
}
impl<E: fmt::Display> fmt::Display for ScopedActivationError<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Scope(error) => error.fmt(f),
Self::Closure(error) => write!(f, "active Context closure failed: {error}"),
}
}
}
impl<E> Error for ScopedActivationError<E>
where
E: Error + 'static,
{
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Scope(error) => Some(error),
Self::Closure(error) => Some(error),
}
}
}