use replace_with::replace_with_or_abort;
use crate::path::Path;
#[derive(Debug, Clone)]
pub enum Position<B, I> {
Attached(AttachedPosition<B, I>),
Detached(DetachedPosition<B, I>),
}
impl<B, I> Position<B, I> {
pub fn new_detached() -> Self {
Self::Detached(DetachedPosition::new())
}
pub fn new_attached(root: I) -> Self {
let mut ph = Path::new();
ph.push_last(root);
Self::Attached(AttachedPosition::from(Path::new(), ph))
}
pub fn from(path: Path<B>, idxs: Path<I>) -> Self {
if !idxs.is_empty() && path.len() == idxs.len() - 1 {
Self::Attached(AttachedPosition::from(path, idxs))
} else {
Self::Detached(DetachedPosition::from(path, idxs))
}
}
pub fn move_up(&mut self, up: usize) -> Option<usize> {
let mut overflow = None;
replace_with_or_abort(self, |s| match s {
Position::Attached(mut attached) => {
attached.move_up(up).map(|e| {
overflow = Some(e);
e
});
attached.into()
}
Position::Detached(detached) => {
let (p, e) = detached.move_up(up);
overflow = e;
p
}
});
overflow
}
pub fn parent(&self) -> Option<(Option<&B>, Option<&I>)> {
match self {
Position::Attached(attached) => attached.parent().map(|(b, i)| (b, Some(i))),
Position::Detached(detached) => detached.parent(),
}
}
pub fn is_attached(&self) -> bool {
match self {
Position::Attached(_) => true,
Position::Detached(_) => false,
}
}
pub fn attached_mut(&mut self) -> Option<&mut AttachedPosition<B, I>> {
match self {
Position::Attached(position) => Some(position),
Position::Detached(_) => None,
}
}
pub fn detached_mut(&mut self) -> Option<&mut DetachedPosition<B, I>> {
match self {
Position::Attached(_) => None,
Position::Detached(position) => Some(position),
}
}
pub fn attached(&self) -> Option<&AttachedPosition<B, I>> {
match self {
Position::Attached(position) => Some(position),
Position::Detached(_) => None,
}
}
pub fn detached(&self) -> Option<&DetachedPosition<B, I>> {
match self {
Position::Attached(_) => None,
Position::Detached(position) => Some(position),
}
}
pub fn unwrap_detached(self) -> DetachedPosition<B, I> {
match self {
Position::Attached(_) => panic!("Unwrapping an Attached Position as DetachedPosition"),
Position::Detached(position) => position,
}
}
pub fn unwrap_attached(self) -> AttachedPosition<B, I> {
match self {
Position::Attached(position) => position,
Position::Detached(_) => panic!("Unwrapping a Detached Position as AttachedPosition"),
}
}
pub fn at(&self) -> Option<&I> {
match self {
Position::Attached(position) => Some(position.at()),
Position::Detached(_) => None,
}
}
pub fn path(&self) -> &Path<B> {
match self {
Position::Attached(position) => position.path(),
Position::Detached(position) => position.path(),
}
}
pub fn idxs(&self) -> &Path<I> {
match self {
Position::Attached(position) => position.idxs(),
Position::Detached(position) => position.idxs(),
}
}
pub fn at_branch(&self) -> Option<&B> {
match self {
Position::Attached(position) => position.at_branch(),
Position::Detached(position) => position.at_branch(),
}
}
}
impl<B, I> From<AttachedPosition<B, I>> for Position<B, I> {
fn from(value: AttachedPosition<B, I>) -> Self {
Self::Attached(value)
}
}
impl<B, I> From<DetachedPosition<B, I>> for Position<B, I> {
fn from(value: DetachedPosition<B, I>) -> Self {
Self::Detached(value)
}
}
#[derive(Debug, Clone)]
pub struct AttachedPosition<B, I> {
path: Path<B>,
idxs: Path<I>,
}
#[derive(Debug, Clone)]
pub struct DetachedPosition<B, I> {
path: Path<B>,
idxs: Path<I>,
}
impl<B, I> AttachedPosition<B, I> {
pub fn from(path: Path<B>, idxs: Path<I>) -> Self {
assert!(path.len() + 1 == idxs.len(), "Position is not attached");
Self { path, idxs }
}
pub fn at(&self) -> &I {
self.idxs.last().unwrap()
}
pub fn move_up(&mut self, up: usize) -> Option<usize> {
let len = self.path.len();
if up > len {
self.path.clear();
self.idxs.truncate_end(self.idxs.len() - 1);
Some(up - len)
} else {
self.path.truncate_end(up);
self.idxs.truncate_end(up);
None
}
}
pub fn move_down(&mut self, branch: B, idx: I) {
self.path.push_last(branch);
self.idxs.push_last(idx);
}
pub fn move_down_detach(mut self, branch: B) -> DetachedPosition<B, I> {
self.path.push_last(branch);
self.into_detached()
}
pub fn parent(&self) -> Option<(Option<&B>, &I)> {
if self.path.last().is_some() {
Some((
if self.path.len() > 1 {
Some(&self.path[self.path.len() - 2])
} else {
None
},
&self.idxs[self.path.len() - 1],
))
} else {
None
}
}
pub fn remove_node(mut self) -> DetachedPosition<B, I> {
self.idxs.pop_last();
self.into_detached()
}
pub fn into_detached(self) -> DetachedPosition<B, I> {
DetachedPosition {
path: self.path,
idxs: self.idxs,
}
}
pub fn at_branch(&self) -> Option<&B> {
self.path.last()
}
pub fn path(&self) -> &Path<B> {
&self.path
}
pub fn idxs(&self) -> &Path<I> {
&self.idxs
}
}
impl<B, I> DetachedPosition<B, I> {
pub fn new() -> Self {
Self {
path: Path::new(),
idxs: Path::new(),
}
}
pub fn from(path: Path<B>, idxs: Path<I>) -> Self {
assert!(path.len() >= idxs.len(), "Position is not detached");
Self { path, idxs }
}
pub fn into_attached(self) -> AttachedPosition<B, I> {
assert!(self.is_attached());
AttachedPosition {
path: self.path,
idxs: self.idxs,
}
}
pub fn detached_at(&self) -> Option<&I> {
self.idxs.last()
}
pub fn move_up(mut self, up: usize) -> (Position<B, I>, Option<usize>) {
let len = self.path.len();
if up > len {
self.path.clear();
if !self.idxs.is_empty() {
self.idxs.truncate_end(self.idxs.len() - 1);
(self.into_attached().into(), Some(up - len))
} else {
(self.into(), Some(up - len))
}
} else {
self.path.truncate_end(up);
(
if self.path.len() < self.idxs.len() {
self.idxs
.truncate_end(self.idxs.len() - self.path.len() - 1);
self.into_attached().into()
} else {
self.into()
},
None,
)
}
}
pub fn move_to_attached(mut self) -> Result<AttachedPosition<B, I>, Self> {
if !self.idxs.is_empty() && self.idxs.len() <= self.path.len() {
self.path
.truncate_end(self.path.len() - self.idxs.len() + 1);
debug_assert!(
self.is_attached(),
"Position is still not attached after moving to attached position"
);
Ok(self.into_attached())
} else {
Err(self)
}
}
pub fn move_down(&mut self, branch: B) {
self.path.push_last(branch);
}
pub fn parent(&self) -> Option<(Option<&B>, Option<&I>)> {
if self.path.last().is_some() {
let l = self.path.len();
Some((
if l > 1 {
Some(&self.path[l - 2])
} else {
None
},
if self.idxs.len() == l {
self.idxs.last()
} else {
None
},
))
} else {
None
}
}
pub fn attach(mut self, idx: I) -> Position<B, I> {
self.idxs.push_last(idx);
if self.is_attached() {
self.into_attached().into()
} else {
self.into()
}
}
pub fn attach_all(mut self, mut idxs: Vec<I>) -> Position<B, I> {
idxs.truncate(self.path.len() - self.idxs.len() + 1);
self.idxs.append(idxs.into());
if self.is_attached() {
self.into_attached().into()
} else {
self.into()
}
}
fn is_attached(&self) -> bool {
self.is_rooted() && self.path.len() == self.idxs.len() - 1 }
pub fn path(&self) -> &Path<B> {
&self.path
}
pub fn idxs(&self) -> &Path<I> {
&self.idxs
}
pub fn iter_detached_path(&self) -> std::collections::vec_deque::Iter<'_, B> {
if self.is_rooted() {
self.path.range((self.idxs.len() - 1)..)
} else {
self.path.range(..)
}
}
pub fn offshoot_len(&self) -> usize {
self.path.len() + 1 - self.idxs.len()
}
pub fn is_rooted(&self) -> bool {
!self.idxs.is_empty()
}
pub fn is_empty(&self) -> bool {
self.path.is_empty()
}
pub fn at_branch(&self) -> Option<&B> {
self.path.last()
}
}
impl<B, I> DetachedPosition<B, I>
where
B: Clone,
{
pub fn detached_at_branch(&self) -> Option<&B> {
if !self.idxs.is_empty() {
Some(&self.path[self.idxs.len()])
} else {
None
}
}
}