#![warn(clippy::all)]
#![warn(clippy::pedantic)]
pub use derive_visitor_macros::Drive;
pub use derive_visitor_macros::DriveMut;
pub use derive_visitor_macros::Visitor;
pub use derive_visitor_macros::VisitorMut;
use std::{any::Any, cell::Cell, marker::PhantomData};
#[cfg(feature = "std-types-drive")]
use std::ops::{Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
use std::sync::{Arc, Mutex, RwLock};
pub trait Visitor {
fn visit(&mut self, item: &dyn Any, event: Event);
}
pub trait VisitorMut {
fn visit(&mut self, item: &mut dyn Any, event: Event);
}
pub fn visitor_fn<T, F: FnMut(&T, Event)>(fun: F) -> FnVisitor<T, F> {
FnVisitor {
marker: PhantomData,
fun,
}
}
pub fn visitor_fn_mut<T, F: FnMut(&mut T, Event)>(fun: F) -> FnVisitor<T, F> {
FnVisitor {
marker: PhantomData,
fun,
}
}
pub fn visitor_enter_fn<T, F: FnMut(&T)>(mut fun: F) -> FnVisitor<T, impl FnMut(&T, Event)> {
visitor_fn(move |item, event| {
if let Event::Enter = event {
fun(item);
}
})
}
pub fn visitor_enter_fn_mut<T, F: FnMut(&mut T)>(
mut fun: F,
) -> FnVisitor<T, impl FnMut(&mut T, Event)> {
visitor_fn_mut(move |item, event| {
if let Event::Enter = event {
fun(item);
}
})
}
pub struct FnVisitor<T, F> {
marker: PhantomData<T>,
fun: F,
}
impl<T: Any, F: FnMut(&T, Event)> Visitor for FnVisitor<T, F> {
fn visit(&mut self, item: &dyn Any, event: Event) {
if let Some(item) = <dyn Any>::downcast_ref::<T>(item) {
let fun = &mut self.fun;
fun(item, event);
}
}
}
impl<T: Any, F: FnMut(&mut T, Event)> VisitorMut for FnVisitor<T, F> {
fn visit(&mut self, item: &mut dyn Any, event: Event) {
if let Some(item) = <dyn Any>::downcast_mut::<T>(item) {
let fun = &mut self.fun;
fun(item, event);
}
}
}
pub enum Event {
Enter,
Exit,
}
pub trait Drive: Any {
fn drive<V: Visitor>(&self, visitor: &mut V);
}
pub trait DriveMut: Any {
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V);
}
trait DerefAndDrive {
fn deref_and_drive<V: Visitor>(self, visitor: &mut V);
}
trait DerefAndDriveMut {
fn deref_and_drive_mut<V: VisitorMut>(self, visitor: &mut V);
}
impl<T: Drive> DerefAndDrive for &T {
fn deref_and_drive<V: Visitor>(self, visitor: &mut V) {
self.drive(visitor);
}
}
impl<T: DriveMut> DerefAndDriveMut for &mut T {
fn deref_and_drive_mut<V: VisitorMut>(self, visitor: &mut V) {
self.drive_mut(visitor);
}
}
impl<TK: Drive, TV: Drive> DerefAndDrive for (&TK, &TV) {
fn deref_and_drive<V: Visitor>(self, visitor: &mut V) {
self.0.drive(visitor);
self.1.drive(visitor);
}
}
impl<TK, TV: DriveMut> DerefAndDriveMut for (TK, &mut TV) {
fn deref_and_drive_mut<V: VisitorMut>(self, visitor: &mut V) {
self.1.drive_mut(visitor);
}
}
macro_rules! impl_drive_for_into_iterator {
( $type:ty ; $($generics:tt)+ ) => {
impl< $($generics)+ > Drive for $type
where
$type: 'static,
for<'a> &'a $type: IntoIterator,
for<'a> <&'a $type as IntoIterator>::Item: DerefAndDrive,
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
for item in self {
item.deref_and_drive(visitor);
}
}
}
impl< $($generics)+ > DriveMut for $type
where
$type: 'static,
for<'a> &'a mut $type: IntoIterator,
for<'a> <&'a mut $type as IntoIterator>::Item: DerefAndDriveMut,
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
for item in self {
item.deref_and_drive_mut(visitor);
}
}
}
};
}
impl_drive_for_into_iterator! { [T] ; T }
impl_drive_for_into_iterator! { Vec<T> ; T }
impl_drive_for_into_iterator! { std::collections::BTreeSet<T> ; T }
impl_drive_for_into_iterator! { std::collections::BinaryHeap<T> ; T }
impl_drive_for_into_iterator! { std::collections::HashSet<T> ; T }
impl_drive_for_into_iterator! { std::collections::LinkedList<T> ; T }
impl_drive_for_into_iterator! { std::collections::VecDeque<T> ; T }
impl_drive_for_into_iterator! { Option<T> ; T }
impl_drive_for_into_iterator! { Result<T, U> ; T, U }
impl_drive_for_into_iterator! { std::collections::BTreeMap<T, U> ; T, U }
impl_drive_for_into_iterator! { std::collections::HashMap<T, U> ; T, U }
impl_drive_for_into_iterator! { [T; N] ; T, const N: usize }
impl<T> Drive for Box<T>
where
T: Drive,
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
(**self).drive(visitor);
}
}
impl<T> DriveMut for Box<T>
where
T: DriveMut,
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
(**self).drive_mut(visitor);
}
}
impl<T> Drive for Arc<T>
where
T: Drive,
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
(**self).drive(visitor);
}
}
impl<T> Drive for Mutex<T>
where
T: Drive,
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
let lock = self.lock().unwrap();
lock.drive(visitor);
}
}
impl<T> Drive for RwLock<T>
where
T: Drive,
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
let lock = self.read().unwrap();
lock.drive(visitor);
}
}
impl<T> DriveMut for Arc<Mutex<T>>
where
T: DriveMut,
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
let mut lock = self.lock().unwrap();
lock.drive_mut(visitor);
}
}
impl<T> DriveMut for Arc<RwLock<T>>
where
T: DriveMut,
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
let mut lock = self.write().unwrap();
lock.drive_mut(visitor);
}
}
impl<T> Drive for Cell<T>
where
T: Drive + Copy,
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
self.get().drive(visitor);
}
}
impl<T> DriveMut for Cell<T>
where
T: DriveMut,
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
self.get_mut().drive_mut(visitor);
}
}
impl Drive for () {
fn drive<V: Visitor>(&self, _visitor: &mut V) {}
}
impl DriveMut for () {
fn drive_mut<V: VisitorMut>(&mut self, _visitor: &mut V) {}
}
macro_rules! tuple_impls {
( $( $( $type:ident ),+ => $( $field:tt ),+ )+ ) => {
$(
impl<$( $type ),+> Drive for ($($type,)+)
where
$(
$type: Drive
),+
{
fn drive<V: Visitor>(&self, visitor: &mut V) {
$(
self.$field.drive(visitor);
)+
}
}
impl<$( $type ),+> DriveMut for ($($type,)+)
where
$(
$type: DriveMut
),+
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
$(
self.$field.drive_mut(visitor);
)+
}
}
)+
};
}
tuple_impls! {
T0 => 0
T0, T1 => 0, 1
T0, T1, T2 => 0, 1, 2
T0, T1, T2, T3 => 0, 1, 2, 3
T0, T1, T2, T3, T4 => 0, 1, 2, 3, 4
T0, T1, T2, T3, T4, T5 => 0, 1, 2, 3, 4, 5
T0, T1, T2, T3, T4, T5, T6 => 0, 1, 2, 3, 4, 5, 6
T0, T1, T2, T3, T4, T5, T6, T7 => 0, 1, 2, 3, 4, 5, 6, 7
}
#[cfg(feature = "std-types-drive")]
macro_rules! trivial_impl {
( $type:ty ) => {
impl Drive for $type {
fn drive<V: Visitor>(&self, visitor: &mut V) {
visitor.visit(self, Event::Enter);
visitor.visit(self, Event::Exit);
}
}
impl DriveMut for $type {
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
visitor.visit(self, Event::Enter);
visitor.visit(self, Event::Exit);
}
}
};
}
#[cfg(not(feature = "std-types-drive"))]
macro_rules! trivial_impl {
( $type:ident ) => {};
}
trivial_impl!(u8);
trivial_impl!(u16);
trivial_impl!(u32);
trivial_impl!(u64);
trivial_impl!(u128);
trivial_impl!(usize);
trivial_impl!(i8);
trivial_impl!(i16);
trivial_impl!(i32);
trivial_impl!(i64);
trivial_impl!(i128);
trivial_impl!(isize);
trivial_impl!(f32);
trivial_impl!(f64);
trivial_impl!(char);
trivial_impl!(bool);
trivial_impl!(String);
#[cfg(feature = "std-types-drive")]
mod drive_ranges {
use super::*;
use std::ops::*;
impl<T: Drive> Drive for Range<T> {
fn drive<V: Visitor>(&self, visitor: &mut V) {
self.start.drive(visitor);
self.end.drive(visitor);
}
}
impl<T: DriveMut> DriveMut for Range<T> {
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
self.start.drive_mut(visitor);
self.end.drive_mut(visitor);
}
}
impl<T: Drive> Drive for RangeTo<T> {
fn drive<V: Visitor>(&self, visitor: &mut V) {
self.end.drive(visitor);
}
}
impl<T: DriveMut> DriveMut for RangeTo<T> {
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
self.end.drive_mut(visitor);
}
}
impl<T: Drive> Drive for RangeToInclusive<T> {
fn drive<V: Visitor>(&self, visitor: &mut V) {
self.end.drive(visitor);
}
}
impl<T: DriveMut> DriveMut for RangeToInclusive<T> {
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
self.end.drive_mut(visitor);
}
}
impl<T: Drive> Drive for RangeFrom<T> {
fn drive<V: Visitor>(&self, visitor: &mut V) {
self.start.drive(visitor);
}
}
impl<T: DriveMut> DriveMut for RangeFrom<T> {
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
self.start.drive_mut(visitor);
}
}
impl<T: Drive> Drive for RangeInclusive<T> {
fn drive<V: Visitor>(&self, visitor: &mut V) {
self.start().drive(visitor);
self.end().drive(visitor);
}
}
impl<T: DriveMut> DriveMut for RangeInclusive<T>
where
T: Default,
{
fn drive_mut<V: VisitorMut>(&mut self, visitor: &mut V) {
let placeholder = RangeInclusive::new(T::default(), T::default());
let bounds = std::mem::replace(self, placeholder);
let mut tuple = bounds.into_inner();
tuple.drive_mut(visitor);
*self = RangeInclusive::new(tuple.0, tuple.1);
}
}
}