use core::{fmt, marker::PhantomData};
use crate::{
Covar, CovariantFallibleLending, DoubleEndedFallibleLender, ExactSizeFallibleLender,
FallibleLend, FallibleLender, FallibleLending, FusedFallibleLender, higher_order::FnOnceHKA,
};
#[inline]
pub fn once_with<St, E, F>(state: St, f: Covar<F>) -> OnceWith<St, E, F>
where
F: for<'all> FnOnceHKA<'all, &'all mut St>,
{
OnceWith {
state,
f: Some(f),
_marker: PhantomData,
}
}
#[inline]
pub fn once_with_err<St, L, F>(state: St, f: F) -> OnceWithErr<St, L, F>
where
L: ?Sized + CovariantFallibleLending,
{
OnceWithErr {
state,
f: Some(f),
_marker: PhantomData,
}
}
#[must_use = "lenders are lazy and do nothing unless consumed"]
pub struct OnceWith<St, E, F> {
state: St,
f: Option<Covar<F>>,
_marker: PhantomData<fn() -> E>,
}
impl<St: Clone, E, F: Clone> Clone for OnceWith<St, E, F> {
#[inline]
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
f: self.f.clone(),
_marker: PhantomData,
}
}
}
impl<St: fmt::Debug, E, F> fmt::Debug for OnceWith<St, E, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FallibleOnceWith")
.field("state", &self.state)
.finish_non_exhaustive()
}
}
impl<'lend, St, E, F> FallibleLending<'lend> for OnceWith<St, E, F>
where
F: for<'all> FnOnceHKA<'all, &'all mut St>,
{
type Lend = <F as FnOnceHKA<'lend, &'lend mut St>>::B;
}
impl<St, E, F> FallibleLender for OnceWith<St, E, F>
where
F: for<'all> FnOnceHKA<'all, &'all mut St>,
{
type Error = E;
crate::unsafe_assume_covariance_fallible!();
#[inline]
fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
Ok(self.f.take().map(|f| f.into_inner()(&mut self.state)))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.f.is_some() {
(1, Some(1))
} else {
(0, Some(0))
}
}
}
impl<St, E, F> DoubleEndedFallibleLender for OnceWith<St, E, F>
where
F: for<'all> FnOnceHKA<'all, &'all mut St>,
{
#[inline(always)]
fn next_back(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
self.next()
}
}
impl<St, E, F> ExactSizeFallibleLender for OnceWith<St, E, F> where
F: for<'all> FnOnceHKA<'all, &'all mut St>
{
}
impl<St, E, F> FusedFallibleLender for OnceWith<St, E, F> where
F: for<'all> FnOnceHKA<'all, &'all mut St>
{
}
#[must_use = "lenders are lazy and do nothing unless consumed"]
pub struct OnceWithErr<St, L: ?Sized, F> {
state: St,
f: Option<F>,
_marker: PhantomData<fn() -> L>,
}
impl<St: Clone, L: ?Sized, F: Clone> Clone for OnceWithErr<St, L, F> {
#[inline]
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
f: self.f.clone(),
_marker: PhantomData,
}
}
}
impl<St: fmt::Debug, L: ?Sized, F> fmt::Debug for OnceWithErr<St, L, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FallibleOnceWithErr")
.field("state", &self.state)
.finish_non_exhaustive()
}
}
impl<'lend, St, L, E, F> FallibleLending<'lend> for OnceWithErr<St, L, F>
where
L: ?Sized + CovariantFallibleLending,
F: FnOnce(&mut St) -> E,
{
type Lend = FallibleLend<'lend, L>;
}
impl<St, L, E, F> FallibleLender for OnceWithErr<St, L, F>
where
L: ?Sized + CovariantFallibleLending,
F: FnOnce(&mut St) -> E,
{
type Error = E;
crate::unsafe_assume_covariance_fallible!();
#[inline]
fn next(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
match self.f.take() {
Some(f) => Err(f(&mut self.state)),
None => Ok(None),
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(0))
}
}
impl<St, L, E, F> DoubleEndedFallibleLender for OnceWithErr<St, L, F>
where
L: ?Sized + CovariantFallibleLending,
F: FnOnce(&mut St) -> E,
{
#[inline(always)]
fn next_back(&mut self) -> Result<Option<FallibleLend<'_, Self>>, Self::Error> {
self.next()
}
}
impl<St, L, E, F> FusedFallibleLender for OnceWithErr<St, L, F>
where
L: ?Sized + CovariantFallibleLending,
F: FnOnce(&mut St) -> E,
{
}
impl<St, L, E, F> ExactSizeFallibleLender for OnceWithErr<St, L, F>
where
L: ?Sized + CovariantFallibleLending,
F: FnOnce(&mut St) -> E,
{
}