use super::WalkResult;
use crate::{
Block, BlockRef, Direction, Operation, OperationRef, Region, RegionRef,
UnsafeIntrusiveEntityRef,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WalkOrder {
PreOrder,
PostOrder,
}
#[derive(Clone, PartialEq, Eq)]
pub struct WalkStage {
num_regions: usize,
next_region: Option<RegionRef>,
}
impl WalkStage {
pub fn new(op: OperationRef) -> Self {
let op = op.borrow();
Self {
num_regions: op.num_regions(),
next_region: op.regions().front().as_pointer(),
}
}
#[inline]
pub fn is_before_all_regions(&self) -> bool {
self.next_region.is_some_and(|r| r.prev().is_none())
}
#[inline]
pub fn is_before_region(&self, region: RegionRef) -> bool {
self.next_region.is_some_and(|r| r.next().is_some_and(|next| next == region))
}
#[inline]
pub fn is_after_region(&self, region: RegionRef) -> bool {
self.next_region.is_some_and(|r| r.prev().is_some_and(|prev| prev == region))
}
#[inline]
pub fn is_after_all_regions(&self) -> bool {
self.next_region.is_none()
}
#[inline]
pub fn advance(&mut self) {
if let Some(next_region) = self.next_region.take() {
self.next_region = next_region.next();
}
}
#[inline(always)]
pub const fn next_region(&self) -> Option<RegionRef> {
self.next_region
}
}
pub trait WalkDirection =
Walker<Region, BlockRef> + Walker<Block, OperationRef> + Walker<Operation, RegionRef>;
pub trait Walk<T> {
fn walk_all<D, F>(&self, order: WalkOrder, mut callback: F)
where
D: WalkDirection,
F: FnMut(&T),
{
let _ = self.walk::<D, _, _>(order, |t| {
callback(t);
WalkResult::<()>::Continue(())
});
}
#[inline]
fn prewalk_all<D, F>(&self, callback: F)
where
D: WalkDirection,
F: FnMut(&T),
{
self.walk_all::<D, _>(WalkOrder::PreOrder, callback)
}
#[inline]
fn postwalk_all<D, F>(&self, callback: F)
where
D: WalkDirection,
F: FnMut(&T),
{
self.walk_all::<D, _>(WalkOrder::PostOrder, callback)
}
fn walk<D, F, B>(&self, order: WalkOrder, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&T) -> WalkResult<B>;
#[inline]
fn prewalk<D, F, B>(&self, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&T) -> WalkResult<B>,
{
self.walk::<D, _, _>(WalkOrder::PreOrder, callback)
}
#[inline]
fn postwalk<D, F, B>(&self, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&T) -> WalkResult<B>,
{
self.walk::<D, _, _>(WalkOrder::PostOrder, callback)
}
}
pub trait WalkMut<T> {
fn walk_all_mut<D, F>(&mut self, order: WalkOrder, mut callback: F)
where
D: WalkDirection,
F: FnMut(&mut T),
{
let _ = self.walk_mut::<D, _, _>(order, |t| {
callback(t);
WalkResult::<()>::Continue(())
});
}
#[inline]
fn prewalk_all_mut<D, F>(&mut self, callback: F)
where
D: WalkDirection,
F: FnMut(&mut T),
{
self.walk_all_mut::<D, _>(WalkOrder::PreOrder, callback)
}
#[inline]
fn postwalk_all_mut<D, F>(&mut self, callback: F)
where
D: WalkDirection,
F: FnMut(&mut T),
{
self.walk_all_mut::<D, _>(WalkOrder::PostOrder, callback)
}
fn walk_mut<D, F, B>(&mut self, order: WalkOrder, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&mut T) -> WalkResult<B>;
#[inline]
fn prewalk_mut_interruptible<D, F, B>(&mut self, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&mut T) -> WalkResult<B>,
{
self.walk_mut::<D, _, _>(WalkOrder::PreOrder, callback)
}
#[inline]
fn postwalk_mut_interruptible<D, F, B>(&mut self, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&mut T) -> WalkResult<B>,
{
self.walk_mut::<D, _, _>(WalkOrder::PostOrder, callback)
}
}
pub trait RawWalk<T> {
fn raw_walk_all<D, F>(&self, order: WalkOrder, mut callback: F)
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<T>),
{
let _ = self.raw_walk::<D, _, _>(order, |t| {
callback(t);
WalkResult::<()>::Continue(())
});
}
#[inline]
fn raw_prewalk_all<D, F>(&self, callback: F)
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<T>),
{
self.raw_walk_all::<D, _>(WalkOrder::PreOrder, callback)
}
#[inline]
fn raw_postwalk_all<D, F>(&self, callback: F)
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<T>),
{
self.raw_walk_all::<D, _>(WalkOrder::PostOrder, callback)
}
fn raw_walk<D, F, B>(&self, order: WalkOrder, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<T>) -> WalkResult<B>;
#[inline]
fn raw_prewalk<D, F, B>(&self, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<T>) -> WalkResult<B>,
{
self.raw_walk::<D, _, _>(WalkOrder::PreOrder, callback)
}
#[inline]
fn raw_postwalk<D, F, B>(&self, callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<T>) -> WalkResult<B>,
{
self.raw_walk::<D, _, _>(WalkOrder::PostOrder, callback)
}
}
impl RawWalk<Operation> for OperationRef {
fn raw_walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<Operation>) -> WalkResult<B>,
{
raw_walk_operations::<D, _, _>(*self, order, &mut callback)
}
}
impl Walk<Operation> for OperationRef {
fn walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&Operation) -> WalkResult<B>,
{
let mut wrapper = |op: OperationRef| callback(&op.borrow());
raw_walk_operations::<D, _, _>(*self, order, &mut wrapper)
}
}
impl WalkMut<Operation> for OperationRef {
fn walk_mut<D, F, B>(&mut self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&mut Operation) -> WalkResult<B>,
{
let mut wrapper = |mut op: OperationRef| callback(&mut op.borrow_mut());
raw_walk_operations::<D, _, _>(*self, order, &mut wrapper)
}
}
impl Walk<Operation> for Operation {
fn walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&Operation) -> WalkResult<B>,
{
let mut wrapper = |op: OperationRef| callback(&op.borrow());
raw_walk_operations::<D, _, _>(self.as_operation_ref(), order, &mut wrapper)
}
}
impl RawWalk<Region> for OperationRef {
fn raw_walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<Region>) -> WalkResult<B>,
{
raw_walk_regions::<D, _, _>(*self, order, &mut callback)
}
}
impl Walk<Region> for OperationRef {
fn walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&Region) -> WalkResult<B>,
{
let mut wrapper = |region: RegionRef| callback(®ion.borrow());
raw_walk_regions::<D, _, _>(*self, order, &mut wrapper)
}
}
impl WalkMut<Region> for OperationRef {
fn walk_mut<D, F, B>(&mut self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&mut Region) -> WalkResult<B>,
{
let mut wrapper = |mut region: RegionRef| callback(&mut region.borrow_mut());
raw_walk_regions::<D, _, _>(*self, order, &mut wrapper)
}
}
impl Walk<Region> for Operation {
fn walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&Region) -> WalkResult<B>,
{
let mut wrapper = |region: RegionRef| callback(®ion.borrow());
raw_walk_regions::<D, _, _>(self.as_operation_ref(), order, &mut wrapper)
}
}
#[allow(unused)]
pub fn raw_walk<D, F, B>(op: OperationRef, callback: &mut F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(OperationRef, &WalkStage) -> WalkResult<B>,
{
let mut stage = WalkStage::new(op);
let mut next_region = stage.next_region();
while let Some(region) = next_region.take() {
let result = callback(op, &stage);
match result {
WalkResult::Skip => return WalkResult::Continue(()),
err @ WalkResult::Break(_) => return err,
WalkResult::Continue(_) => {
stage.advance();
let mut next_block = D::start(&*region.borrow());
while let Some(block) = next_block.take() {
next_block = D::continue_walk(block);
let mut next_op = D::start(&*block.borrow());
while let Some(op) = next_op.take() {
next_op = D::continue_walk(op);
raw_walk::<D, _, _>(op, callback)?;
}
}
}
}
}
callback(op, &stage)
}
fn raw_walk_regions<D, F, B>(op: OperationRef, order: WalkOrder, callback: &mut F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(RegionRef) -> WalkResult<B>,
{
let mut next_region = D::start(&*op.borrow());
while let Some(region) = next_region.take() {
next_region = D::continue_walk(region);
if matches!(order, WalkOrder::PreOrder) {
let result = callback(region);
match result {
WalkResult::Skip => continue,
err @ WalkResult::Break(_) => return err,
_ => (),
}
}
let mut next_block = D::start(&*region.borrow());
while let Some(block) = next_block.take() {
next_block = D::continue_walk(block);
let mut next_op = D::start(&*block.borrow());
while let Some(op) = next_op.take() {
next_op = D::continue_walk(op);
raw_walk_regions::<D, _, _>(op, order, callback)?;
}
}
if matches!(order, WalkOrder::PostOrder) {
callback(region)?;
}
}
WalkResult::Continue(())
}
#[allow(unused)]
fn raw_walk_blocks<D, F, B>(op: OperationRef, order: WalkOrder, callback: &mut F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(BlockRef) -> WalkResult<B>,
{
let mut next_region = D::start(&*op.borrow());
while let Some(region) = next_region.take() {
next_region = D::continue_walk(region);
let mut next_block = D::start(&*region.borrow());
while let Some(block) = next_block.take() {
next_block = D::continue_walk(block);
if matches!(order, WalkOrder::PreOrder) {
let result = callback(block);
match result {
WalkResult::Skip => continue,
err @ WalkResult::Break(_) => return err,
_ => (),
}
}
let mut next_op = D::start(&*block.borrow());
while let Some(op) = next_op.take() {
next_op = D::continue_walk(op);
raw_walk_blocks::<D, _, _>(op, order, callback)?;
}
if matches!(order, WalkOrder::PostOrder) {
callback(block)?;
}
}
}
WalkResult::Continue(())
}
fn raw_walk_operations<D, F, B>(
op: OperationRef,
order: WalkOrder,
callback: &mut F,
) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(OperationRef) -> WalkResult<B>,
{
if matches!(order, WalkOrder::PreOrder) {
let result = callback(op);
match result {
WalkResult::Skip => return WalkResult::Continue(()),
err @ WalkResult::Break(_) => return err,
_ => (),
}
}
let mut next_region = D::start(&*op.borrow());
while let Some(region) = next_region.take() {
next_region = D::continue_walk(region);
let mut next_block = D::start(&*region.borrow());
while let Some(block) = next_block.take() {
next_block = D::continue_walk(block);
let mut next_op = D::start(&*block.borrow());
while let Some(op) = next_op.take() {
next_op = D::continue_walk(op);
raw_walk_operations::<D, _, _>(op, order, callback)?;
}
}
}
if matches!(order, WalkOrder::PostOrder) {
callback(op)?;
}
WalkResult::Continue(())
}
fn raw_walk_region_operations<D, F, B>(
region: RegionRef,
order: WalkOrder,
callback: &mut F,
) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(OperationRef) -> WalkResult<B>,
{
let mut next_block = D::start(&*region.borrow());
while let Some(block) = next_block.take() {
next_block = D::continue_walk(block);
let mut next_op = D::start(&*block.borrow());
while let Some(op) = next_op.take() {
next_op = D::continue_walk(op);
raw_walk_operations::<D, _, _>(op, order, callback)?;
}
}
WalkResult::Continue(())
}
impl RawWalk<Operation> for RegionRef {
fn raw_walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(UnsafeIntrusiveEntityRef<Operation>) -> WalkResult<B>,
{
raw_walk_region_operations::<D, _, _>(*self, order, &mut callback)
}
}
impl Walk<Operation> for RegionRef {
fn walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&Operation) -> WalkResult<B>,
{
let mut wrapper = |op: OperationRef| callback(&op.borrow());
raw_walk_region_operations::<D, _, _>(*self, order, &mut wrapper)
}
}
impl WalkMut<Operation> for RegionRef {
fn walk_mut<D, F, B>(&mut self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&mut Operation) -> WalkResult<B>,
{
let mut wrapper = |mut op: OperationRef| callback(&mut op.borrow_mut());
raw_walk_region_operations::<D, _, _>(*self, order, &mut wrapper)
}
}
impl Walk<Operation> for Region {
fn walk<D, F, B>(&self, order: WalkOrder, mut callback: F) -> WalkResult<B>
where
D: WalkDirection,
F: FnMut(&Operation) -> WalkResult<B>,
{
let mut wrapper = |op: OperationRef| callback(&op.borrow());
raw_walk_region_operations::<D, _, _>(self.as_region_ref(), order, &mut wrapper)
}
}
pub trait Walker<Parent, Child> {
fn start(entity: &Parent) -> Option<Child>;
fn continue_walk(child: Child) -> Option<Child>;
}
pub struct ReverseBlock;
impl Walker<Region, BlockRef> for ReverseBlock {
#[inline(always)]
fn start(entity: &Region) -> Option<BlockRef> {
entity.body().front().as_pointer()
}
#[inline(always)]
fn continue_walk(child: BlockRef) -> Option<BlockRef> {
child.next()
}
}
impl Walker<Block, OperationRef> for ReverseBlock {
#[inline(always)]
fn start(entity: &Block) -> Option<OperationRef> {
entity.body().back().as_pointer()
}
#[inline(always)]
fn continue_walk(child: OperationRef) -> Option<OperationRef> {
child.prev()
}
}
impl Walker<Operation, RegionRef> for ReverseBlock {
#[inline(always)]
fn start(entity: &Operation) -> Option<RegionRef> {
entity.regions().front().as_pointer()
}
#[inline(always)]
fn continue_walk(child: RegionRef) -> Option<RegionRef> {
child.next()
}
}
impl<D: Direction> Walker<Region, BlockRef> for D {
#[inline(always)]
fn start(entity: &Region) -> Option<BlockRef> {
if const { D::IS_FORWARD } {
entity.body().front().as_pointer()
} else {
entity.body().back().as_pointer()
}
}
#[inline(always)]
fn continue_walk(child: BlockRef) -> Option<BlockRef> {
if const { D::IS_FORWARD } {
child.next()
} else {
child.prev()
}
}
}
impl<D: Direction> Walker<Block, OperationRef> for D {
#[inline(always)]
fn start(entity: &Block) -> Option<OperationRef> {
if const { D::IS_FORWARD } {
entity.body().front().as_pointer()
} else {
entity.body().back().as_pointer()
}
}
#[inline(always)]
fn continue_walk(child: OperationRef) -> Option<OperationRef> {
if const { D::IS_FORWARD } {
child.next()
} else {
child.prev()
}
}
}
impl<D: Direction> Walker<Operation, RegionRef> for D {
#[inline(always)]
fn start(entity: &Operation) -> Option<RegionRef> {
if const { D::IS_FORWARD } {
entity.regions().front().as_pointer()
} else {
entity.regions().back().as_pointer()
}
}
#[inline(always)]
fn continue_walk(child: RegionRef) -> Option<RegionRef> {
if const { D::IS_FORWARD } {
child.next()
} else {
child.prev()
}
}
}