#[cfg(test)]
mod tests;
use ::std::cell::OnceCell;
use ::std::convert::Infallible;
use ::std::fmt::Debug;
use ::std::hash::Hash;
use ::std::ptr;
#[cfg(feature = "itertools")]
pub use ::itertools::EitherOrBoth;
#[cfg(not(feature = "itertools"))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum EitherOrBoth<L, R> {
Both(L, R),
Left(L),
Right(R),
}
#[derive(Clone)]
pub struct Pair<L, R, C = StdConverter> {
inner: PairInner<L, R>,
converter: C,
}
impl<L, R, C> Pair<L, R, C> {
pub fn from_left(left: L) -> Self
where
C: Default,
{
Self {
inner: PairInner::from_left(left),
converter: C::default(),
}
}
pub fn from_right(right: R) -> Self
where
C: Default,
{
Self {
inner: PairInner::from_right(right),
converter: C::default(),
}
}
pub fn from_left_conv(left: L, converter: C) -> Self {
Self {
inner: PairInner::from_left(left),
converter,
}
}
pub fn from_right_conv(right: R, converter: C) -> Self {
Self {
inner: PairInner::from_right(right),
converter,
}
}
pub fn left_opt(&self) -> Option<&L> {
self.inner.left_opt()
}
pub fn right_opt(&self) -> Option<&R> {
self.inner.right_opt()
}
pub fn left_opt_mut(&mut self) -> Option<&mut L> {
self.inner.left_opt_mut()
}
pub fn right_opt_mut(&mut self) -> Option<&mut R> {
self.inner.right_opt_mut()
}
pub unsafe fn left_with<F: FnOnce(&R) -> L>(&self, f: F) -> &L {
self.try_left_with(|r| Ok::<L, Infallible>(f(r))).into_ok2()
}
pub unsafe fn right_with<F: FnOnce(&L) -> R>(&self, f: F) -> &R {
self.try_right_with(|l| Ok::<R, Infallible>(f(l)))
.into_ok2()
}
pub unsafe fn try_left_with<F: FnOnce(&R) -> Result<L, E>, E>(&self, f: F) -> Result<&L, E> {
self.inner.try_left_with(f)
}
pub unsafe fn try_right_with<F: FnOnce(&L) -> Result<R, E>, E>(&self, f: F) -> Result<&R, E> {
self.inner.try_right_with(f)
}
pub unsafe fn left_mut_with<F: FnOnce(&R) -> L>(&mut self, f: F) -> &mut L {
self.try_left_mut_with(|r| Ok::<L, Infallible>(f(r)))
.into_ok2()
}
pub unsafe fn right_mut_with<F: FnOnce(&L) -> R>(&mut self, f: F) -> &mut R {
self.try_right_mut_with(|l| Ok::<R, Infallible>(f(l)))
.into_ok2()
}
pub unsafe fn try_left_mut_with<F: FnOnce(&R) -> Result<L, E>, E>(
&mut self,
f: F,
) -> Result<&mut L, E> {
self.inner.try_left_mut_with(f)
}
pub unsafe fn try_right_mut_with<F: FnOnce(&L) -> Result<R, E>, E>(
&mut self,
f: F,
) -> Result<&mut R, E> {
self.inner.try_right_mut_with(f)
}
pub unsafe fn into_left_with<F: FnOnce(R) -> L>(self, f: F) -> L {
self.try_into_left_with(|r| Ok::<L, Infallible>(f(r)))
.into_ok2()
}
pub unsafe fn into_right_with<F: FnOnce(L) -> R>(self, f: F) -> R {
self.try_into_right_with(|l| Ok::<R, Infallible>(f(l)))
.into_ok2()
}
pub unsafe fn try_into_left_with<F: FnOnce(R) -> Result<L, E>, E>(self, f: F) -> Result<L, E> {
self.inner.try_into_left_with(f)
}
pub unsafe fn try_into_right_with<F: FnOnce(L) -> Result<R, E>, E>(self, f: F) -> Result<R, E> {
self.inner.try_into_right_with(f)
}
pub fn as_ref(&self) -> EitherOrBoth<&L, &R> {
match &self.inner {
PairInner::GivenLeft { left, right_cell } => match right_cell.get() {
Some(right) => EitherOrBoth::Both(left, right),
None => EitherOrBoth::Left(left),
},
PairInner::GivenRight { right, left_cell } => match left_cell.get() {
Some(left) => EitherOrBoth::Both(left, right),
None => EitherOrBoth::Right(right),
},
}
}
pub unsafe fn extract_left_with<F: FnOnce(&L) -> R>(&mut self, f: F) -> Option<L> {
self.try_extract_left_with(|l| Ok::<R, Infallible>(f(l)))
.into_ok2()
}
pub unsafe fn extract_right_with<F: FnOnce(&R) -> L>(&mut self, f: F) -> Option<R> {
self.try_extract_right_with(|r| Ok::<L, Infallible>(f(r)))
.into_ok2()
}
pub unsafe fn try_extract_left_with<F: FnOnce(&L) -> Result<R, E>, E>(
&mut self,
f: F,
) -> Result<Option<L>, E> {
self.inner.try_extract_left_with(f)
}
pub unsafe fn try_extract_right_with<F: FnOnce(&R) -> Result<L, E>, E>(
&mut self,
f: F,
) -> Result<Option<R>, E> {
self.inner.try_extract_right_with(f)
}
pub fn converter(&self) -> &C {
&self.converter
}
pub fn converter_mut(&mut self) -> &mut C {
&mut self.converter
}
}
impl<L, R, C> Pair<L, R, C>
where
C: Converter<L, R>,
{
pub fn try_left(&self) -> Result<&L, C::ToLeftError> {
self.inner
.try_left_with(|r| self.converter.convert_to_left(r))
}
pub fn try_right(&self) -> Result<&R, C::ToRightError> {
self.inner
.try_right_with(|l| self.converter.convert_to_right(l))
}
pub fn try_left_mut(&mut self) -> Result<&mut L, C::ToLeftError> {
self.inner
.try_left_mut_with(|r| Ok(self.converter.convert_to_left(r)?))
}
pub fn try_right_mut(&mut self) -> Result<&mut R, C::ToRightError> {
self.inner
.try_right_mut_with(|l| Ok(self.converter.convert_to_right(l)?))
}
pub fn try_into_left(self) -> Result<L, C::ToLeftError> {
let converter = &self.converter;
self.inner
.try_into_left_with(|r| Ok(converter.convert_to_left(&r)?))
}
pub fn try_into_right(self) -> Result<R, C::ToRightError> {
let converter = &self.converter;
self.inner
.try_into_right_with(|l| Ok(converter.convert_to_right(&l)?))
}
pub fn try_extract_left(&mut self) -> Result<Option<L>, C::ToRightError> {
self.inner
.try_extract_left_with(|l| Ok(self.converter.convert_to_right(l)?))
}
pub fn try_extract_right(&mut self) -> Result<Option<R>, C::ToLeftError> {
self.inner
.try_extract_right_with(|r| Ok(self.converter.convert_to_left(r)?))
}
}
impl<L, R, C> Pair<L, R, C>
where
C: Converter<L, R, ToLeftError = Infallible>,
{
pub fn left(&self) -> &L {
self.try_left().into_ok2()
}
pub fn left_mut(&mut self) -> &mut L {
self.try_left_mut().into_ok2()
}
pub fn into_left(self) -> L {
self.try_into_left().into_ok2()
}
pub fn extract_right(&mut self) -> Option<R> {
self.try_extract_right().into_ok2()
}
}
impl<L, R, C> Pair<L, R, C>
where
C: Converter<L, R, ToRightError = Infallible>,
{
pub fn right(&self) -> &R {
self.try_right().into_ok2()
}
pub fn right_mut(&mut self) -> &mut R {
self.try_right_mut().into_ok2()
}
pub fn into_right(self) -> R {
self.try_into_right().into_ok2()
}
pub fn extract_left(&mut self) -> Option<L> {
self.try_extract_left().into_ok2()
}
}
#[derive(Clone)]
enum PairInner<L, R> {
#[doc(hidden)]
GivenLeft { left: L, right_cell: OnceCell<R> },
#[doc(hidden)]
GivenRight { left_cell: OnceCell<L>, right: R },
}
impl<L, R> PairInner<L, R> {
fn from_left(left: L) -> Self {
Self::GivenLeft {
left,
right_cell: OnceCell::new(),
}
}
fn from_right(right: R) -> Self {
Self::GivenRight {
left_cell: OnceCell::new(),
right,
}
}
fn left_opt(&self) -> Option<&L> {
match self {
PairInner::GivenLeft { left, .. } => Some(left),
PairInner::GivenRight { left_cell, .. } => left_cell.get(),
}
}
fn right_opt(&self) -> Option<&R> {
match self {
PairInner::GivenLeft { right_cell, .. } => right_cell.get(),
PairInner::GivenRight { right, .. } => Some(right),
}
}
fn left_opt_mut(&mut self) -> Option<&mut L> {
match self {
PairInner::GivenLeft { left, right_cell } => {
let _ = right_cell.take();
Some(left)
}
PairInner::GivenRight { left_cell, .. } => {
let left = left_cell.take()?;
*self = Self::from_left(left);
if let PairInner::GivenLeft { left, .. } = self {
Some(left)
} else {
unreachable!()
}
}
}
}
fn right_opt_mut(&mut self) -> Option<&mut R> {
match self {
PairInner::GivenLeft { right_cell, .. } => {
let right = right_cell.take()?;
*self = Self::from_right(right);
if let PairInner::GivenRight { right, .. } = self {
Some(right)
} else {
unreachable!()
}
}
PairInner::GivenRight { right, left_cell } => {
let _ = left_cell.take();
Some(right)
}
}
}
fn try_left_with<F: FnOnce(&R) -> Result<L, E>, E>(&self, f: F) -> Result<&L, E> {
match self {
PairInner::GivenLeft { left, .. } => Ok(left),
PairInner::GivenRight { left_cell, right } => left_cell.get_or_try_init2(|| f(right)),
}
}
fn try_right_with<F: FnOnce(&L) -> Result<R, E>, E>(&self, f: F) -> Result<&R, E> {
match self {
PairInner::GivenLeft { left, right_cell } => right_cell.get_or_try_init2(|| f(left)),
PairInner::GivenRight { right, .. } => Ok(right),
}
}
fn try_left_mut_with<F: FnOnce(&R) -> Result<L, E>, E>(&mut self, f: F) -> Result<&mut L, E> {
match self {
PairInner::GivenLeft { left, right_cell } => {
let _ = right_cell.take();
Ok(left)
}
PairInner::GivenRight { left_cell, right } => {
let left = left_cell.take().map(Ok).unwrap_or_else(|| f(right))?;
*self = Self::from_left(left);
if let PairInner::GivenLeft { left, .. } = self {
Ok(left)
} else {
unreachable!()
}
}
}
}
fn try_right_mut_with<F: FnOnce(&L) -> Result<R, E>, E>(&mut self, f: F) -> Result<&mut R, E> {
match self {
PairInner::GivenLeft { left, right_cell } => {
let right = right_cell.take().map(Ok).unwrap_or_else(|| f(left))?;
*self = Self::from_right(right);
if let PairInner::GivenRight { right, .. } = self {
Ok(right)
} else {
unreachable!()
}
}
PairInner::GivenRight { right, left_cell } => {
let _ = left_cell.take();
Ok(right)
}
}
}
fn try_extract_left_with<F: FnOnce(&L) -> Result<R, E>, E>(
&mut self,
f: F,
) -> Result<Option<L>, E> {
match self {
PairInner::GivenLeft { left, right_cell } => {
let right = right_cell.take().map(Ok).unwrap_or_else(|| f(left))?;
let _ = unsafe { ptr::read(right_cell) };
let old_left = unsafe { ptr::read(left) };
unsafe {
ptr::write(self, Self::from_right(right));
}
Ok(Some(old_left))
}
PairInner::GivenRight { left_cell, .. } => Ok(left_cell.take()),
}
}
fn try_extract_right_with<F: FnOnce(&R) -> Result<L, E>, E>(
&mut self,
f: F,
) -> Result<Option<R>, E> {
match self {
PairInner::GivenRight { right, left_cell } => {
let left = left_cell.take().map(Ok).unwrap_or_else(|| f(right))?;
let _ = unsafe { ptr::read(left_cell) };
let old_right = unsafe { ptr::read(right) };
unsafe {
ptr::write(self, Self::from_left(left));
}
Ok(Some(old_right))
}
PairInner::GivenLeft { right_cell, .. } => Ok(right_cell.take()),
}
}
fn try_into_left_with<F: FnOnce(R) -> Result<L, E>, E>(self, f: F) -> Result<L, E> {
match self {
PairInner::GivenLeft { left, .. } => Ok(left),
PairInner::GivenRight {
right,
mut left_cell,
} => left_cell.take().map_or_else(|| f(right), Ok),
}
}
fn try_into_right_with<F: FnOnce(L) -> Result<R, E>, E>(self, f: F) -> Result<R, E> {
match self {
PairInner::GivenRight { right, .. } => Ok(right),
PairInner::GivenLeft {
left,
mut right_cell,
} => right_cell.take().map_or_else(|| f(left), Ok),
}
}
}
impl<L: Debug, R: Debug, C> Debug for Pair<L, R, C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Pair")
.field(&self.left_opt())
.field(&self.right_opt())
.finish()
}
}
impl<L: PartialEq, R: PartialEq, C> PartialEq for Pair<L, R, C> {
fn eq(&self, other: &Self) -> bool {
(self.left_opt(), self.right_opt()) == (other.left_opt(), other.right_opt())
}
}
impl<L: Hash, R: Hash, C> Hash for Pair<L, R, C> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.left_opt().hash(state);
self.right_opt().hash(state);
}
}
impl<L, R, C> From<Pair<L, R, C>> for EitherOrBoth<L, R> {
fn from(pair: Pair<L, R, C>) -> Self {
let (left, right) = match pair.inner {
PairInner::GivenLeft {
left,
mut right_cell,
} => (Some(left), right_cell.take()),
PairInner::GivenRight {
mut left_cell,
right,
} => (left_cell.take(), Some(right)),
};
match (left, right) {
(Some(left), Some(right)) => EitherOrBoth::Both(left, right),
(Some(left), None) => EitherOrBoth::Left(left),
(None, Some(right)) => EitherOrBoth::Right(right),
(None, None) => unreachable!(),
}
}
}
pub trait Converter<L, R> {
type ToLeftError;
type ToRightError;
fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError>;
fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError>;
}
#[derive(Default, Debug, Clone)]
pub struct StdConverter;
impl<L, R, EL, ER> Converter<L, R> for StdConverter
where
for<'a> &'a L: TryInto<R, Error = ER>,
for<'a> &'a R: TryInto<L, Error = EL>,
{
type ToLeftError = EL;
type ToRightError = ER;
fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError> {
right.try_into()
}
fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError> {
left.try_into()
}
}
#[derive(Clone)]
pub struct FnConverter<F, G> {
to_left: F,
to_right: G,
}
impl<F, G> Debug for FnConverter<F, G> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FnConverter")
.field("to_left", &"<function>")
.field("to_right", &"<function>")
.finish()
}
}
pub fn fn_converter<F, G>(f: F, g: G) -> FnConverter<F, G> {
FnConverter {
to_left: f,
to_right: g,
}
}
impl<L, R, F, G, EL, ER> Converter<L, R> for FnConverter<F, G>
where
for<'a> F: Fn(&'a R) -> Result<L, EL>,
for<'a> G: Fn(&'a L) -> Result<R, ER>,
{
type ToLeftError = EL;
type ToRightError = ER;
fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError> {
(self.to_left)(right)
}
fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError> {
(self.to_right)(left)
}
}
pub struct BoxedFnConverter<L, R, EL = Infallible, ER = Infallible> {
to_left: Box<dyn for<'a> Fn(&'a R) -> Result<L, EL>>,
to_right: Box<dyn for<'a> Fn(&'a L) -> Result<R, ER>>,
}
impl<L, R, EL, ER> Debug for BoxedFnConverter<L, R, EL, ER> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BoxedFnConverter")
.field("to_left", &"<boxed function>")
.field("to_right", &"<boxed function>")
.finish()
}
}
pub fn boxed_fn_converter<L, R, F, G, EL, ER>(f: F, g: G) -> BoxedFnConverter<L, R, EL, ER>
where
for<'a> F: Fn(&'a R) -> Result<L, EL> + 'static,
for<'a> G: Fn(&'a L) -> Result<R, ER> + 'static,
{
BoxedFnConverter {
to_left: Box::new(f),
to_right: Box::new(g),
}
}
impl<L, R, EL, ER> Converter<L, R> for BoxedFnConverter<L, R, EL, ER> {
type ToLeftError = EL;
type ToRightError = ER;
fn convert_to_left(&self, right: &R) -> Result<L, Self::ToLeftError> {
(self.to_left)(right)
}
fn convert_to_right(&self, left: &L) -> Result<R, Self::ToRightError> {
(self.to_right)(left)
}
}
trait OnceCellExt<T> {
fn get_or_try_init2<E, F>(&self, init: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>;
}
impl<T> OnceCellExt<T> for OnceCell<T> {
fn get_or_try_init2<E, F>(&self, init: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
{
match self.get() {
Some(v) => Ok(v),
None => {
let v = init()?;
let _ = self.set(v); Ok(unsafe { self.get().unwrap_unchecked() })
}
}
}
}
trait ResultExt<T, E> {
fn into_ok2(self) -> T
where
E: Into<Infallible>;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
#[allow(unreachable_code)]
fn into_ok2(self) -> T
where
E: Into<Infallible>,
{
match self {
Ok(v) => v,
Err(e) => match e.into() {},
}
}
}