epac-utils 0.1.0

Set of Utilities for Errors, and some cachers/timers/macros
Documentation
use std::fmt::{Debug, Formatter};

///Enum which can represent one of two values
///
///The Same as an `(Option<A>, Option<B>)` where one [`Option`] must always be [`Option::Some`] and the other must be [`Option::None`]
pub enum Either<L, R> {
    ///The First variant of [`Either`]
    Left(L),
    ///The second variant of [`Either`]
    Right(R),
}

impl<L, R> Either<L, R> {
    ///Constructor for [`Either::Left`] which uses [`Into::into`]
    pub fn l(a: impl Into<L>) -> Self {
        Self::Left(a.into())
    }

    ///Constructor for [`Either::Right`] which uses [`Into::into`]
    pub fn r(b: impl Into<R>) -> Self {
        Self::Right(b.into())
    }

    ///Utility function for checking which side it is. Here we check if it is the [`Either::Left`] variant
    pub fn is_left(&self) -> bool {
        matches!(self, Either::Left(_))
    }

    ///Utility function for checking which side it is. Here we check if it is the [`Either::Right`] variant
    pub fn is_right(&self) -> bool {
        matches!(self, Either::Right(_))
    }

    //region transformers
    ///Utility function for [`Either::Left`] Vs [`Either::Right`] if you need nice variable names
    pub fn to_unit(&self) -> Either<(), ()> {
        if self.is_left() {
            Either::Left(())
        } else {
            Either::Right(())
        }
    }

    ///Function to check if this is [`Either::Left`], and if so return [`Some`] of that, else [`None`]
    ///
    ///Returns an Owned `L`
    pub fn to_left(self) -> Option<L> {
        if let Either::Left(l) = self {
            Some(l)
        } else {
            None
        }
    }
    ///Function to check if this is [`Either::Left`], and if so return [`Some`] of that, else [`None`]
    ///
    ///Returns a reference to an `L`
    pub fn ref_left(&self) -> Option<&L> {
        if let Either::Left(l) = self {
            Some(l)
        } else {
            None
        }
    }
    ///Function to check if this is [`Either::Left`], and if so return [`Some`] of that, else [`None`]
    ///
    ///Returns a mutable reference to an `L`
    pub fn mut_ref_left(&mut self) -> Option<&mut L> {
        if let Either::Left(l) = self {
            Some(l)
        } else {
            None
        }
    }

    ///Function to check if this is [`Either::Right`], and if so return [`Some`] of that, else [`None`]
    ///
    ///Returns an Owned `L`
    pub fn to_right(self) -> Option<R> {
        if let Either::Right(r) = self {
            Some(r)
        } else {
            None
        }
    }
    ///Function to check if this is [`Either::Right`], and if so return [`Some`] of that, else [`None`]
    ///
    ///Returns a reference to an `L`
    pub fn ref_right(&self) -> Option<&R> {
        if let Either::Right(r) = self {
            Some(r)
        } else {
            None
        }
    }
    ///Function to check if this is [`Either::Right`], and if so return [`Some`] of that, else [`None`]
    ///
    ///Returns a mutable reference to an `L`
    pub fn mut_ref_right(&mut self) -> Option<&mut R> {
        if let Either::Right(r) = self {
            Some(r)
        } else {
            None
        }
    }

    //endregion
    //TODO: Work out more elegant way (maybe macros) to do above and below transformers
}

impl<L: Clone, R: Clone> Either<L, R> {
    ///Function to check if this is [`Either::Left`], and if so return [`Some`] of that, else [`None`]
    pub fn clone_left(&self) -> Option<L> {
        if let Either::Left(l) = self.clone() {
            Some(l)
        } else {
            None
        }
    }

    ///Function to check if this is [`Either::Right`], and if so return [`Some`] of that, else [`None`]
    pub fn clone_right(&self) -> Option<R> {
        if let Either::Right(r) = self.clone() {
            Some(r)
        } else {
            None
        }
    }
}

impl<T> Either<T, T> {
    ///If `L` == `R` then this function will return an `L` - useful for when the [`Either`] side signifies something, but always returns the same type.
    #[allow(clippy::missing_const_for_fn)] //Cannot be const as destructors cannot be const - Github error 8874
    pub fn one_type(self) -> T {
        match self {
            Self::Left(l) => l,
            Self::Right(r) => r,
        }
    }
}

impl<L: Debug, R: Debug> Debug for Either<L, R> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Left(arg0) => f.debug_tuple("Left").field(arg0).finish(),
            Self::Right(arg0) => f.debug_tuple("Right").field(arg0).finish(),
        }
    }
}

impl<L: Clone, R: Clone> Clone for Either<L, R> {
    fn clone(&self) -> Self {
        match self {
            Self::Left(l) => Self::Left(l.clone()),
            Self::Right(r) => Self::Right(r.clone()),
        }
    }
}