breadx 3.1.0

Pure-Rust X11 connection implementation with a focus on adaptability
Documentation
//               Copyright John Nunley, 2022.
// Distributed under the Boost Software License, Version 1.0.
//       (See accompanying file LICENSE or copy at
//         https://www.boost.org/LICENSE_1_0.txt)

use crate::{Error, Result};

/// A wrapper around a type that may be able to be poisoned if it runs
/// an operation that may put it into an invalid state.
pub(crate) struct Poisonable<T> {
    inner: Option<T>,
}

impl<T> Poisonable<T> {
    /// Run a poison-aware operation on the inner value.
    pub(crate) fn with<R>(&mut self, f: impl FnOnce(&mut T) -> Result<R>) -> Result<R> {
        let inner = match self.inner {
            Some(ref mut inner) => inner,
            None => return Err(Error::make_poisoned::<T>()),
        };

        match f(inner) {
            Err(err) if err.invalid_state() => {
                // we've been put into an invalid state, so poison ourselves
                self.inner = None;
                Err(err)
            }
            other_result => other_result,
        }
    }

    /// Sometimes we just want a ref.
    #[cfg(feature = "std")]
    pub(crate) fn with_ref<R>(&self, f: impl FnOnce(&T) -> Result<R>) -> Result<R> {
        let inner = match self.inner {
            Some(ref inner) => inner,
            None => return Err(Error::make_poisoned::<T>()),
        };

        f(inner)
    }
}

impl<T> From<T> for Poisonable<T> {
    fn from(inner: T) -> Self {
        Self { inner: Some(inner) }
    }
}