use self::and_then::AndThen;
use crate::util::{map::Map, move_map::MoveMap};
use either::Either;
use string_cache::{Atom, StaticAtomSet};
pub mod and_then;
pub trait Fold<T> {
fn fold(&mut self, node: T) -> T;
fn then<F>(self, folder: F) -> AndThen<Self, F>
where
Self: Sized,
F: Fold<T>,
{
AndThen {
first: self,
second: folder,
}
}
}
pub trait Visit<T> {
fn visit(&mut self, node: &T);
fn then<F>(self, visitor: F) -> AndThen<Self, F>
where
Self: Sized,
F: Visit<T>,
{
AndThen {
first: self,
second: visitor,
}
}
}
impl<T, F: ?Sized> Fold<T> for Box<F>
where
T: FoldWith<Self>,
F: Fold<T>,
{
fn fold(&mut self, node: T) -> T {
(**self).fold(node)
}
}
impl<T, F: ?Sized> Visit<T> for Box<F>
where
T: VisitWith<Self>,
F: Visit<T>,
{
fn visit(&mut self, node: &T) {
(**self).visit(node)
}
}
impl<'a, T, F: ?Sized> Fold<T> for &'a mut F
where
T: FoldWith<Self>,
F: Fold<T>,
{
fn fold(&mut self, node: T) -> T {
(**self).fold(node)
}
}
impl<'a, T, F: ?Sized> Visit<T> for &'a mut F
where
T: VisitWith<Self>,
F: Visit<T>,
{
fn visit(&mut self, node: &T) {
(**self).visit(node)
}
}
impl<T, F> Fold<T> for F
where
T: FoldWith<F>,
{
default fn fold(&mut self, t: T) -> T {
t.fold_children(self)
}
}
impl<T, F> Visit<T> for F
where
T: VisitWith<F>,
{
default fn visit(&mut self, t: &T) {
t.visit_children(self)
}
}
pub trait FoldWith<F>: Sized {
fn fold_children(self, f: &mut F) -> Self;
fn fold_with(self, f: &mut F) -> Self
where
F: Fold<Self>,
{
f.fold(self)
}
}
pub trait VisitWith<F> {
fn visit_children(&self, f: &mut F);
fn visit_with(&self, f: &mut F)
where
Self: Sized,
{
f.visit(self)
}
}
impl<'a, T, F> VisitWith<F> for &'a T
where
F: Visit<T>,
{
fn visit_children(&self, f: &mut F) {
f.visit(*self)
}
}
impl<T, F> FoldWith<F> for Box<T>
where
F: Fold<T>,
{
fn fold_children(self, f: &mut F) -> Self {
self.map(|node| f.fold(node))
}
}
impl<T, F> VisitWith<F> for Box<T>
where
F: Visit<T>,
{
fn visit_children(&self, f: &mut F) {
f.visit(&**self)
}
}
impl<T, F> FoldWith<F> for Vec<T>
where
F: Fold<T>,
{
fn fold_children(self, f: &mut F) -> Self {
self.move_map(|it| f.fold(it))
}
}
impl<T, F> VisitWith<F> for Vec<T>
where
F: Visit<T>,
{
fn visit_children(&self, f: &mut F) {
self.iter().for_each(|node| f.visit(node))
}
}
impl<T, F> VisitWith<F> for [T]
where
F: Visit<T>,
{
fn visit_children(&self, f: &mut F) {
self.iter().for_each(|node| f.visit(node))
}
}
impl<T, F> FoldWith<F> for Option<T>
where
F: Fold<T>,
{
fn fold_children(self, f: &mut F) -> Self {
self.map(|t| f.fold(t))
}
}
impl<T, F> VisitWith<F> for Option<T>
where
F: Visit<T>,
{
fn visit_children(&self, f: &mut F) {
if let Some(ref node) = *self {
f.visit(node)
}
}
}
impl<F> FoldWith<F> for String {
fn fold_children(self, _: &mut F) -> Self {
self
}
}
impl<F> VisitWith<F> for String {
fn visit_children(&self, _: &mut F) {}
}
impl<F, S: StaticAtomSet> FoldWith<F> for Atom<S> {
fn fold_children(self, _: &mut F) -> Self {
self
}
}
impl<F, S: StaticAtomSet> VisitWith<F> for Atom<S> {
fn visit_children(&self, _: &mut F) {}
}
impl<A, B, F> FoldWith<F> for Either<A, B>
where
F: Fold<A> + Fold<B>,
{
fn fold_children(self, f: &mut F) -> Self {
match self {
Either::Left(a) => Either::Left(Fold::<A>::fold(f, a)),
Either::Right(b) => Either::Right(Fold::<B>::fold(f, b)),
}
}
}
impl<A, B, F> VisitWith<F> for Either<A, B>
where
F: Visit<A> + Visit<B>,
{
fn visit_children(&self, f: &mut F) {
match *self {
Either::Left(ref a) => f.visit(a),
Either::Right(ref b) => f.visit(b),
}
}
}