extern crate alloc;
use alloc::vec::Vec;
use super::children::{Bucket, sibling_cmp};
use super::placement::Dot;
use super::placement::RawDot;
use super::{Anchor, Rhapsody};
#[derive(Clone, Copy, Debug)]
enum Frame {
Visit(Dot),
Emit(Dot),
}
#[derive(Clone, Debug)]
pub struct OrderWalk<'a> {
rhapsody: &'a Rhapsody,
stack: Vec<Frame>,
climb: Option<Dot>,
}
impl OrderWalk<'_> {
fn climb_one_level(&mut self) -> Option<()> {
let cursor = self.climb?;
let locus = self.rhapsody.skeleton.get(&cursor)?;
match locus.anchor {
Anchor::Origin => {
self.climb = None;
let bucket = self
.rhapsody
.children
.bucket(&self.rhapsody.skeleton, Anchor::Origin)?;
let pos = self.rhapsody.sibling_position(&bucket, cursor)?;
for kid in bucket.suffix(pos).rev() {
self.stack.push(Frame::Visit(kid));
}
}
Anchor::After(parent) => {
self.climb = Some(Dot::try_from(parent).ok()?);
let bucket = self
.rhapsody
.children
.bucket(&self.rhapsody.skeleton, Anchor::After(parent))?;
let pos = self.rhapsody.sibling_position(&bucket, cursor)?;
for kid in bucket.suffix(pos).rev() {
self.stack.push(Frame::Visit(kid));
}
}
Anchor::Before(parent) => {
let parent_dot = Dot::try_from(parent).ok()?;
self.climb = Some(parent_dot);
for kid in self
.rhapsody
.children
.iter(&self.rhapsody.skeleton, Anchor::After(parent))
.rev()
{
self.stack.push(Frame::Visit(kid));
}
self.stack.push(Frame::Emit(parent_dot));
let bucket = self
.rhapsody
.children
.bucket(&self.rhapsody.skeleton, Anchor::Before(parent))?;
let pos = self.rhapsody.sibling_position(&bucket, cursor)?;
for kid in bucket.prefix(pos) {
self.stack.push(Frame::Visit(kid));
}
}
}
Some(())
}
}
impl OrderWalk<'_> {
pub(super) fn next_slot(&mut self) -> Option<(Dot, bool)> {
loop {
while let Some(frame) = self.stack.pop() {
match frame {
Frame::Emit(dot) => {
return Some((dot, self.rhapsody.visible.contains(dot)));
}
Frame::Visit(dot) => {
for kid in self
.rhapsody
.children
.iter(&self.rhapsody.skeleton, Anchor::After(dot.into()))
.rev()
{
self.stack.push(Frame::Visit(kid));
}
self.stack.push(Frame::Emit(dot));
for kid in self
.rhapsody
.children
.iter(&self.rhapsody.skeleton, Anchor::Before(dot.into()))
{
self.stack.push(Frame::Visit(kid));
}
}
}
}
self.climb_one_level()?;
}
}
}
impl Iterator for OrderWalk<'_> {
type Item = Dot;
fn next(&mut self) -> Option<Self::Item> {
loop {
let (dot, visible) = self.next_slot()?;
if visible {
return Some(dot);
}
}
}
}
impl core::iter::FusedIterator for OrderWalk<'_> {}
#[derive(Clone, Debug)]
pub struct OrderWalkRev<'a> {
rhapsody: &'a Rhapsody,
remaining: usize,
}
impl Iterator for OrderWalkRev<'_> {
type Item = Dot;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
self.rhapsody.order_at(self.remaining)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl ExactSizeIterator for OrderWalkRev<'_> {}
impl core::iter::FusedIterator for OrderWalkRev<'_> {}
impl Rhapsody {
#[must_use]
pub fn order(&self) -> Vec<Dot> {
self.order_walk().collect()
}
#[must_use]
pub fn order_walk(&self) -> OrderWalk<'_> {
let mut stack: Vec<Frame> = Vec::new();
for root in self.children.iter(&self.skeleton, Anchor::Origin).rev() {
stack.push(Frame::Visit(root));
}
OrderWalk {
rhapsody: self,
stack,
climb: None,
}
}
pub(super) fn sibling_position(&self, bucket: &Bucket<'_>, dot: Dot) -> Option<usize> {
match bucket {
Bucket::Explicit(bucket) => {
let pos = bucket
.partition_point(|&other| sibling_cmp(&self.skeleton, other, dot).is_lt());
(bucket.get(pos) == Some(&dot)).then_some(pos)
}
Bucket::Implicit(child) => (*child == dot).then_some(0),
}
}
#[must_use]
pub fn order_walk_after(&self, dot: Dot) -> Option<OrderWalk<'_>> {
let start = dot;
if !self.skeleton.contains(start) || self.unplaced.contains(&start) {
return None;
}
let mut stack: Vec<Frame> = Vec::new();
for kid in self
.children
.iter(&self.skeleton, Anchor::After(start.into()))
.rev()
{
stack.push(Frame::Visit(kid));
}
Some(OrderWalk {
rhapsody: self,
stack,
climb: Some(start),
})
}
#[must_use]
pub fn anchor_for_visual_insert(&self, after: Option<RawDot>) -> Anchor {
let base = after.map_or(Anchor::Origin, Anchor::After);
let Some(head) = self
.children
.bucket(&self.skeleton, base)
.map(|b| b.first())
else {
return base;
};
let mut successor = head;
while let Some(next) = self
.children
.bucket(&self.skeleton, Anchor::Before(successor.into()))
.map(|bucket| bucket.last())
{
successor = next;
}
Anchor::Before(successor.into())
}
pub fn children_of(&self, anchor: Anchor) -> impl Iterator<Item = Dot> + '_ {
self.children.iter(&self.skeleton, anchor)
}
#[must_use]
pub fn order_walk_rev(&self) -> OrderWalkRev<'_> {
OrderWalkRev {
rhapsody: self,
remaining: self.thread.visible_len(),
}
}
#[must_use]
pub fn order_walk_rev_before(&self, dot: Dot) -> Option<OrderWalkRev<'_>> {
self.thread
.position_of(dot)
.map(|(_, visible_before)| OrderWalkRev {
rhapsody: self,
remaining: visible_before,
})
}
#[must_use]
pub fn is_reachable(&self, dot: Dot) -> bool {
self.skeleton.contains(dot) && !self.unplaced.contains(&dot)
}
}