#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
use std::marker;
use std::mem;
#[derive(Debug, Copy, Clone)]
pub struct ImplFolder<Output, Item> {
output: Output,
item: marker::PhantomData<Item>,
}
pub trait FolderTrait<Output, Item> {
fn fold(output: Output, item: Item) -> Output;
}
impl<Output, Item> ImplFolder<Output, Item> {
pub fn new(initial: Output) -> Self {
Self {
output: initial,
item: marker::PhantomData,
}
}
pub fn into_inner(self) -> Output {
self.output
}
pub fn fold(&mut self, item: Item)
where
Self: FolderTrait<Output, Item>,
{
#[allow(clippy::uninit_assumed_init)]
let uninit = unsafe { mem::MaybeUninit::<Output>::uninit().assume_init() };
let current_output = mem::replace(&mut self.output, uninit);
let new_output = <Self as FolderTrait<Output, Item>>::fold(current_output, item);
let uninit = mem::replace(&mut self.output, new_output);
mem::forget(uninit);
}
}
impl<Output, Item> From<Output> for ImplFolder<Output, Item> {
fn from(output: Output) -> Self {
Self::new(output)
}
}
impl<Output, Item> AsRef<Output> for ImplFolder<Output, Item> {
fn as_ref(&self) -> &Output {
&self.output
}
}
impl<Output, Item> Extend<Item> for ImplFolder<Output, Item>
where
ImplFolder<Output, Item>: FolderTrait<Output, Item>,
{
fn extend<It: IntoIterator<Item = Item>>(&mut self, iter: It) {
iter.into_iter().for_each(|i| self.fold(i));
}
}
impl<Output, Item> Default for ImplFolder<Output, Item>
where
Output: Default,
{
fn default() -> Self {
Self::new(Default::default())
}
}
impl<Output, Item> std::iter::FromIterator<Item> for ImplFolder<Output, Item>
where
Output: Default,
ImplFolder<Output, Item>: FolderTrait<Output, Item>,
{
fn from_iter<It: IntoIterator<Item = Item>>(iter: It) -> Self {
let mut autofolder = ImplFolder::<Output, Item>::default();
autofolder.extend(iter);
autofolder
}
}
#[macro_export]
macro_rules! autofolder_impl_foldertrait{
(|$a:ident : $output_type: ty, $i:ident : $item_type: ty| $body: block) => {
impl FolderTrait<$output_type, $item_type> for ImplFolder<$output_type, $item_type> {
fn fold(mut $a: $output_type, $i: $item_type) -> $output_type $body
}
}
}