Showing preview only (269K chars total). Download the full file or copy to clipboard to get everything.
Repository: matthieu-m/ghost-collections
Branch: master
Commit: 4a72daed3758
Files: 15
Total size: 260.4 KB
Directory structure:
gitextract_xxgw4ag_/
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src/
├── lib.rs
├── linked_list/
│ ├── cursor.rs
│ └── iter.rs
├── linked_list.rs
├── tripod_list/
│ ├── cursor.rs
│ └── iter.rs
├── tripod_list.rs
├── tripod_tree/
│ ├── cursor.rs
│ └── iter.rs
└── tripod_tree.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.cargo
target
Cargo.lock
================================================
FILE: Cargo.toml
================================================
[package]
name = "ghost-collections"
version = "0.1.0"
authors = ["Matthieu M. <matthieum.147192@gmail.com>"]
edition = "2018"
description = "Safe collections, on stable Rust"
repository = "https://github.com/matthieu-m/ghost-collections"
license = "MIT OR Apache-2.0"
keywords = ["experimental", "aliasing", "borrowing"]
categories = ["data-structures", "no-std"]
[dependencies]
ghost-cell = "0.2"
static-rc = { version = "0.4.0", features = ["experimental-lift"] }
[features]
# Enables a variety of features relying on the experimental ghost-cell `GhostCursor`, such as LinkedList's append and cursor_mut.
experimental-ghost-cursor = ["ghost-cell/experimental-ghost-cursor"]
# Enables debug printing to stderr, only available in test to debug trees.
test-tree-debug = []
================================================
FILE: LICENSE-APACHE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 matthieu-m
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: LICENSE-MIT
================================================
Copyright 2021 matthieu-m
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
A proof of concept implementation of cyclic data structures in stable, safe, Rust.
This demonstrates the combined power of the [static-rc](https://github.com/matthieu-m/static-rc) crate and the
[ghost-cell](https://github.com/matthieu-m/ghost-cell) crate.
# Motivation
## Why the focus on safety?
A simple combination of 2 facts about data structures:
- They are pervasive and often used to store user-controlled input.
- They are extremely error-prone, juggling lifetime and aliasing concerns at the same time.
The combination of this two factors means that a single logical bug can result in Undefined Behavior, opening up the
door to a multitude of attacks.
## How can you write safe cyclic data structures?
There are typically two obstacles, as mentioned: lifetime, and aliasing.
The state of the art recommendation today is one of:
- A `Vec` with indices instead of pointers.
- An arena to handle lifetime, and some form of cell to handle aliasing.
- `Rc` + `RefCell`.
## What's wrong with those approaches?
`Vec` based solutions will blow up the algorithmic complexity of splice/split operations. In a linked list, splicing in
another list, or splitting a part of the list, are both O(1) operations, but transferring N elements from one `Vec` to
another is at least an O(N) operation.
Arena based solution will allow implementing all operations with their expected algorithmic complexity, but this comes at
the cost of never being able to reclaim memory from the arena as long as a single data structure exists which references
the arena.
Finally `Rc` + `RefCell` suffer from increased memory consumption and runtime overhead:
- `Rc` typically embeds 2 `usize` counters: the strong and weak count.
- An `Rc` implementation optimized for data structures could ditch the weak count.
- `RefCell` typically embeds an `isize` counter: to count the number of readers and writers.
# Does ghost-collections offer a better alternative then?
Maybe.
## Lighter-weight building bricks
This crate aims at refining the `Rc` + `RefCell` solution by substituting both of them with `StaticRc` and `GhostCell`
respectively:
- `GhostCell` is a compile-time cell, splitting the aliasing compile-time checks to the zero-sized `GhostToken`.
- `StaticRc` is a compile-time reference counted pointer, so is _mostly_ free at run-time.
- One exception: joining 2 `StaticRc` requires checking that they both refer to the same allocation.
On the face of it, this seems fairly interesting:
- No memory overhead.
- No run-time overhead.
## And a catch.
There's a catch, though.
`GhostCell` is a straightforward replacement, `StaticRc` is a _bit_ more complicated. Typical implementations based on
`Rc` will clone it whenever necessary -- but cloning a `StaticRc` is impossible.
If you have split your `StaticRc` in halves, that is, you have 2 instances of `StaticRc<T, 1, 2>`, then you only have
those two instances. You can split one, but it changes its type. This makes _temporarily_ holding onto one more
instance of a reference-counted pointer... impossible. There's no temporary instance.
To solve this problem, the nodes of the `TripodList` and `TripodTree` contain one extra instance of a pointer, compared
to the typical implementation. That is, a node from a `TripodList` contains 3 pointers, and one from a `TripodTree`
contains 4 pointers.
That's the same memory overhead as a special-purpose `Rc` with no weak count. And mostly the same run-time overhead too
as deploying the _tripod_ pointer is a memory write, just as cloning a `Rc`, and retracting the _tripod_ pointer is
another memory write, just as destroying a `Rc`. It may be slightly more efficient, and linear logic keeps one honest...
It _may_ be possible to avoid this overhead altogether. `LinkedList` avoids it... and uses the experimental
`GhostCursor` instead. It's not clear whether `GhostCursor` is _quite_ sufficient to implement all the functionality of
a list, though. And then there's the _experimental_ issue...
## At least it's safe, no?
Mostly?
The core functionality of `GhostCell` and `StaticRc` are really strong contenders:
- `GhostCell` (the paper) was developed by Ralf Jung and co, and proven safe. The implementation hopefully is also
safe.
- `StaticRc` is really basic reference-counting, just at compile-time.
The core functionality, though, is also _slightly_ insufficient. This forces this crate to use extra, experimental
functionality from its 2 core crates, and those are much less proven:
- `static_rc::lift*` is at the core of this crate. None of the collections are too useful without it. Its core idea
_looks_ sound (scary eh?), though even if it is, the implementation may not be...
- `GhostCursor` is even more sketchy, safety-wise. If safe, it may allow writing the collections without an extra
_tripod_ pointer... May.
# Is ghost-collections really helpful then?
**Yes**.
## GhostCell is practical.
At the very least, this crate is a proof-of-concept that `GhostCell` is _really_ usable.
To the best of our knowledge, this is the first crate making extensive use of `GhostCell`, and there were some questions
as to whether it was possible to express algorithms with `GhostCell`. Having implemented a complete linked list and
binary tree around `GhostCell` I can confirm that it is **practical** enough.
Replacing `RefCell` by `GhostCell` means avoiding both the memory and run-time overhead of `RefCell`. That's a
significant advantage.
There are some ergonomic downsides, though:
- Using lifetime as a brand means that all the entire program needs to be wrapped within a closure.
- Having to pass the extra `GhostToken` everywhere means that many traits -- such as `Debug` -- cannot be implemented
on the collections.
Those were all foreseen, so no surprise there, but of course it's still annoying.
## StaticRc is practical.
This crate also proves that `StaticRc` works, although it is perhaps not the best tool for cyclic data structures.
## Test bed.
Finally, this crate provides a test bed for both of the above.
After putting them through their paces, I am happy to report that MIRI finds no issue when running the full test-suite.
# And beyond?
One interesting avenue of investigation is automatic translation of the current code, stripping out `StaticRc` and/or
`GhostCell`.
As long as:
- The current code is safe -- meaning, the 2 crates used are safe.
- The translation preserves safety.
Then this opens up the ability to write entirely safe code and automatically translate it into simpler (though unsafe)
code -- not unlike the work that compilers do.
Exciting, isn't it?
There is one difficulty, though, it's unclear whether the remove/split operations can be translated automatically:
- Merging 2 pools of nodes -- through `splice` -- is trivially safe: the result is a coarser grain.
- Splitting 1 pool of nodes into two, however, is not: the result is finer grain.
Today, the reference-counting and borrowing works _globally_, regardless of which pools of nodes a node belongs to.
However translating `StaticRc<GhostCell<T>, N, D>` into just `NonNull<T>` breaks this assumptions, and functional bugs
such as accidentally keeping a link between nodes across pools could lead to aliasing/lifetime issues.
_Note: and even though tracing could solve the issue, it would be linear in the number of elements to trace at best, so
would not make sense algorithmically._
# That's all folks!
And thanks for reading.
================================================
FILE: src/lib.rs
================================================
//! A repository of collections written entirely in safe, zero-cost, stable, Rust.
//!
//! # Safety
//!
//! This repository is built upon 2 crates:
//!
//! - `ghost-cell`: which provides safe borrow-checking of aliases, with zero runtime overhead.
//! - `static-rc`: which provides safe reference-counting of aliases, with zero runtime overhead.
//!
//! Additionally, this repository builds upon the `core` and `alloc` crates.
//!
//! The safety of this library depends, entirely, and only, on the safety of those 4 foundational libraries.
// Generic features.
#![cfg_attr(not(test), no_std)]
#![forbid(unsafe_code)]
// Lints.
#![deny(missing_docs)]
pub mod linked_list;
pub mod tripod_list;
pub mod tripod_tree;
================================================
FILE: src/linked_list/cursor.rs
================================================
use ghost_cell::GhostToken;
use super::{GhostNode, LinkedList};
#[cfg(feature = "experimental-ghost-cursor")]
use ghost_cell::GhostCursor;
#[cfg(feature = "experimental-ghost-cursor")]
use super::Node;
/// A Cursor over the LinkedList.
pub struct Cursor<'a, 'brand, T> {
token: &'a GhostToken<'brand>,
node: Option<&'a GhostNode<'brand, T>>,
}
impl<'a, 'brand, T> Cursor<'a, 'brand, T> {
/// Creates a new instance pointing to the front element of the list, if any.
pub fn new_front(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.0);
Self { token, node, }
}
/// Creates a new instance pointing to the back element of the list, if any.
pub fn new_back(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.1);
Self { token, node, }
}
/// Moves the cursor to the next element, if any.
///
/// If there is no next element, either because the list is empty, or because the current element is the back
/// element, then an error is returned.
pub fn move_next(&mut self) -> Result<(), ()> {
if let Some(node) = self.peek_next_node() {
self.node = Some(node);
Ok(())
} else {
Err(())
}
}
/// Moves the cursor to the previous element, if any.
///
/// If there is no previous element, either because the list is empty, or because the current element is the front
/// element, then an error is returned.
pub fn move_prev(&mut self) -> Result<(), ()> {
if let Some(node) = self.peek_prev_node() {
self.node = Some(node);
Ok(())
} else {
Err(())
}
}
/// Returns a reference to the current element, if any.
///
/// Unless the list is empty, there should always be a current element.
pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the next element, if any.
pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the next element, if any.
pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().map(|node| &node.borrow(self.token).value) }
// Internal: returns a reference to the next GhostNode.
fn peek_next_node(&self) -> Option<&'a GhostNode<'brand, T>> {
self.node?.borrow(self.token).next.as_ref().map(|n| &**n)
}
// Internal: returns a reference to the previous GhostNode.
fn peek_prev_node(&self) -> Option<&'a GhostNode<'brand, T>> {
self.node?.borrow(self.token).prev.as_ref().map(|n| &**n)
}
}
/// A mutable Cursor over a LinkedList.
#[cfg(feature = "experimental-ghost-cursor")]
pub struct CursorMut<'a, 'brand, T> {
inner: GhostCursor<'a, 'brand, Node<'brand, T>>,
}
#[cfg(feature = "experimental-ghost-cursor")]
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
/// Creates a new instance pointing to the front element of the list, if any.
pub fn new_front(token: &'a mut GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.0);
let inner = GhostCursor::new(token, node);
Self { inner, }
}
/// Creates a new instance pointing to the back element of the list, if any.
pub fn new_back(token: &'a mut GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.1);
let inner = GhostCursor::new(token, node);
Self { inner, }
}
/// Returns a read-only cursor pointing to the current element.
pub fn into_cursor(self) -> Cursor<'a, 'brand, T> {
let (token, node) = self.inner.into_parts();
Cursor { token, node, }
}
/// Moves the cursor to the next element, if any.
///
/// If there is no next element, either because the list is empty, or because the current element is the back
/// element, then an error is returned and the cursor is left unmodified.
pub fn move_next(&mut self) -> Result<(), ()> {
self.inner.move_mut(|node| node.next.as_ref().map(|n| &**n))
}
/// Moves the cursor to the previous element, if any.
///
/// If there is no previous element, either because the list is empty, or because the current element is the front
/// element, then an error is returned and the cursor is left unmodified.
pub fn move_prev(&mut self) -> Result<(), ()> {
self.inner.move_mut(|node| node.prev.as_ref().map(|n| &**n))
}
/// Returns a mutable reference to the current element, if any.
///
/// Unless the list is empty, there should always be a current element.
pub fn current(&mut self) -> Option<&mut T> { self.inner.borrow_mut().map(|node| &mut node.value) }
/// Returns a reference to the next element, if any.
///
/// # Deviation
///
/// In safe code, it is not possible to allow mutable access to another node than the one currently visited as this
/// other node could be the anchor of the current node to the stack.
pub fn peek_next(&self) -> Option<&T> {
let token = self.inner.token();
self.peek_next_node().map(|node| &node.borrow(token).value)
}
/// Returns a reference to the previous element, if any.
///
/// # Deviation
///
/// In safe code, it is not possible to allow mutable access to another node than the one currently visited as this
/// other node could be the anchor of the current node to the stack.
pub fn peek_prev(&self) -> Option<&T> {
let token = self.inner.token();
self.peek_prev_node().map(|node| &node.borrow(token).value)
}
// Internal: returns a reference to the next GhostNode.
fn peek_next_node(&self) -> Option<&GhostNode<'brand, T>> {
self.inner.borrow().and_then(|node| node.next.as_ref().map(|n| &**n))
}
// Internal: returns a reference to the previous GhostNode.
fn peek_prev_node(&self) -> Option<&GhostNode<'brand, T>> {
self.inner.borrow().and_then(|node| node.prev.as_ref().map(|n| &**n))
}
}
#[cfg(test)]
mod cursor_tests {
use std::fmt::Debug;
use super::super::tests::with_list;
use super::*;
#[track_caller]
fn cursor_assert_none<'a, 'brand, T>(cursor: &Cursor<'a, 'brand, T>)
where
T: Debug + Eq,
{
assert_eq!(None, cursor.current());
assert_eq!(None, cursor.peek_next());
assert_eq!(None, cursor.peek_prev());
}
#[test]
fn cursor_brush_front_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = Cursor::new_front(token, list);
cursor_assert_none(&cursor);
assert_eq!(Err(()), cursor.move_next());
cursor_assert_none(&cursor);
assert_eq!(Err(()), cursor.move_prev());
cursor_assert_none(&cursor);
});
}
#[test]
fn cursor_brush_back_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = Cursor::new_back(token, list);
cursor_assert_none(&cursor);
assert_eq!(Err(()), cursor.move_next());
cursor_assert_none(&cursor);
assert_eq!(Err(()), cursor.move_prev());
cursor_assert_none(&cursor);
});
}
#[test]
fn cursor_brush_move_next() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut cursor = Cursor::new_front(token, list);
assert_eq!(None, cursor.peek_prev().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(String::as_str));
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Ok(()), cursor.move_next());
assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("1"), cursor.current().map(String::as_str));
assert_eq!(Some("2"), cursor.peek_next().map(String::as_str));
assert_eq!(Ok(()), cursor.move_next());
assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("2"), cursor.current().map(String::as_str));
assert_eq!(Some("3"), cursor.peek_next().map(String::as_str));
assert_eq!(Ok(()), cursor.move_next());
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(String::as_str));
assert_eq!(None, cursor.peek_next());
assert_eq!(Err(()), cursor.move_next());
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(String::as_str));
assert_eq!(None, cursor.peek_next());
assert_eq!(Err(()), cursor.move_next());
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(String::as_str));
assert_eq!(None, cursor.peek_next());
});
}
#[test]
fn cursor_brush_move_prev() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut cursor = Cursor::new_back(token, list);
assert_eq!(None, cursor.peek_next().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(String::as_str));
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Ok(()), cursor.move_prev());
assert_eq!(Some("3"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("2"), cursor.current().map(String::as_str));
assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str));
assert_eq!(Ok(()), cursor.move_prev());
assert_eq!(Some("2"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("1"), cursor.current().map(String::as_str));
assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str));
assert_eq!(Ok(()), cursor.move_prev());
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(String::as_str));
assert_eq!(None, cursor.peek_prev());
assert_eq!(Err(()), cursor.move_prev());
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(String::as_str));
assert_eq!(None, cursor.peek_prev());
assert_eq!(Err(()), cursor.move_prev());
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(String::as_str));
assert_eq!(None, cursor.peek_prev());
});
}
} // mod cursor_tests
#[cfg(all(test, feature = "experimental-ghost-cursor"))]
mod cursor_mut_tests {
use std::fmt::Debug;
use super::super::tests::with_list;
use super::*;
#[track_caller]
fn cursor_mut_assert_none<'a, 'brand, T>(cursor: &mut CursorMut<'a, 'brand, T>)
where
T: Debug + Eq,
{
assert_eq!(None, cursor.current());
assert_eq!(None, cursor.peek_next());
assert_eq!(None, cursor.peek_prev());
}
#[test]
fn cursor_mut_brush_front_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
cursor_mut_assert_none(&mut cursor);
assert_eq!(Err(()), cursor.move_next());
cursor_mut_assert_none(&mut cursor);
assert_eq!(Err(()), cursor.move_prev());
cursor_mut_assert_none(&mut cursor);
});
}
#[test]
fn cursor_mut_brush_back_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = CursorMut::new_back(token, list);
cursor_mut_assert_none(&mut cursor);
assert_eq!(Err(()), cursor.move_next());
cursor_mut_assert_none(&mut cursor);
assert_eq!(Err(()), cursor.move_prev());
cursor_mut_assert_none(&mut cursor);
});
}
#[test]
fn cursor_mut_brush_move_next() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut cursor = CursorMut::new_front(token, list);
assert_eq!(None, cursor.peek_prev().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(|s| &**s));
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Ok(()), cursor.move_next());
assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("1"), cursor.current().map(|s| &**s));
assert_eq!(Some("2"), cursor.peek_next().map(String::as_str));
assert_eq!(Ok(()), cursor.move_next());
assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("2"), cursor.current().map(|s| &**s));
assert_eq!(Some("3"), cursor.peek_next().map(String::as_str));
assert_eq!(Ok(()), cursor.move_next());
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(|s| &**s));
assert_eq!(None, cursor.peek_next());
assert_eq!(Err(()), cursor.move_next());
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(|s| &**s));
assert_eq!(None, cursor.peek_next());
assert_eq!(Err(()), cursor.move_next());
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(|s| &**s));
assert_eq!(None, cursor.peek_next());
});
}
#[test]
fn cursor_mut_brush_move_prev() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut cursor = CursorMut::new_back(token, list);
assert_eq!(None, cursor.peek_next().map(String::as_str));
assert_eq!(Some("3"), cursor.current().map(|s| &**s));
assert_eq!(Some("2"), cursor.peek_prev().map(String::as_str));
assert_eq!(Ok(()), cursor.move_prev());
assert_eq!(Some("3"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("2"), cursor.current().map(|s| &**s));
assert_eq!(Some("1"), cursor.peek_prev().map(String::as_str));
assert_eq!(Ok(()), cursor.move_prev());
assert_eq!(Some("2"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("1"), cursor.current().map(|s| &**s));
assert_eq!(Some("0"), cursor.peek_prev().map(String::as_str));
assert_eq!(Ok(()), cursor.move_prev());
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(|s| &**s));
assert_eq!(None, cursor.peek_prev());
assert_eq!(Err(()), cursor.move_prev());
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(|s| &**s));
assert_eq!(None, cursor.peek_prev());
assert_eq!(Err(()), cursor.move_prev());
assert_eq!(Some("1"), cursor.peek_next().map(String::as_str));
assert_eq!(Some("0"), cursor.current().map(|s| &**s));
assert_eq!(None, cursor.peek_prev());
});
}
} // mod cursor_mut_tests
================================================
FILE: src/linked_list/iter.rs
================================================
use ghost_cell::GhostToken;
use super::{GhostNode, LinkedList};
/// An iterator over a LinkedList, self-sufficient once created as it carries its own token.
pub struct Iter<'a, 'brand, T> {
token: &'a GhostToken<'brand>,
head_tail: Option<(&'a GhostNode<'brand, T>, &'a GhostNode<'brand, T>)>,
}
impl<'a, 'brand, T> Iter<'a, 'brand, T> {
/// Creates a new instance of the Iter.
pub fn new(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T>) -> Self {
let head_tail = list.head_tail.as_ref().map(|head_tail| {
(&*head_tail.0, &*head_tail.1)
});
Self { token, head_tail, }
}
}
impl<'a, 'brand, T> Iterator for Iter<'a, 'brand, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let (head, tail) = self.head_tail.take()?;
let node = head.borrow(self.token);
if head as *const _ != tail as *const _ {
self.head_tail = node.next.as_ref().map(|n| {
let n: &'a GhostNode<'_, _> = &*n;
(n, tail)
});
} else {
self.head_tail = None;
}
Some(&node.value)
}
}
impl<'a, 'brand, T> DoubleEndedIterator for Iter<'a, 'brand, T> {
fn next_back(&mut self) -> Option<Self::Item> {
let (head, tail) = self.head_tail.take()?;
let node = tail.borrow(self.token);
if head as *const _ != tail as *const _ {
self.head_tail = node.prev.as_ref().map(|n| {
let n: &'a GhostNode<'_, _> = &*n;
(head, n)
});
} else {
self.head_tail = None;
}
Some(&node.value)
}
}
#[cfg(test)]
mod tests {
use super::super::tests::with_list;
use super::*;
#[test]
fn empty() {
with_list::<String, _, _>(vec!(), |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(None, iterator.next());
assert_eq!(None, iterator.next_back());
});
}
#[test]
fn forward() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("0"), iterator.next().map(String::as_str));
assert_eq!(Some("1"), iterator.next().map(String::as_str));
assert_eq!(Some("2"), iterator.next().map(String::as_str));
assert_eq!(Some("3"), iterator.next().map(String::as_str));
assert_eq!(None, iterator.next());
});
}
#[test]
fn backward() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("3"), iterator.next_back().map(String::as_str));
assert_eq!(Some("2"), iterator.next_back().map(String::as_str));
assert_eq!(Some("1"), iterator.next_back().map(String::as_str));
assert_eq!(Some("0"), iterator.next_back().map(String::as_str));
assert_eq!(None, iterator.next_back());
});
}
#[test]
fn alternate() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("0"), iterator.next().map(String::as_str));
assert_eq!(Some("3"), iterator.next_back().map(String::as_str));
assert_eq!(Some("1"), iterator.next().map(String::as_str));
assert_eq!(Some("2"), iterator.next_back().map(String::as_str));
assert_eq!(None, iterator.next());
assert_eq!(None, iterator.next_back());
});
}
#[test]
fn alternate_other() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("3"), iterator.next_back().map(String::as_str));
assert_eq!(Some("0"), iterator.next().map(String::as_str));
assert_eq!(Some("2"), iterator.next_back().map(String::as_str));
assert_eq!(Some("1"), iterator.next().map(String::as_str));
assert_eq!(None, iterator.next_back());
assert_eq!(None, iterator.next());
});
}
} // mod tests
================================================
FILE: src/linked_list.rs
================================================
//! A LinkedList, with externally supplied token.
//!
//! A number of operations normally implemented by traits cannot be successfully implemented on this collection due to
//! the requirement of supplying the GhostToken externally.
mod iter;
mod cursor;
pub use iter::Iter;
pub use cursor::Cursor;
#[cfg(feature = "experimental-ghost-cursor")]
pub use cursor::CursorMut;
use ghost_cell::{GhostCell, GhostToken};
use static_rc::StaticRc;
#[cfg(feature = "experimental-ghost-cursor")]
use core::mem;
#[cfg(feature = "experimental-ghost-cursor")]
use ghost_cell::GhostCursor;
/// A safe implementation of a linked-list build upon `GhostCell` and `StaticRc`.
///
/// The future is now!
pub struct LinkedList<'brand, T> {
head_tail: Option<(HalfNodePtr<'brand, T>, HalfNodePtr<'brand, T>)>,
}
impl<'brand, T> LinkedList<'brand, T> {
/// Creates an empty list.
pub const fn new() -> Self { Self { head_tail: None } }
/// Creates an iterator over self.
pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'brand, T> {
Iter::new(token, self)
}
/// Creates a cursor pointing to the front element, if any.
pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> {
Cursor::new_front(token, self)
}
/// Creates a cursor pointing to the back element, if any.
pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> {
Cursor::new_back(token, self)
}
/// Returns whether the list is empty, or not.
pub fn is_empty(&self) -> bool { self.head_tail.is_none() }
/// Returns the number of elements of the list.
///
/// # Complexity
///
/// This operation is O(N).
///
/// Maintaining a separate length field is incompatible with arbitrary splits at a given cursor position.
pub fn len(&self, token: &GhostToken<'brand>) -> usize { self.iter(token).count() }
/// Clears the list, making it empty.
///
/// # Complexity
///
/// This operation is O(N), where N is the number of elements.
pub fn clear(&mut self, token: &mut GhostToken<'brand>) {
while let Some(_) = self.pop_back(token) {}
}
/// Returns a reference to the first element, if any.
pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
self.head_tail.as_ref().map(|(head, _)| {
&head.borrow(token).value
})
}
/// Returns a mutable reference to the first element, if any.
pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> {
self.head_tail.as_mut().map(move |(head, _)| {
&mut head.borrow_mut(token).value
})
}
/// Returns a reference to the last element, if any.
pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
self.head_tail.as_ref().map(|(_, tail)| {
&tail.borrow(token).value
})
}
/// Returns a mutable reference to the last element, if any.
pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> {
self.head_tail.as_mut().map(move |(_, tail)| {
&mut tail.borrow_mut(token).value
})
}
/// Prepends the given element at the front of the list.
pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) {
let (one, two) = Self::new_halves(value);
let head_tail = if let Some((head, tail)) = self.head_tail.take() {
head.borrow_mut(token).prev = Some(one);
two.borrow_mut(token).next = Some(head);
(two, tail)
} else {
(one, two)
};
self.head_tail = Some(head_tail);
}
/// Removes and returns the first element of the list, if any.
pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
let (head, tail) = self.head_tail.take()?;
if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) {
return Some(Self::into_inner(head, tail));
}
let next = head.borrow_mut(token).next.take()
.expect("Non-tail should have a next node");
let other_head = next.borrow_mut(token).prev.take()
.expect("Non-head should have a previous node");
self.head_tail = Some((next, tail));
Some(Self::into_inner(head, other_head))
}
/// Appends the given element at the back of the list.
pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) {
let (one, two) = Self::new_halves(value);
let head_tail = if let Some((head, tail)) = self.head_tail.take() {
tail.borrow_mut(token).next = Some(one);
two.borrow_mut(token).prev = Some(tail);
(head, two)
} else {
(one, two)
};
self.head_tail = Some(head_tail);
}
/// Removes and returns the last element of the list, if any.
pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
let (head, tail) = self.head_tail.take()?;
if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) {
return Some(Self::into_inner(head, tail));
}
let prev = tail.borrow_mut(token).prev.take()
.expect("Non-head should have a previous node");
let other_tail = prev.borrow_mut(token).next.take()
.expect("Non-tail should have a next node");
self.head_tail = Some((head, prev));
Some(Self::into_inner(tail, other_tail))
}
fn new_halves(value: T) -> (HalfNodePtr<'brand, T>, HalfNodePtr<'brand, T>) {
let node = Node { value, prev: None, next: None, };
let full = FullNodePtr::new(GhostNode::new(node));
StaticRc::split::<1, 1>(full)
}
fn into_inner(left: HalfNodePtr<'brand, T>, right: HalfNodePtr<'brand, T>) -> T {
let full = FullNodePtr::join(left, right);
let ghost_cell = FullNodePtr::into_inner(full);
let node = GhostNode::into_inner(ghost_cell);
// If the node still has a prev and next, they are leaked.
debug_assert!(node.prev.is_none());
debug_assert!(node.next.is_none());
node.value
}
}
#[cfg(feature = "experimental-ghost-cursor")]
impl<'brand, T> LinkedList<'brand, T> {
/// Appends all elements of `other`, in order, to the back of this list.
///
/// After this call, `other` is empty
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn append(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) {
let other_ht = if let Some(other_ht) = other.head_tail.take() {
other_ht
} else {
return;
};
if let Some(self_ht) = self.head_tail.take() {
let (new_head, mid_tail) = self_ht;
let (mid_head, new_tail) = other_ht;
mid_tail.borrow_mut(token).next = Some(mid_head);
let previous = static_rc::lift_with_mut(Some(mid_tail), token, |mid_tail: &Option<HalfNodePtr<'brand, T>>, token| {
let mut cursor = GhostCursor::new(token, Some(mid_tail.as_ref().unwrap()));
cursor.move_mut(|mid_tail| mid_tail.next.as_ref().map(core::borrow::Borrow::borrow))
.expect("mid_tail.next was just set!");
let mid_head = cursor.into_inner().expect("mid_head was just computed!");
&mut mid_head.prev
});
debug_assert!(previous.is_none(), "mid_head should not have had any previous!");
self.head_tail = Some((new_head, new_tail));
} else {
self.head_tail = Some(other_ht);
}
}
/// Prepends all elements of `other`, in order, to the front of this list.
///
/// After this call, `other` is empty
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn prepend(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) {
other.append(self, token);
mem::swap(self, other);
}
/// Creates a cursor pointing to the front element, if any.
pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> {
CursorMut::new_front(token, self)
}
/// Creates a cursor pointing to the back element, if any.
pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> {
CursorMut::new_back(token, self)
}
/// Splits the list in two at the given index. Returns a list containing everything after the given index, inclusive.
///
/// Returns None if the given index is out of bounds.
///
/// # Complexity
///
/// This operations is O(min(`at`, N)), where N is the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -> Option<Self> {
// This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity.
let mut head = LinkedList::new();
for _ in 0..at {
let element = if let Some(element) = self.pop_front(token) {
element
} else {
// Restore popped elements, and pretend that nothing happened.
self.prepend(&mut head, token);
return None;
};
head.push_back(element, token);
}
mem::swap(self, &mut head);
Some(head)
}
/// Removes the element at the given index, and returns it, if the index is within bounds.
///
/// # Complexity
///
/// This operations is O(min(`at`, N)), where N is the number of elements.
///
/// No memory allocation occurs, and a single memory deallocation occurs.
pub fn remove(&mut self, at: usize, token: &mut GhostToken<'brand>) -> Option<T> {
// This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity.
let mut head = LinkedList::new();
for _ in 0..at {
let element = if let Some(element) = self.pop_front(token) {
element
} else {
// Restore popped elements, and pretend that nothing happened.
self.prepend(&mut head, token);
return None;
};
head.push_back(element, token);
}
let result = self.pop_front(token);
// Restore popped elements!
self.prepend(&mut head, token);
result
}
}
impl<'brand, T> Default for LinkedList<'brand, T> {
fn default() -> Self { Self::new() }
}
//
// Implementation
//
struct Node<'brand, T> {
value: T,
prev: Option<HalfNodePtr<'brand, T>>,
next: Option<HalfNodePtr<'brand, T>>,
}
type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>;
type HalfNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 1, 2>;
type FullNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 2, 2>;
#[cfg(test)]
mod tests {
use std::panic::{self, AssertUnwindSafe};
use super::*;
pub(crate) fn with_list<T, R, F>(initial: Vec<T>, fun: F) -> R
where
F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut LinkedList<'brand, T>) -> R,
{
GhostToken::new(|mut token| {
let mut list = LinkedList::new();
for value in initial {
list.push_back(value, &mut token);
}
let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut list)));
list.clear(&mut token);
result.expect("No Panic")
})
}
} // mod tests
================================================
FILE: src/tripod_list/cursor.rs
================================================
use core::mem;
use ghost_cell::GhostToken;
use super::{GhostNode, Iter, ThirdNodePtr, TripodList};
/// A Cursor over the TripodList.
pub struct Cursor<'a, 'brand, T> {
token: &'a GhostToken<'brand>,
list: &'a TripodList<'brand, T>,
node: Option<&'a GhostNode<'brand, T>>,
index: usize,
}
impl<'a, 'brand, T> Cursor<'a, 'brand, T> {
/// Creates a new instance pointing to the front element of the list, if any.
pub fn new_front(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.0);
Self { token, index: 0, node, list, }
}
/// Creates a new instance pointing to the back element of the list, if any.
pub fn new_back(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| &*head_tail.1);
let index = list.len().checked_sub(1).unwrap_or(0);
Self { token, index, node, list, }
}
/// Returns a triplet (iterator, iterator) in which:
///
/// - The first iterator is an iterator over all the elements before the cursor.
/// - The second iterator is an iterator over all the elements after the cursor.
///
/// If the cursor currently points to the "twilight" non-element, all elements are considered to be before it.
pub fn before_after(&self) -> (Iter<'a, 'brand, T>, Iter<'a, 'brand, T>) {
if let Some(_) = self.node {
let (head, tail) = self.list.head_tail.as_ref().expect("non-empty, node being non-null");
let prev = self.peek_prev_node();
let next = self.peek_next_node();
let before = prev.map(|prev| (&**head, prev));
let after = next.map(|next| (next, &**tail));
(Iter::slice(self.token, before), Iter::slice(self.token, after))
} else {
(self.list.iter(self.token), Iter::empty(self.token))
}
}
/// Returns the index of the element pointed to by the cursor in the list.
///
/// If the cursor currently points to the "twilight" non-element, returns None.
pub fn index(&self) -> Option<usize> { self.node.map(|_| self.index) }
/// Moves the cursor to the next element, if any.
///
/// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the front
/// and back element.
pub fn move_next(&mut self) {
if self.node.is_some() {
self.index += 1;
} else {
self.index = 0;
}
self.node = self.peek_next_node();
}
/// Moves the cursor to the previous element, if any.
///
/// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the front
/// and back element.
pub fn move_prev(&mut self) {
if self.node.is_some() {
self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len());
} else {
self.index = self.list.len().checked_sub(1).unwrap_or(0);
}
self.node = self.peek_prev_node();
}
/// Returns a reference to the current element, if any.
pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the next element, if any.
pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the previous element, if any.
pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().map(|node| &node.borrow(self.token).value) }
// Internal: returns a reference to the next GhostNode.
fn peek_next_node(&self) -> Option<&'a GhostNode<'brand, T>> {
if let Some(node) = self.node {
node.borrow(self.token).next.as_ref().map(|n| &**n)
} else {
self.list.front_node()
}
}
// Internal: returns a reference to the previous GhostNode.
fn peek_prev_node(&self) -> Option<&'a GhostNode<'brand, T>> {
if let Some(node) = self.node {
node.borrow(self.token).prev.as_ref().map(|n| &**n)
} else {
self.list.back_node()
}
}
}
impl<'a, 'brand, T> Clone for Cursor<'a, 'brand, T> {
fn clone(&self) -> Self { *self }
}
impl<'a, 'brand, T> Copy for Cursor<'a, 'brand, T> {}
/// A mutable cursor over the TripodList.
///
/// A mutable cursor allows freely moving back-and-forth amongst the elements of the list, and mutate the list as any
/// point.
///
/// Cursors index the list in a logically circular way. To accomodate this, there is a "twilight" non-element
/// represented by `None` between the head and tail of the list.
///
/// # Warning.
///
/// This cursor mutates the list as it iterates. Although the list is left in a safe state by construction, forgoing the
/// drop of this cursor -- unless it points to the "twilight" non-element -- will leave the list in an unusable state.
///
/// Any further mutable operation on the list, including calling `clear`, is at risk of panicking.
pub struct CursorMut<'a, 'brand, T> {
token: &'a mut GhostToken<'brand>,
list: &'a mut TripodList<'brand, T>,
node: Option<ThirdNodePtr<'brand, T>>,
index: usize,
}
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
/// Creates a new instance pointing to the front element of the list, if any.
pub fn new_front(token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| head_tail.0.borrow(token).deploy());
Self { token, index: 0, node, list, }
}
/// Creates a new instance pointing to the back element of the list, if any.
pub fn new_back(token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, T>) -> Self {
let node = list.head_tail.as_ref().map(|head_tail| head_tail.1.borrow(token).deploy());
let index = list.len().checked_sub(1).unwrap_or(0);
Self { token, index, node, list, }
}
/// Returns a read-only cursor pointing to the current element.
pub fn as_cursor(&self) -> Cursor<'_, 'brand, T> {
let token = &*self.token;
let index = self.index;
let node = self.node.as_ref().map(|rc| &**rc);
let list = &*self.list;
Cursor { token, index, node, list, }
}
/// Returns the index of the element pointed to by the cursor in the list.
///
/// If the cursor currently points to the "twilight" non-element, returns None.
pub fn index(&self) -> Option<usize> { self.node.as_ref().map(|_| self.index) }
/// Moves the cursor to the next element, if any.
///
/// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the front
/// and back element.
pub fn move_next(&mut self) {
let new_tripod = self.peek_next_node().map(|node| node.borrow(self.token).deploy());
if let Some(tripod) = mem::replace(&mut self.node, new_tripod) {
super::retract(tripod, self.token);
self.index += 1;
} else {
self.index = 0;
}
}
/// Moves the cursor to the previous element, if any.
///
/// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the front
/// and back element.
pub fn move_prev(&mut self) {
let new_tripod = self.peek_prev_node().map(|node| node.borrow(self.token).deploy());
if let Some(tripod) = mem::replace(&mut self.node, new_tripod) {
super::retract(tripod, self.token);
self.index = self.index.checked_sub(1).unwrap_or(0);
} else {
self.index = self.list.len().checked_sub(1).unwrap_or(0);
}
}
/// Returns a mutable reference to the current element, if any.
pub fn current(&mut self) -> Option<&mut T> {
let tripod = self.node.as_ref()?;
Some(&mut tripod.borrow_mut(self.token).value)
}
/// Returns a reference to the next element, if any.
///
/// # Deviation
///
/// It is not possible to return a mutable reference, safely.
pub fn peek_next(&self) -> Option<&T> { self.peek_next_node().map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the previous element, if any.
///
/// # Deviation
///
/// It is not possible to return a mutable reference, safely.
pub fn peek_prev(&self) -> Option<&T> { self.peek_prev_node().map(|node| &node.borrow(self.token).value) }
// Internal: returns a reference to the next GhostNode.
fn peek_next_node(&self) -> Option<&GhostNode<'brand, T>> {
if let Some(node) = self.node.as_ref() {
node.borrow(self.token).next.as_ref().map(|n| &**n)
} else {
self.list.front_node()
}
}
// Internal: returns a reference to the previous GhostNode.
fn peek_prev_node(&self) -> Option<&GhostNode<'brand, T>> {
if let Some(node) = self.node.as_ref() {
node.borrow(self.token).prev.as_ref().map(|n| &**n)
} else {
self.list.back_node()
}
}
}
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
/// Inserts a new element in the list after the current one.
///
/// If the cursor is pointing at the "twilight" non-element, then the new element is inserted at the front of the
/// list.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// One memory allocation and no deallocation occur.
pub fn insert_after(&mut self, item: T) {
let mut list = TripodList::new();
list.push_front(item, self.token);
self.splice_after(&mut list);
debug_assert!(list.is_empty());
}
/// Inserts a new element in the list before the current one.
///
/// If the cursor is pointing at the "twilight" non-element, then the new element is inserted at the back of the
/// list.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// One memory allocation and no deallocation occur.
pub fn insert_before(&mut self, item: T) {
let mut list = TripodList::new();
list.push_back(item, self.token);
self.splice_before(&mut list);
debug_assert!(list.is_empty());
}
/// Removes the current element from the list, and return it.
///
/// If the cursor is pointing to the "twilight" non-element, then None is returned and the cursor is left unmodified.
/// Otherwise, the element is returned and the cursor is moved to the next element.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn remove_current(&mut self) -> Option<T> {
let mut list = self.remove_current_as_list()?;
debug_assert_eq!(1, list.len());
list.pop_front(self.token)
}
/// Removes the current element from the list, and return it as a list of its own.
///
/// If the cursor is pointing to the "twilight" non-element, then None is returned and the cursor is left unmodified.
/// Otherwise, the element is returned and the cursor is moved to the next element.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn remove_current_as_list(&mut self) -> Option<TripodList<'brand, T>> {
let node = self.node.take()?;
let (head, tail) = self.list.head_tail.take()?;
let prev = node.borrow_mut(self.token).prev.take();
let next = node.borrow_mut(self.token).next.take();
let (new_head_tail, result_head_tail, next_node) = match (prev, next) {
// `node` is in the middle of the list, gotta splice the two bits together.
(Some(prev), Some(next)) => {
let next_node = next.borrow(self.token).deploy();
let result_head = prev.borrow_mut(self.token).next.replace(next).expect("node.prev.next == node");
let result_tail = next_node.borrow_mut(self.token).prev.replace(prev).expect("node.next.prev == node");
(Some((head, tail)), Some((result_head, result_tail)), Some(next_node))
},
// `node` is the current head of the list.
(None, Some(next)) => {
let next_node = next.borrow(self.token).deploy();
let result_tail = next.borrow_mut(self.token).prev.take().expect("node.next.prev == node");
(Some((next, tail)), Some((head, result_tail)), Some(next_node))
},
// `node` is the current tail of the list.
(Some(prev), None) => {
let result_head = prev.borrow_mut(self.token).next.take().expect("node.prev.next == node");
(Some((head, prev)), Some((result_head, tail)), None)
},
// `node` is the only element of the list.
(None, None) => {
(None, Some((head, tail)), None)
}
};
super::retract(node, self.token);
self.node = next_node;
self.list.length -= 1;
self.list.head_tail = new_head_tail;
Some(TripodList { length: 1, head_tail: result_head_tail })
}
/// Inserts the elements from the given list after the current one.
///
/// If the cursor is pointing at the "twilight" non-element, then the new elements are inserted at the front of the
/// list.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn splice_after(&mut self, other: &mut TripodList<'brand, T>) {
if let Some(node) = self.node.as_ref() {
let (other_head, other_tail) = if let Some(other_ht) = other.head_tail.take() {
other_ht
} else {
return;
};
let other_head_tripod = other_head.borrow(self.token).deploy();
if let Some(previous_next) = node.borrow_mut(self.token).next.replace(other_head) {
let previous_next_tripod = previous_next.borrow(self.token).deploy();
other_tail.borrow_mut(self.token).next = Some(previous_next);
let previous_node = previous_next_tripod.borrow_mut(self.token).prev.replace(other_tail);
super::retract(previous_next_tripod, self.token);
debug_assert!(previous_node.is_some(), "node.next.prev == node");
other_head_tripod.borrow_mut(self.token).prev = previous_node;
super::retract(other_head_tripod, self.token);
} else {
let (head, tail) = self.list.head_tail.take().expect("Non-empty since self.node is non-null!");
other_head_tripod.borrow_mut(self.token).prev = Some(tail);
super::retract(other_head_tripod, self.token);
self.list.head_tail = Some((head, other_tail));
}
self.list.length += other.length;
other.length = 0;
} else {
self.list.prepend(other, self.token);
}
}
/// Inserts the elements from the given list before the current one.
///
/// If the cursor is pointing at the "twilight" non-element, then the new elements are inserted at the back of the
/// list.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn splice_before(&mut self, other: &mut TripodList<'brand, T>) {
if let Some(node) = self.node.as_ref() {
let (other_head, other_tail) = if let Some(other_ht) = other.head_tail.take() {
other_ht
} else {
return;
};
let other_tail_tripod = other_tail.borrow(self.token).deploy();
if let Some(previous_prev) = node.borrow_mut(self.token).prev.replace(other_tail) {
let previous_prev_tripod = previous_prev.borrow(self.token).deploy();
other_head.borrow_mut(self.token).prev = Some(previous_prev);
let previous_node = previous_prev_tripod.borrow_mut(self.token).next.replace(other_head);
super::retract(previous_prev_tripod, self.token);
debug_assert!(previous_node.is_some(), "node.prev.next == node");
other_tail_tripod.borrow_mut(self.token).next = previous_node;
super::retract(other_tail_tripod, self.token);
} else {
let (head, tail) = self.list.head_tail.take().expect("Non-empty since self.node is non-null!");
other_tail_tripod.borrow_mut(self.token).next = Some(head);
super::retract(other_tail_tripod, self.token);
self.list.head_tail = Some((other_head, tail));
}
self.list.length += other.length;
self.index += other.length;
other.length = 0;
} else {
self.list.append(other, self.token);
}
}
/// Splits the list into two after the current element.
///
/// If the cursor is pointing at the "twilight" non-element, then the entire contents of the list are moved.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn split_after(&mut self) -> TripodList<'brand, T> {
if let Some(node) = &self.node {
let next = node.borrow_mut(self.token).next.take();
// node is not the tail of the current list.
if let Some(next) = next {
let (head, tail) = self.list.head_tail.take().expect("non-empty, node is non-null!");
let new_tail = next.borrow_mut(self.token).prev.take().expect("node.next.prev == node");
let remaining_length = self.index + 1;
let result_length = self.list.length - remaining_length;
self.list.length = remaining_length;
self.list.head_tail = Some((head, new_tail));
TripodList { length: result_length, head_tail: Some((next, tail)) }
} else {
TripodList::new()
}
} else {
mem::replace(self.list, TripodList::new())
}
}
/// Splits the list into two before the current element.
///
/// If the cursor is pointing at the "twilight" non-element, then the entire contents of the list are moved.
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn split_before(&mut self) -> TripodList<'brand, T> {
if let Some(node) = &self.node {
let prev = node.borrow_mut(self.token).prev.take();
// node is not the head of the current list.
if let Some(prev) = prev {
let (head, tail) = self.list.head_tail.take().expect("non-empty, node is non-null!");
let new_head = prev.borrow_mut(self.token).next.take().expect("node.prev.next == node");
let result_length = self.index;
let remaining_length = self.list.length - result_length;
self.index = 0;
self.list.length = remaining_length;
self.list.head_tail = Some((new_head, tail));
TripodList { length: result_length, head_tail: Some((head, prev)) }
} else {
TripodList::new()
}
} else {
mem::replace(self.list, TripodList::new())
}
}
}
impl<'a, 'brand, T> Drop for CursorMut<'a, 'brand, T> {
fn drop(&mut self) {
if let Some(tripod) = self.node.take() {
super::retract(tripod, self.token);
}
}
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use super::super::tests::*;
use super::*;
#[track_caller]
fn assert_none<'a, 'brand, T>(cursor: Cursor<'a, 'brand, T>)
where
T: Debug + Eq,
{
assert_eq!(None, cursor.index());
assert_eq!(None, cursor.current());
assert_eq!(None, cursor.peek_next());
assert_eq!(None, cursor.peek_prev());
}
#[track_caller]
fn assert_cursor(before: &[&str], current: &str, after: &[&str], cursor: Cursor<'_, '_, String>) {
assert_eq!(Some(before.len()), cursor.index());
assert_eq!(before.last().copied(), cursor.peek_prev().map(String::as_str));
assert_eq!(Some(current), cursor.current().map(String::as_str));
assert_eq!(after.first().copied(), cursor.peek_next().map(String::as_str));
let (actual_before, actual_after) = cursor.before_after();
assert_eq!(before, collect(actual_before));
assert_eq!(after, collect(actual_after));
}
#[track_caller]
fn assert_twilight(before: &[&str], cursor: Cursor<'_, '_, String>) {
assert_eq!(None, cursor.index());
assert_eq!(before.last().copied(), cursor.peek_prev().map(String::as_str));
assert_eq!(None, cursor.current().map(String::as_str));
assert_eq!(before.first().copied(), cursor.peek_next().map(String::as_str));
let (actual_before, actual_after) = cursor.before_after();
let (actual_before, actual_after) = (collect(actual_before), collect(actual_after));
assert_eq!(before, actual_before);
assert!(actual_after.is_empty(), "{:?}", actual_after);
}
// Creates a cursor at the specified index.
fn place_cursor<'a, 'brand>(token: &'a mut GhostToken<'brand>, list: &'a mut TripodList<'brand, String>, at: usize)
-> CursorMut<'a, 'brand, String>
{
assert!(at <= list.len());
let mut cursor = CursorMut::new_front(token, list);
for _ in 0..at {
cursor.move_next();
}
cursor
}
#[test]
fn cursor_front_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = Cursor::new_front(token, list);
assert_none(cursor);
cursor.move_next();
assert_none(cursor);
cursor.move_prev();
assert_none(cursor);
});
}
#[test]
fn cursor_back_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = Cursor::new_back(token, list);
assert_none(cursor);
cursor.move_next();
assert_none(cursor);
cursor.move_prev();
assert_none(cursor);
});
}
#[test]
fn cursor_move_next() {
with_list(create(0..4), |token, list| {
let mut cursor = Cursor::new_front(token, list);
assert_cursor(&[], "0", &["1", "2", "3"], cursor);
cursor.move_next();
assert_cursor(&["0"], "1", &["2", "3"], cursor);
cursor.move_next();
assert_cursor(&["0", "1"], "2", &["3"], cursor);
cursor.move_next();
assert_cursor(&["0", "1", "2"], "3", &[], cursor);
cursor.move_next();
assert_twilight(&["0", "1", "2", "3"], cursor);
cursor.move_next();
assert_cursor(&[], "0", &["1", "2", "3"], cursor);
});
}
#[test]
fn cursor_move_prev() {
with_list(create(0..4), |token, list| {
let mut cursor = Cursor::new_back(token, list);
assert_cursor(&["0", "1", "2"], "3", &[], cursor);
cursor.move_prev();
assert_cursor(&["0", "1"], "2", &["3"], cursor);
cursor.move_prev();
assert_cursor(&["0"], "1", &["2", "3"], cursor);
cursor.move_prev();
assert_cursor(&[], "0", &["1", "2", "3"], cursor);
cursor.move_prev();
assert_twilight(&["0", "1", "2", "3"], cursor);
cursor.move_prev();
assert_cursor(&["0", "1", "2"], "3", &[], cursor);
});
}
#[test]
fn cursor_mut_front_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
assert_none(cursor.as_cursor());
cursor.move_next();
assert_none(cursor.as_cursor());
cursor.move_prev();
assert_none(cursor.as_cursor());
});
}
#[test]
fn cursor_mut_back_empty() {
// Test all functions on empty list.
with_list::<String, _, _>(vec!(), |token, list| {
let mut cursor = CursorMut::new_back(token, list);
assert_none(cursor.as_cursor());
cursor.move_next();
assert_none(cursor.as_cursor());
cursor.move_prev();
assert_none(cursor.as_cursor());
});
}
#[test]
fn cursor_mut_move_next() {
with_list(create(0..4), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
assert_cursor(&[], "0", &["1", "2", "3"], cursor.as_cursor());
cursor.move_next();
assert_cursor(&["0"], "1", &["2", "3"], cursor.as_cursor());
cursor.move_next();
assert_cursor(&["0", "1"], "2", &["3"], cursor.as_cursor());
cursor.move_next();
assert_cursor(&["0", "1", "2"], "3", &[], cursor.as_cursor());
cursor.move_next();
assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor());
cursor.move_next();
assert_cursor(&[], "0", &["1", "2", "3"], cursor.as_cursor());
});
}
#[test]
fn cursor_mut_move_prev() {
with_list(create(0..4), |token, list| {
let mut cursor = CursorMut::new_back(token, list);
assert_cursor(&["0", "1", "2"], "3", &[], cursor.as_cursor());
cursor.move_prev();
assert_cursor(&["0", "1"], "2", &["3"], cursor.as_cursor());
cursor.move_prev();
assert_cursor(&["0"], "1", &["2", "3"], cursor.as_cursor());
cursor.move_prev();
assert_cursor(&[], "0", &["1", "2", "3"], cursor.as_cursor());
cursor.move_prev();
assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor());
cursor.move_prev();
assert_cursor(&["0", "1", "2"], "3", &[], cursor.as_cursor());
});
}
#[track_caller]
fn assert_insert_after(list: Vec<String>, element: String, at: usize, before: &[&str], current: &str, after: &[&str]) {
with_list(list, |token, list| {
let mut cursor = place_cursor(token, list, at);
cursor.insert_after(element);
assert_cursor(before, current, after, cursor.as_cursor());
});
}
#[test]
fn cursor_mut_insert_after() {
assert_insert_after(create(0..4), "4".to_string(), 0, &[], "0", &["4", "1", "2", "3"]);
assert_insert_after(create(0..4), "4".to_string(), 1, &["0"], "1", &["4", "2", "3"]);
assert_insert_after(create(0..4), "4".to_string(), 2, &["0", "1"], "2", &["4", "3"]);
assert_insert_after(create(0..4), "4".to_string(), 3, &["0", "1", "2"], "3", &["4"]);
// Special case: "empty"
with_list(create(0..0), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
cursor.insert_after("4".to_string());
assert_twilight(&["4"], cursor.as_cursor());
});
// Special case: "twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 4);
cursor.insert_after("4".to_string());
assert_twilight(&["4", "0", "1", "2", "3"], cursor.as_cursor());
});
}
#[track_caller]
fn assert_insert_before(list: Vec<String>, element: String, at: usize, before: &[&str], current: &str, after: &[&str]) {
with_list(list, |token, list| {
let mut cursor = place_cursor(token, list, at);
cursor.insert_before(element);
assert_cursor(before, current, after, cursor.as_cursor());
});
}
#[test]
fn cursor_mut_insert_before() {
assert_insert_before(create(0..4), "4".to_string(), 0, &["4"], "0", &["1", "2", "3"]);
assert_insert_before(create(0..4), "4".to_string(), 1, &["0", "4"], "1", &["2", "3"]);
assert_insert_before(create(0..4), "4".to_string(), 2, &["0", "1", "4"], "2", &["3"]);
assert_insert_before(create(0..4), "4".to_string(), 3, &["0", "1", "2", "4"], "3", &[]);
// Special case: "empty"
with_list(create(0..0), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
cursor.insert_before("4".to_string());
assert_twilight(&["4"], cursor.as_cursor());
});
// Special case: "twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 4);
cursor.insert_before("4".to_string());
assert_twilight(&["0", "1", "2", "3", "4"], cursor.as_cursor());
});
}
#[track_caller]
fn assert_splice_after(list: Vec<String>, other: Vec<String>, at: usize, before: &[&str], current: &str, after: &[&str]) {
with_list_duo(list, other, |token, list, other| {
let mut cursor = place_cursor(token, list, at);
cursor.splice_after(other);
assert!(other.is_empty(), "{} elements!", other.len());
assert_cursor(before, current, after, cursor.as_cursor());
});
}
#[track_caller]
fn assert_splice_after_twilight(list: Vec<String>, other: Vec<String>, before: &[&str]) {
with_list_duo(list, other, |token, list, other| {
let mut cursor = place_cursor(token, list, list.len());
cursor.splice_after(other);
assert!(other.is_empty(), "{} elements!", other.len());
assert_twilight(before, cursor.as_cursor());
});
}
#[test]
fn cursor_mut_splice_after() {
// Empty spliced
{
assert_splice_after(create(0..4), create(0..0), 0, &[], "0", &["1", "2", "3"]);
assert_splice_after(create(0..4), create(0..0), 1, &["0"], "1", &["2", "3"]);
assert_splice_after(create(0..4), create(0..0), 2, &["0", "1"], "2", &["3"]);
assert_splice_after(create(0..4), create(0..0), 3, &["0", "1", "2"], "3", &[]);
// Special case: "empty"
assert_splice_after_twilight(create(0..0), create(0..0), &[]);
// Special case: "twilight"
assert_splice_after_twilight(create(0..4), create(0..0), &["0", "1", "2", "3"]);
}
// Single-element spliced
// See insert_after.
// Multi-elements spliced
{
assert_splice_after(create(0..4), create(4..7), 0, &[], "0", &["4", "5", "6", "1", "2", "3"]);
assert_splice_after(create(0..4), create(4..7), 1, &["0"], "1", &["4", "5", "6", "2", "3"]);
assert_splice_after(create(0..4), create(4..7), 2, &["0", "1"], "2", &["4", "5", "6", "3"]);
assert_splice_after(create(0..4), create(4..7), 3, &["0", "1", "2"], "3", &["4", "5", "6"]);
// Special case: "empty"
assert_splice_after_twilight(create(0..0), create(4..7), &["4", "5", "6"]);
// Special case: "twilight"
assert_splice_after_twilight(create(0..4), create(4..7), &["4", "5", "6", "0", "1", "2", "3"]);
}
}
#[track_caller]
fn assert_splice_before(list: Vec<String>, other: Vec<String>, at: usize, before: &[&str], current: &str, after: &[&str]) {
with_list_duo(list, other, |token, list, other| {
let mut cursor = place_cursor(token, list, at);
cursor.splice_before(other);
assert!(other.is_empty(), "{} elements!", other.len());
assert_cursor(before, current, after, cursor.as_cursor());
});
}
#[track_caller]
fn assert_splice_before_twilight(list: Vec<String>, other: Vec<String>, before: &[&str]) {
with_list_duo(list, other, |token, list, other| {
let mut cursor = place_cursor(token, list, list.len());
cursor.splice_before(other);
assert!(other.is_empty(), "{} elements!", other.len());
assert_twilight(before, cursor.as_cursor());
});
}
#[test]
fn cursor_mut_splice_before() {
// Empty spliced
{
assert_splice_before(create(0..4), create(0..0), 0, &[], "0", &["1", "2", "3"]);
assert_splice_before(create(0..4), create(0..0), 1, &["0"], "1", &["2", "3"]);
assert_splice_before(create(0..4), create(0..0), 2, &["0", "1"], "2", &["3"]);
assert_splice_before(create(0..4), create(0..0), 3, &["0", "1", "2"], "3", &[]);
// Special case: "empty"
assert_splice_before_twilight(create(0..0), create(0..0), &[]);
// Special case: "twilight"
assert_splice_before_twilight(create(0..4), create(0..0), &["0", "1", "2", "3"]);
}
// Single-element spliced
// See insert_after.
// Multi-elements spliced
{
assert_splice_before(create(0..4), create(4..7), 0, &["4", "5", "6"], "0", &["1", "2", "3"]);
assert_splice_before(create(0..4), create(4..7), 1, &["0", "4", "5", "6"], "1", &["2", "3"]);
assert_splice_before(create(0..4), create(4..7), 2, &["0", "1", "4", "5", "6"], "2", &["3"]);
assert_splice_before(create(0..4), create(4..7), 3, &["0", "1", "2", "4", "5", "6"], "3", &[]);
// Special case: "empty"
assert_splice_before_twilight(create(0..0), create(4..7), &["4", "5", "6"]);
// Special case: "twilight"
assert_splice_before_twilight(create(0..4), create(4..7), &["0", "1", "2", "3", "4", "5", "6"]);
}
}
#[track_caller]
fn assert_remove_current(list: Vec<String>, at: usize, result: Option<&str>, before: &[&str], current: &str, after: &[&str]) {
with_list(list, |token, list| {
let mut cursor = place_cursor(token, list, at);
let actual = cursor.remove_current();
assert_eq!(result, actual.as_ref().map(String::as_str));
assert_cursor(before, current, after, cursor.as_cursor());
});
}
#[test]
fn cursor_mut_remove_current() {
assert_remove_current(create(0..4), 0, Some("0"), &[], "1", &["2", "3"]);
assert_remove_current(create(0..4), 1, Some("1"), &["0"], "2", &["3"]);
assert_remove_current(create(0..4), 2, Some("2"), &["0", "1"], "3", &[]);
// Special-case: "empty"
with_list(create(0..0), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
let actual = cursor.remove_current();
assert_eq!(None, actual);
assert_twilight(&[], cursor.as_cursor());
});
// Special-case: "twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 4);
let actual = cursor.remove_current();
assert_eq!(None, actual);
assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor());
});
// Special-case: "next twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 3);
let actual = cursor.remove_current();
assert_eq!(Some("3"), actual.as_ref().map(String::as_str));
assert_twilight(&["0", "1", "2"], cursor.as_cursor());
});
}
#[track_caller]
fn assert_remove_current_as_list(list: Vec<String>, at: usize, result: Option<&str>, before: &[&str], current: &str, after: &[&str]) {
let result: Vec<_> = result.iter().copied().collect();
with_list(list, |token, list| {
let mut cursor = place_cursor(token, list, at);
let actual = cursor.remove_current_as_list();
assert_cursor(before, current, after, cursor.as_cursor());
mem::drop(cursor);
assert_list(&result, token, actual.expect("Some"));
});
}
#[test]
fn cursor_mut_remove_current_as_list() {
assert_remove_current_as_list(create(0..4), 0, Some("0"), &[], "1", &["2", "3"]);
assert_remove_current_as_list(create(0..4), 1, Some("1"), &["0"], "2", &["3"]);
assert_remove_current_as_list(create(0..4), 2, Some("2"), &["0", "1"], "3", &[]);
// Special-case: "empty"
with_list(create(0..0), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
let actual = cursor.remove_current_as_list();
assert!(actual.is_none());
assert_twilight(&[], cursor.as_cursor());
});
// Special-case: "twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 4);
let actual = cursor.remove_current_as_list();
assert!(actual.is_none());
assert_twilight(&["0", "1", "2", "3"], cursor.as_cursor());
});
// Special-case: "next twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 3);
let actual = cursor.remove_current_as_list();
assert_twilight(&["0", "1", "2"], cursor.as_cursor());
mem::drop(cursor);
assert_list(&["3"], token, actual.expect("Some"));
});
}
#[track_caller]
fn assert_split_after(list: Vec<String>, at: usize, before: &[&str], current: &str, after: &[&str]) {
with_list(list, |token, list| {
let mut cursor = place_cursor(token, list, at);
let actual = cursor.split_after();
assert_cursor(before, current, &[], cursor.as_cursor());
mem::drop(cursor);
assert_list(after, token, actual);
});
}
#[test]
fn cursor_mut_split_after() {
assert_split_after(create(0..4), 0, &[], "0", &["1", "2", "3"]);
assert_split_after(create(0..4), 1, &["0"], "1", &["2", "3"]);
assert_split_after(create(0..4), 2, &["0", "1"], "2", &["3"]);
assert_split_after(create(0..4), 3, &["0", "1", "2"], "3", &[]);
// Special-case: "empty"
with_list(create(0..0), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
let actual = cursor.split_after();
assert_twilight(&[], cursor.as_cursor());
mem::drop(cursor);
assert_list(&[], token, actual);
});
// Special-case: "twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 4);
let actual = cursor.split_after();
assert_twilight(&[], cursor.as_cursor());
mem::drop(cursor);
assert_list(&["0", "1", "2", "3"], token, actual);
});
}
#[track_caller]
fn assert_split_before(list: Vec<String>, at: usize, before: &[&str], current: &str, after: &[&str]) {
with_list(list, |token, list| {
let mut cursor = place_cursor(token, list, at);
let actual = cursor.split_before();
assert_cursor(&[], current, &after, cursor.as_cursor());
mem::drop(cursor);
assert_list(before, token, actual);
});
}
#[test]
fn cursor_mut_split_before() {
assert_split_before(create(0..4), 0, &[], "0", &["1", "2", "3"]);
assert_split_before(create(0..4), 1, &["0"], "1", &["2", "3"]);
assert_split_before(create(0..4), 2, &["0", "1"], "2", &["3"]);
assert_split_before(create(0..4), 3, &["0", "1", "2"], "3", &[]);
// Special-case: "empty"
with_list(create(0..0), |token, list| {
let mut cursor = CursorMut::new_front(token, list);
let actual = cursor.split_before();
assert_twilight(&[], cursor.as_cursor());
mem::drop(cursor);
assert_list(&[], token, actual);
});
// Special-case: "twilight"
with_list(create(0..4), |token, list| {
let mut cursor = place_cursor(token, list, 4);
let actual = cursor.split_before();
assert_twilight(&[], cursor.as_cursor());
mem::drop(cursor);
assert_list(&["0", "1", "2", "3"], token, actual);
});
}
} // mod tests
================================================
FILE: src/tripod_list/iter.rs
================================================
use ghost_cell::GhostToken;
use super::{GhostNode, TripodList};
/// An iterator over a TripodList, self-sufficient once created as it carries its own token.
pub struct Iter<'a, 'brand, T> {
token: &'a GhostToken<'brand>,
head_tail: Option<(&'a GhostNode<'brand, T>, &'a GhostNode<'brand, T>)>,
}
impl<'a, 'brand, T> Iter<'a, 'brand, T> {
/// Creates a new instance of the Iter.
pub fn new(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T>) -> Self {
let head_tail = list.head_tail.as_ref().map(|head_tail| {
(&*head_tail.0, &*head_tail.1)
});
Self { token, head_tail, }
}
// Internal: creates an empty instance.
pub(super) fn empty(token: &'a GhostToken<'brand>) -> Self {
Self { token, head_tail: None, }
}
// Internal: creates an instance over a slice of items.
pub(super) fn slice(
token: &'a GhostToken<'brand>,
head_tail: Option<(&'a GhostNode<'brand, T>, &'a GhostNode<'brand, T>)>,
)
-> Self
{
Self { token, head_tail, }
}
}
impl<'a, 'brand, T> Iterator for Iter<'a, 'brand, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let (head, tail) = self.head_tail.take()?;
let node = head.borrow(self.token);
if head as *const _ != tail as *const _ {
self.head_tail = node.next.as_ref().map(|n| {
let n: &'a GhostNode<'_, _> = &*n;
(n, tail)
});
} else {
self.head_tail = None;
}
Some(&node.value)
}
}
impl<'a, 'brand, T> DoubleEndedIterator for Iter<'a, 'brand, T> {
fn next_back(&mut self) -> Option<Self::Item> {
let (head, tail) = self.head_tail.take()?;
let node = tail.borrow(self.token);
if head as *const _ != tail as *const _ {
self.head_tail = node.prev.as_ref().map(|n| {
let n: &'a GhostNode<'_, _> = &*n;
(head, n)
});
} else {
self.head_tail = None;
}
Some(&node.value)
}
}
#[cfg(test)]
mod tests {
use super::super::tests::with_list;
use super::*;
#[test]
fn empty() {
with_list::<String, _, _>(vec!(), |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(None, iterator.next());
assert_eq!(None, iterator.next_back());
});
}
#[test]
fn forward() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("0"), iterator.next().map(String::as_str));
assert_eq!(Some("1"), iterator.next().map(String::as_str));
assert_eq!(Some("2"), iterator.next().map(String::as_str));
assert_eq!(Some("3"), iterator.next().map(String::as_str));
assert_eq!(None, iterator.next());
});
}
#[test]
fn backward() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("3"), iterator.next_back().map(String::as_str));
assert_eq!(Some("2"), iterator.next_back().map(String::as_str));
assert_eq!(Some("1"), iterator.next_back().map(String::as_str));
assert_eq!(Some("0"), iterator.next_back().map(String::as_str));
assert_eq!(None, iterator.next_back());
});
}
#[test]
fn alternate() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("0"), iterator.next().map(String::as_str));
assert_eq!(Some("3"), iterator.next_back().map(String::as_str));
assert_eq!(Some("1"), iterator.next().map(String::as_str));
assert_eq!(Some("2"), iterator.next_back().map(String::as_str));
assert_eq!(None, iterator.next());
assert_eq!(None, iterator.next_back());
});
}
#[test]
fn alternate_other() {
let vec: Vec<_> = (0..4).map(|n| n.to_string()).collect();
with_list(vec, |token, list| {
let mut iterator = Iter::new(token, list);
assert_eq!(Some("3"), iterator.next_back().map(String::as_str));
assert_eq!(Some("0"), iterator.next().map(String::as_str));
assert_eq!(Some("2"), iterator.next_back().map(String::as_str));
assert_eq!(Some("1"), iterator.next().map(String::as_str));
assert_eq!(None, iterator.next_back());
assert_eq!(None, iterator.next());
});
}
} // mod tests
================================================
FILE: src/tripod_list.rs
================================================
//! A LinkedList, with externally supplied token.
//!
//! Unlike LinkedList, a TripodList has one additional pointer per node. In exchange, extra capabilities are unlocked.
//!
//! A number of operations normally implemented by traits cannot be successfully implemented on this collection due to
//! the requirement of supplying the GhostToken externally.
mod cursor;
mod iter;
pub use cursor::{Cursor, CursorMut};
pub use iter::Iter;
use core::{
cell::Cell,
mem,
};
use ghost_cell::{GhostCell, GhostToken};
use static_rc::StaticRc;
/// A safe implementation of a linked-list build upon `GhostCell` and `StaticRc`.
///
/// The `TripodList` contains 3 pointers per node, rather than 2 for a standard doubly linked list, the extra pointer
/// is used to temporarily anchor a node to the stack, guaranteeing its lifetime.
pub struct TripodList<'brand, T> {
length: usize,
head_tail: Option<(ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>)>,
}
impl<'brand, T> TripodList<'brand, T> {
/// Creates a fresh instance.
pub fn new() -> Self { Self::default() }
/// Appends all elements of `other`, in order, to the back of this list.
///
/// After this call, `other` is empty
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn append(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) {
let other_ht = if let Some(other_ht) = other.head_tail.take() {
other_ht
} else {
return;
};
self.head_tail = if let Some(self_ht) = self.head_tail.take() {
let (new_head, mid_tail) = self_ht;
let (mid_head, new_tail) = other_ht;
let tripod = mid_head.borrow(token).deploy();
mid_tail.borrow_mut(token).next = Some(mid_head);
tripod.borrow_mut(token).prev = Some(mid_tail);
retract(tripod, token);
Some((new_head, new_tail))
} else {
Some(other_ht)
};
self.length += other.length;
other.length = 0;
}
/// Prepends all elements of `other`, in order, to the front of this list.
///
/// After this call, `other` is empty
///
/// # Complexity
///
/// This operation is O(1) in the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn prepend(&mut self, other: &mut Self, token: &mut GhostToken<'brand>) {
other.append(self, token);
mem::swap(self, other);
}
/// Creates an iterator over self.
pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'brand, T> {
Iter::new(token, self)
}
/// Creates a cursor pointing to the front element.
pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> {
Cursor::new_front(token, self)
}
/// Creates a mutable cursor pointing to the front element.
pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> {
CursorMut::new_front(token, self)
}
/// Creates a cursor pointing to the back element.
pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a, 'brand, T> {
Cursor::new_back(token, self)
}
/// Creates a mutable cursor pointing to the back element.
pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> CursorMut<'a, 'brand, T> {
CursorMut::new_back(token, self)
}
/// Returns whether the list is empty, or not.
pub fn is_empty(&self) -> bool { self.length == 0 }
/// Returns the number of elements in the list.
pub fn len(&self) -> usize { self.length }
/// Clears the list, destroying all elements.
///
/// # Complexity
///
/// This operation is O(N) in the number of elements.
pub fn clear(&mut self, token: &mut GhostToken<'brand>) {
while let Some(_) = self.pop_back(token) {}
}
/// Returns a reference to the front element of the list, if any.
pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
self.front_node().map(|node| &node.borrow(token).value)
}
/// Returns a mutable reference to the front element of the list, if any.
pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> {
self.front_node().map(move |node| &mut node.borrow_mut(token).value)
}
/// Returns a reference to the back element of the list, if any.
pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
self.back_node().map(|node| &node.borrow(token).value)
}
/// Returns a mutable reference to the back element of the list, if any.
pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> Option<&'a mut T> {
self.back_node().map(move |node| &mut node.borrow_mut(token).value)
}
/// Pushes an element to the front of the list.
pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) {
let (one, two) = Self::new_thirds(value, token);
let head_tail = if let Some((head, tail)) = self.head_tail.take() {
head.borrow_mut(token).prev = Some(one);
two.borrow_mut(token).next = Some(head);
(two, tail)
} else {
(one, two)
};
self.length += 1;
self.head_tail = Some(head_tail);
}
/// Removes and returns the front element of the list, if any.
pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
let (head, tail) = self.head_tail.take()?;
let tripod = head.borrow(token).deploy();
let (one, two) = if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) {
(head, tail)
} else {
let next = head.borrow_mut(token).next.take()
.expect("Non-tail should have a next node");
let other_head = next.borrow_mut(token).prev.take()
.expect("Non-head should have a previous node");
self.head_tail = Some((next, tail));
(head, other_head)
};
self.length -= 1;
Some(Self::into_inner((one, two, tripod)))
}
/// Pushes an element to the back of the list.
pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) {
let (one, two) = Self::new_thirds(value, token);
let head_tail = if let Some((head, tail)) = self.head_tail.take() {
tail.borrow_mut(token).next = Some(one);
two.borrow_mut(token).prev = Some(tail);
(head, two)
} else {
(one, two)
};
self.length += 1;
self.head_tail = Some(head_tail);
}
/// Removes and returns the back element of the list, if any.
pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
let (head, tail) = self.head_tail.take()?;
let tripod = tail.borrow(token).deploy();
let (one, two) = if StaticRc::as_ptr(&head) == StaticRc::as_ptr(&tail) {
(head, tail)
} else {
let prev = tail.borrow_mut(token).prev.take()
.expect("Non-head should have a previous node");
let other_tail = prev.borrow_mut(token).next.take()
.expect("Non-tail should have a next node");
self.head_tail = Some((head, prev));
(other_tail, tail)
};
self.length -= 1;
Some(Self::into_inner((one, two, tripod)))
}
/// Splits the list in two at the given index. Returns a list containing everything after the given index, inclusive.
///
/// Returns None if the given index is out of bounds.
///
/// # Complexity
///
/// This operations is O(min(`at`, N)), where N is the number of elements.
///
/// No memory allocation or deallocation occurs.
pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -> Self {
assert!(at < self.length, "at ({}) >= self.len() ({})", at, self.length);
// This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity.
let mut cursor = self.cursor_front_mut(token);
if at == 0 {
cursor.move_prev();
} else {
for _ in 0..(at-1) {
cursor.move_next();
}
}
cursor.split_after()
}
/// Removes the element at the given index, and returns it, if the index is within bounds.
///
/// # Complexity
///
/// This operations is O(min(`at`, N)), where N is the number of elements.
///
/// No memory allocation occurs, and a single memory deallocation occurs.
pub fn remove(&mut self, at: usize, token: &mut GhostToken<'brand>) -> T {
assert!(at < self.length, "at ({}) >= self.len() ({})", at, self.length);
// This is not the most optimal implementation, but it works, and respects the promised algorithmic complexity.
let mut cursor = self.cursor_front_mut(token);
for _ in 0..at {
cursor.move_next();
}
cursor.remove_current().expect("Element, since at < self.length")
}
// Internal: returns a reference to the front node, if any.
fn front_node(&self) -> Option<&GhostNode<'brand, T>> { self.head_tail.as_ref().map(|ht| &*ht.0) }
// Internal: returns a reference to the front node, if any.
fn back_node(&self) -> Option<&GhostNode<'brand, T>> { self.head_tail.as_ref().map(|ht| &*ht.1) }
// Internal: creates a node with the value, and returns 2/3 of its pointers, the remaining tucked into its tripod field.
fn new_thirds(value: T, token: &GhostToken<'brand>) -> (ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>) {
let node = Node { value, prev: None, next: None, tripod: Cell::new(None), };
let full = FullNodePtr::new(GhostNode::new(node));
let (partial, tripod) = StaticRc::split::<2, 1>(full);
partial.borrow(token).retract(tripod);
StaticRc::split::<1, 1>(partial)
}
// Internal: takes 3 1/3 pointers, reassemble them, and return their inner value.
fn into_inner(thirds: ThirdTuple<'brand, T>) -> T {
let partial = TwoThirdsNodePtr::join(thirds.0, thirds.1);
let full = FullNodePtr::join(partial, thirds.2);
let ghost_cell = FullNodePtr::into_inner(full);
let node = GhostNode::into_inner(ghost_cell);
// If the node still has a prev and next, they are leaked.
debug_assert!(node.prev.is_none());
debug_assert!(node.next.is_none());
debug_assert!(node.tripod.replace(None).is_none());
node.value
}
}
impl<'brand, T> Default for TripodList<'brand, T> {
fn default() -> Self { Self { length: 0, head_tail: None, } }
}
//
// Implementation
//
struct Node<'brand, T> {
value: T,
prev: Option<ThirdNodePtr<'brand, T>>,
next: Option<ThirdNodePtr<'brand, T>>,
tripod: Cell<Option<ThirdNodePtr<'brand, T>>>,
}
impl<'brand, T> Node<'brand, T> {
// Internal; deploys the tripod.
fn deploy(&self) -> ThirdNodePtr<'brand, T> { self.tripod.take().expect("Tripod not to be None") }
// Internal; retracts the tripod.
fn retract(&self, tripod: ThirdNodePtr<'brand, T>) {
let previous = self.tripod.replace(Some(tripod));
debug_assert!(previous.is_none());
}
}
fn retract<'brand, T>(tripod: ThirdNodePtr<'brand, T>, token: &mut GhostToken<'brand>) {
let previous = static_rc::lift_with_mut(Some(tripod), token, |tripod, token| {
tripod.as_ref().expect("Some").borrow_mut(token).tripod.get_mut()
});
debug_assert!(previous.is_none(), "Node should not have any tripod to retract it!");
}
type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>;
type ThirdNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 1, 3>;
type TwoThirdsNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 2, 3>;
type FullNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 3, 3>;
type ThirdTuple<'brand, T> = (ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>, ThirdNodePtr<'brand, T>);
#[cfg(test)]
mod tests {
use std::{
panic::{self, AssertUnwindSafe},
ops::Range,
};
use super::*;
#[track_caller]
fn assert_list_mut<'brand>(expected: &[&str], token: &mut GhostToken<'brand>, list: &mut TripodList<'brand, String>) {
let actual = collect(list.iter(token));
assert_eq!(expected, actual);
assert_eq!(expected.len(), list.len());
assert_eq!(expected.is_empty(), list.is_empty());
list.clear(token);
}
#[track_caller]
pub(crate) fn assert_list<'brand>(expected: &[&str], token: &mut GhostToken<'brand>, mut list: TripodList<'brand, String>) {
assert_list_mut(expected, token, &mut list);
}
#[track_caller]
fn assert_list_append(list: Vec<String>, append: Vec<String>, expected: &[&str]) {
with_list_duo(list, append, |token, list, other| {
list.append(other, token);
assert_list_mut(expected, token, list);
assert_list_mut(&[], token, other);
});
}
#[test]
fn list_append() {
// Append empty list
assert_list_append(create(0..0), create(0..0), &[]);
assert_list_append(create(0..1), create(0..0), &["0"]);
assert_list_append(create(0..4), create(0..0), &["0", "1", "2", "3"]);
// Append single element list
assert_list_append(create(0..0), create(4..5), &["4"]);
assert_list_append(create(0..1), create(4..5), &["0", "4"]);
assert_list_append(create(0..4), create(4..5), &["0", "1", "2", "3", "4"]);
// Append multi element list
assert_list_append(create(0..0), create(4..7), &["4", "5", "6"]);
assert_list_append(create(0..1), create(4..7), &["0", "4", "5", "6"]);
assert_list_append(create(0..4), create(4..7), &["0", "1", "2", "3", "4", "5", "6"]);
}
#[track_caller]
fn assert_list_split_off(list: Vec<String>, at: usize, expected_list: &[&str], expected_result: &[&str]) {
with_list(list, |token, list| {
let result = list.split_off(at, token);
assert_list_mut(expected_list, token, list);
assert_list(expected_result, token, result);
});
}
#[test]
fn list_split_off() {
assert_list_split_off(create(0..4), 0, &[], &["0", "1", "2", "3"]);
assert_list_split_off(create(0..4), 1, &["0"], &["1", "2", "3"]);
assert_list_split_off(create(0..4), 2, &["0", "1"], &["2", "3"]);
assert_list_split_off(create(0..4), 3, &["0", "1", "2"], &["3"]);
}
#[test]
#[should_panic]
fn list_split_off_out_of_bounds() {
with_list(create(0..4), |token, list| {
list.split_off(4, token);
});
}
#[track_caller]
fn assert_list_remove(list: Vec<String>, at: usize, expected_list: &[&str], expected_result: &str) {
with_list(list, |token, list| {
let result = list.remove(at, token);
assert_eq!(expected_result, result);
assert_list_mut(expected_list, token, list);
});
}
#[test]
fn list_remove() {
assert_list_remove(create(0..4), 0, &["1", "2", "3"], "0");
assert_list_remove(create(0..4), 1, &["0", "2", "3"], "1");
assert_list_remove(create(0..4), 2, &["0", "1", "3"], "2");
assert_list_remove(create(0..4), 3, &["0", "1", "2"], "3");
}
#[test]
#[should_panic]
fn list_remove_out_of_bounds() {
with_list(create(0..4), |token, list| {
list.remove(4, token);
});
}
pub(crate) fn create(range: Range<i32>) -> Vec<String> {
range.map(|n| n.to_string()).collect()
}
pub(crate) fn collect<'a>(iter: Iter<'a, '_, String>) -> Vec<&'a str> {
iter.map(String::as_str).collect()
}
pub(crate) fn with_list<T, R, F>(initial: Vec<T>, fun: F) -> R
where
F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut TripodList<'brand, T>) -> R,
{
GhostToken::new(|mut token| {
let mut list = TripodList::new();
for value in initial {
list.push_back(value, &mut token);
}
let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut list)));
list.clear(&mut token);
result.expect("No Panic")
})
}
pub(crate) fn with_list_duo<T, R, F>(first: Vec<T>, second: Vec<T>, fun: F) -> R
where
F: for<'brand> FnOnce(&mut GhostToken<'brand>, &mut TripodList<'brand, T>, &mut TripodList<'brand, T>) -> R,
{
GhostToken::new(|mut token| {
let mut first_list = TripodList::new();
let mut second_list = TripodList::new();
for value in first {
first_list.push_back(value, &mut token);
}
for value in second {
second_list.push_back(value, &mut token);
}
let result = panic::catch_unwind(AssertUnwindSafe(|| fun(&mut token, &mut first_list, &mut second_list)));
first_list.clear(&mut token);
second_list.clear(&mut token);
result.expect("No Panic")
})
}
} // mod tests
================================================
FILE: src/tripod_tree/cursor.rs
================================================
use core::{
cmp,
mem,
ops::Range,
};
use ghost_cell::GhostToken;
use super::{GhostNode, QuarterNodePtr, Side, TripodTree};
/// A Cursor over the TripodTree.
///
/// The Cursor contains a "twilight" non-element between the leaves and the root, that is:
///
/// - Going "up" from the root points the cursor to the "twilight" non-element.
/// - Going "left", respectively "right", from any node without a "left" (resp. "right") sub-tree points the cursor
/// to the "twilight" non-element.
///
/// A cursor pointing to the "twilight" non-element cannot go "up", and going either "left" or "right" points the
/// cursor back to the root.
pub struct Cursor<'a, 'brand, T> {
token: &'a GhostToken<'brand>,
tree: &'a TripodTree<'brand, T>,
node: Option<&'a GhostNode<'brand, T>>,
index: usize,
}
// Constant time cursor navigation.
impl<'a, 'brand, T> Cursor<'a, 'brand, T> {
/// Creates a new cursor pointing at the root of the tree, if any.
pub fn new(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self {
let (node, index) = Self::root_of(token, tree);
Self { token, index, node, tree, }
}
/// Returns the index of the cursor, if any.
///
/// If the cursor points to the "twilight" non-element, None is returned.
pub fn index(&self) -> Option<usize> { self.node.map(|_| self.index) }
/// Returns the range of indices covered by the sub-tree rooted at node the cursor is pointing at.
///
/// If the cursor points to the new "twilight" non-element, None is returned.
pub fn range(&self) -> Range<usize> {
self.node.map(|node| {
let left_size = node.borrow(self.token).left_size(self.token);
let right_size = node.borrow(self.token).right_size(self.token);
(self.index - left_size)..(self.index + right_size + 1)
}).unwrap_or(0..0)
}
/// Moves the cursor to the root, if any.
pub fn move_to_root(&mut self) { *self = Self::new(self.token, self.tree) }
/// Moves the cursor to the parent node, if any.
///
/// If the cursor points to the "twilight" non-element, nothing happens.
pub fn move_up(&mut self) {
let (node, index) = self.peek_up_node();
self.index = index;
self.node = node;
}
/// Moves the cursor to the left child.
///
/// If the element the cursor points to has no left child, moves to the "twilight" non-element.
///
/// If the cursor points to the "twilight" non-element, moves to the root instead, if any.
pub fn move_left(&mut self) {
let (node, index) = self.peek_left_node();
self.index = index;
self.node = node;
}
/// Moves the cursor to the right child.
///
/// If the element the cursor points to has no right child, moves to the "twilight" non-element.
///
/// If the cursor points to the "twilight" non-element, moves to the root instead, if any.
pub fn move_right(&mut self) {
let (node, index) = self.peek_right_node();
self.index = index;
self.node = node;
}
/// Moves the cursor to the child element on the given side.
///
/// If the element the cursor points to has no such element, moves to the "twilight" non-element.
///
/// If the cursor points to the "twilight" non-element, moves to the root instead, if any.
pub fn move_down(&mut self, side: Side) {
let (node, index) = self.peek_down_node(side);
self.index = index;
self.node = node;
}
/// Attempts to move the cursor to the parent node, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no parent node, or is the "twilight" element, does not move.
pub fn try_move_up(&mut self) -> Option<&'a T> {
let (node, index) = self.peek_up_node();
if let Some(_) = node {
self.index = index;
self.node = node;
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the left child, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no left child, or is the "twilight" element, does not move.
pub fn try_move_left(&mut self) -> Option<&'a T> {
let (node, index) = self.peek_left_node();
if let Some(_) = node {
self.index = index;
self.node = node;
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the right child, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no right child, or is the "twilight" element, does not move.
pub fn try_move_right(&mut self) -> Option<&'a T> {
let (node, index) = self.peek_right_node();
if let Some(_) = node {
self.index = index;
self.node = node;
self.current()
} else {
None
}
}
/// Attempts to move the cursor down to the given side, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor is pointing to has no child on that side, or is the "twilight" non-element, nothing
/// happens and None is returned.
pub fn try_move_down(&mut self, side: Side) -> Option<&'a T> {
let (node, index) = self.peek_down_node(side);
if let Some(_) = node {
self.index = index;
self.node = node;
self.current()
} else {
None
}
}
/// Returns a reference to the current element, if any.
pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the up element, if any.
pub fn peek_up(&self) -> Option<&'a T> { self.peek_up_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the left child, if any.
pub fn peek_left(&self) -> Option<&'a T> { self.peek_left_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the right child, if any.
pub fn peek_right(&self) -> Option<&'a T> { self.peek_right_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the child element on the given side, if any.
pub fn peek_down(&self, side: Side) -> Option<&'a T> { self.peek_down_node(side).0.map(|node| &node.borrow(self.token).value) }
// Internal; extract the root and its index from the tree.
fn root_of(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> (Option<&'a GhostNode<'brand, T>>, usize) {
let root = tree.root.as_ref().map(|node| &**node);
let index = root.map(|node| node.borrow(token).index(token)).unwrap_or(0);
(root, index)
}
// Internal; returns a reference to the up GhostNode, and the matching index.
fn peek_up_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
if let Some(node) = self.node {
let node = node.borrow(self.token);
let parent = node.up();
let index = if let Some(parent) = parent {
let parent = parent.borrow(self.token);
if node.is_aliased(parent.left()) {
self.index + 1 + node.right_size(self.token)
} else {
debug_assert!(node.is_aliased(parent.right()));
self.index - 1 - node.left_size(self.token)
}
} else {
self.len()
};
(parent, index)
} else {
(self.node, self.len())
}
}
// Internal; returns a reference to the left GhostNode, and the matching index.
fn peek_left_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
if let Some(node) = self.node {
let node = node.borrow(self.token);
let dest = node.left();
let index = if let Some(left) = dest {
self.index - 1 - left.borrow(self.token).right_size(self.token)
} else {
self.len()
};
(dest, index)
} else {
Self::root_of(self.token, self.tree)
}
}
// Internal; returns a reference to the right GhostNode, and the matching index.
fn peek_right_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
if let Some(node) = self.node {
let node = node.borrow(self.token);
let dest = node.right();
let index = if let Some(right) = dest {
self.index + 1 + right.borrow(self.token).left_size(self.token)
} else {
self.len()
};
(dest, index)
} else {
Self::root_of(self.token, self.tree)
}
}
// Internal; returns a reference to the child GhostNode on the given side, and the matching index.
fn peek_down_node(&self, side: Side) -> (Option<&'a GhostNode<'brand, T>>, usize) {
if let Some(node) = self.node {
let node = node.borrow(self.token);
let dest = node.child(side);
let index = if let Some(dest) = dest {
let opposite_size = dest.borrow(self.token).child_size(side.opposite(), self.token);
match side {
Side::Left => self.index - 1 - opposite_size,
Side::Right => self.index + 1 + opposite_size,
}
} else {
self.len()
};
(dest, index)
} else {
Self::root_of(self.token, self.tree)
}
}
}
// Logarithmic cursor navigation.
impl<'a, 'brand, T> Cursor<'a, 'brand, T> {
/// Creates a new cursor pointing at the front element of the tree, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn new_front(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self {
let mut cursor = Self::new(token, tree);
while let Some(_) = cursor.try_move_left() {}
debug_assert_eq!(0, cursor.index);
cursor
}
/// Creates a new cursor pointing at the back element of the tree, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn new_back(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T>) -> Self {
let mut cursor = Self::new(token, tree);
while let Some(_) = cursor.try_move_right() {}
debug_assert_eq!(cursor.len() - 1, cursor.index);
cursor
}
/// Moves the cursor to the front element, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_to_front(&mut self) { *self = Self::new_front(self.token, self.tree); }
/// Moves the cursor to the back element, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_to_back(&mut self) { *self = Self::new_back(self.token, self.tree); }
/// Moves the cursor to the next element, if any.
///
/// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the root
/// and the leaves.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_next(&mut self) {
let (node, index) = self.peek_next_node();
self.index = index;
self.node = node;
}
/// Moves the cursor to the previous element, if any.
///
/// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the root
/// and the leaves.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_prev(&mut self) {
let (node, index) = self.peek_prev_node();
self.index = index;
self.node = node;
}
/// Moves the cursor to the element at the given index.
///
/// If there is no such element, then the cursor moves to the "twilight" non-element, which exists between the front
/// and back element.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
///
/// # Panics
///
/// If `at` is strictly greater than `tree.len()`.
pub fn move_to(&mut self, at: usize) {
self.node = self.peek_at_node(at);
self.index = at;
}
/// Attempts to move the cursor to the next element, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no next element, or is the "twilight" element, does not move.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn try_move_next(&mut self) -> Option<&'a T> {
let (node, index) = self.peek_next_node();
if let Some(_) = node {
self.index = index;
self.node = node;
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the previous element, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no previous element, or is the "twilight" element, does not move.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn try_move_prev(&mut self) -> Option<&'a T> {
let (node, index) = self.peek_prev_node();
if let Some(_) = node {
self.index = index;
self.node = node;
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the element at the given index, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If there is not such element, or the cursor points to the "twilight" element, does not move.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
///
/// # Panics
///
/// If `at` is strictly greater than `tree.len()`.
pub fn try_move_to(&mut self, at: usize) -> Option<&'a T> {
self.node?;
let node = self.peek_at_node(at);
if let Some(_) = node {
self.index = at;
self.node = node;
self.current()
} else {
None
}
}
/// Returns a reference to the next element, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the previous element, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the element at the given index, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn peek_at(&self, at: usize) -> Option<&'a T> { self.peek_at_node(at).map(|node| &node.borrow(self.token).value) }
// Internal; returns the length of the tree.
fn len(&self) -> usize { self.tree.len(self.token) }
// Internal; returns a reference to the GhostNode at the next index.
fn peek_next_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
let index = if let Some(_) = self.node {
self.index + 1
} else {
0
};
(self.peek_at_node(index), index)
}
// Internal; returns a reference to the GhostNode at the previous index.
fn peek_prev_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
let index = if let Some(_) = self.node {
self.index.checked_sub(1).unwrap_or_else(|| self.len())
} else {
self.len().checked_sub(1).unwrap_or(0)
};
(self.peek_at_node(index), index)
}
// Internal; returns a reference to the GhostNode at the specific index.
//
// Panics if the index is "too" out of bounds; returns the "twilight" non-element if the index is only 1 out of bounds.
fn peek_at_node(&self, at: usize) -> Option<&'a GhostNode<'brand, T>> {
let length = self.len();
assert!(at <= length, "at ({}) > self.tree.len() ({})", at, length);
if at == length {
return None;
}
if at == self.index {
return self.node;
}
let mut cursor = match (self.node, self.tree.root.as_ref().map(|n| &**n)) {
(Some(_), Some(root)) => {
let root_index = root.borrow(self.token).index(self.token);
if at >= root_index && root_index > self.index {
Cursor::new(self.token, self.tree)
} else if at <= root_index && root_index < self.index {
Cursor::new(self.token, self.tree)
} else {
self.clone()
}
},
(Some(_), None) => self.clone(),
(None, Some(_)) => Cursor::new(self.token, self.tree),
(None, None) => unreachable!("at >= length, then"),
};
// In this case, move start to the first common ancestor of start and the node at index `at`.
if self.index == cursor.index {
while !cursor.range().contains(&at) {
cursor.move_up();
}
}
// From then on, we are guaranteed that `cursor` is pointing to an ancestor of `at`, so it's somewhere down.
let mut max_iteration = length + 1;
loop {
use cmp::Ordering::*;
let index = cursor.index;
debug_assert!(cursor.range().contains(&at), "{:?} does not contain {}", cursor.range(), at);
match at.cmp(&index) {
Less => {
cursor.move_left();
debug_assert!(cursor.index < index);
},
Equal => break,
Greater => {
cursor.move_right();
debug_assert!(cursor.index > index);
},
}
debug_assert!(max_iteration > 0);
max_iteration = max_iteration.saturating_sub(1);
}
debug_assert_eq!(at, cursor.index);
cursor.node
}
}
impl<'a, 'brand, T> Clone for Cursor<'a, 'brand, T> {
fn clone(&self) -> Self { *self }
}
impl<'a, 'brand, T> Copy for Cursor<'a, 'brand, T> {}
/// A mutable cursor over the TripodTree.
///
/// A mutable cursor allows freely moving back-and-forth amongst the elements of the tree, and mutate the tree as any
/// point.
///
/// Cursors index the tree in a logically circular way. To accomodate this, there is a "twilight" non-element
/// represented by `None` between the root and leaves of the tree.
///
/// # Warning.
///
/// This cursor mutates the tree as it iterates. Although the tree is left in a safe state by construction, forgoing the
/// drop of this cursor -- unless it points to the "twilight" non-element -- will leave the tree in an unusable state.
///
/// Any further mutable operation on the tree, including calling `clear`, is at risk of panicking.
pub struct CursorMut<'a, 'brand, T> {
token: &'a mut GhostToken<'brand>,
tree: &'a mut TripodTree<'brand, T>,
node: Option<QuarterNodePtr<'brand, T>>,
index: usize,
}
// Constant time cursor navigation.
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
/// Creates a new instance pointing to the front element of the tree, if any.
pub fn new(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>) -> Self {
let (node, index) = Self::root_of(token, tree);
let node = node.map(|node| node.borrow(token).deploy());
Self { token, index, node, tree, }
}
/// Returns a read-only cursor pointing to the current element.
pub fn as_cursor(&self) -> Cursor<'_, 'brand, T> {
let token = &*self.token;
let index = self.index;
let node = self.node.as_ref().map(|rc| &**rc);
let tree = &*self.tree;
Cursor { token, index, node, tree, }
}
/// Returns the index of the element pointed to by the cursor in the tree.
///
/// If the cursor currently points to the "twilight" non-element, returns None.
pub fn index(&self) -> Option<usize> { self.node.as_ref().map(|_| self.index) }
/// Returns the range of indices covered by the sub-tree rooted at node the cursor is pointing at.
///
/// If the cursor points to the new "twilight" non-element, None is returned.
pub fn range(&self) -> Range<usize> { self.as_cursor().range() }
/// Moves the cursor to the parent element, if any.
///
/// If the cursor points to the "twilight" non-element, nothing happens.
pub fn move_up(&mut self) {
let (node, index) = self.peek_up_node();
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
}
/// Moves the cursor to the left element.
///
/// If the element the cursor points to has no left element, moves to the "twilight" non-element.
///
/// If the cursor points to the "twilight" non-element, moves to the root instead, if any.
pub fn move_left(&mut self) {
let (node, index) = self.peek_left_node();
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
}
/// Moves the cursor to the right element.
///
/// If the element the cursor points to has no right element, moves to the "twilight" non-element.
///
/// If the cursor points to the "twilight" non-element, moves to the root instead, if any.
pub fn move_right(&mut self) {
let (node, index) = self.peek_right_node();
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
}
/// Moves the cursor to the child element on the design side.
///
/// If the element the cursor points to has no such element, moves to the "twilight" non-element.
///
/// If the cursor points to the "twilight" non-element, moves to the root instead, if any.
pub fn move_down(&mut self, side: Side) {
let (node, index) = self.peek_down_node(side);
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
}
/// Moves to the cursor to the root of the tree.
///
/// If there is no such element, moves to the "twilight" non-element.
pub fn move_to_root(&mut self) {
// If list empty, no root to move to.
if self.tree.is_empty() {
return;
}
// If pointing at root, no need to move.
if self.node.is_some() && self.peek_up().is_none() {
return;
}
let root_tripod = self.tree.root.as_ref().map(|node| self.deploy_tripod(node));
let root_index = root_tripod.as_ref().map(|tripod| tripod.borrow(self.token).index(self.token)).unwrap_or(0);
self.switch_tripod(root_tripod, root_index);
}
/// Attempts to move the cursor to the parent element, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no parent element, or is the "twilight" element, nothing
/// happens and None is returned.
pub fn try_move_up(&mut self) -> Option<&mut T> {
let (node, index) = self.peek_up_node();
if let Some(_) = node {
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the left child, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no left child, or is the "twilight" non-element, nothing
/// happens and None is returned.
pub fn try_move_left(&mut self) -> Option<&mut T> {
let (node, index) = self.peek_left_node();
if let Some(_) = node {
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the right child, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no right child, or is the "twilight" non-element, nothing
/// happens and None is returned.
pub fn try_move_right(&mut self) -> Option<&mut T> {
let (node, index) = self.peek_right_node();
if let Some(_) = node {
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
self.current()
} else {
None
}
}
/// Attempts to move the cursor down to the given side, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor is pointing to has no child on that side, or is the "twilight" non-element, nothing
/// happens and None is returned.
pub fn try_move_down(&mut self, side: Side) -> Option<&mut T> {
let (node, index) = self.peek_down_node(side);
if let Some(_) = node {
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
self.current()
} else {
None
}
}
/// Returns a reference to the current element, if any.
pub fn current(&mut self) -> Option<&mut T> {
let tripod = self.node.as_ref()?;
Some(&mut tripod.borrow_mut(self.token).value)
}
/// Returns a reference to the up element, if any.
pub fn peek_up(&self) -> Option<&T> { self.peek_up_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the left element, if any.
pub fn peek_left(&self) -> Option<&T> { self.peek_left_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the right element, if any.
pub fn peek_right(&self) -> Option<&T> { self.peek_right_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the child element on the given side, if any.
pub fn peek_down(&self, side: Side) -> Option<&T> { self.peek_down_node(side).0.map(|node| &node.borrow(self.token).value) }
// Internal; extract the root and its index from the tree.
fn root_of<'b>(token: &'b GhostToken<'brand>, tree: &'b TripodTree<'brand, T>) -> (Option<&'b GhostNode<'brand, T>>, usize) {
let root = tree.root.as_ref().map(|node| &**node);
let index = root.map(|node| node.borrow(token).index(token)).unwrap_or(0);
(root, index)
}
// Internal; deploys a tripod.
fn deploy_tripod(&self, node: &GhostNode<'brand, T>) -> QuarterNodePtr<'brand, T> { node.borrow(self.token).deploy() }
// Internal; deploys a tripod.
fn retract_tripod(&mut self, node: QuarterNodePtr<'brand, T>) {
super::retract(node, self.token);
}
// Internal; replace the current tripod with another, retracting the former if any.
fn switch_tripod(&mut self, new_tripod: Option<QuarterNodePtr<'brand, T>>, index: usize) {
self.index = index;
if let Some(tripod) = mem::replace(&mut self.node, new_tripod) {
super::retract(tripod, self.token);
}
}
// Internal; returns a reference to the up GhostNode, and the matching index.
fn peek_up_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
self.as_cursor().peek_up_node()
}
// Internal; returns a reference to the left GhostNode, and the matching index.
fn peek_left_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
self.as_cursor().peek_left_node()
}
// Internal; returns a reference to the right GhostNode, and the matching index.
fn peek_right_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
self.as_cursor().peek_right_node()
}
// Internal; returns a reference to the child GhostNode on the given side, and the matching index.
fn peek_down_node(&self, side: Side) -> (Option<&GhostNode<'brand, T>>, usize) {
self.as_cursor().peek_down_node(side)
}
}
// Logarithmic cursor navigation.
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
/// Creates a new cursor pointing at the front element of the tree, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn new_front(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>) -> Self {
let mut cursor = Self::new(token, tree);
while let Some(_) = cursor.try_move_left() {}
debug_assert_eq!(0, cursor.index);
cursor
}
/// Creates a new cursor pointing at the back element of the tree, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn new_back(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'brand, T>) -> Self {
let mut cursor = Self::new(token, tree);
while let Some(_) = cursor.try_move_right() {}
debug_assert_eq!(cursor.len() - 1, cursor.index);
cursor
}
/// Moves the cursor to the next element, if any.
///
/// If there is no next element, then the cursor moves to the "twilight" non-element, which exists between the root
/// and the leaves.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_next(&mut self) {
let (node, index) = self.peek_next_node();
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
}
/// Moves the cursor to the previous element, if any.
///
/// If there is no previous element, then the cursor moves to the "twilight" non-element, which exists between the root
/// and the leaves.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_prev(&mut self) {
let (node, index) = self.peek_prev_node();
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
}
/// Moves the cursor to the element at the given index.
///
/// If there is no such element, then the cursor moves to the "twilight" non-element, which exists between the front
/// and back element.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
///
/// # Panics
///
/// If `at` is strictly greater than `tree.len()`.
pub fn move_to(&mut self, at: usize) {
if self.index == at {
return;
}
let node = self.peek_at_node(at);
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, at);
}
/// Moves the cursor to the front element.
///
/// If there is no such element, then the cursor moves to the "twilight" non-element.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_to_front(&mut self) {
self.move_to_root();
while let Some(_) = self.try_move_left() {}
}
/// Moves the cursor to the front element.
///
/// If there is no such element, then the cursor moves to the "twilight" non-element.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn move_to_back(&mut self) {
self.move_to_root();
while let Some(_) = self.try_move_right() {}
}
/// Attempts to move the cursor to the next element, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no next element, or is the "twilight" element, does not move.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn try_move_next(&mut self) -> Option<&mut T> {
let (node, index) = self.peek_next_node();
if let Some(_) = node {
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the previous element, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If the element the cursor points to has no previous element, or is the "twilight" element, does not move.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn try_move_prev(&mut self) -> Option<&mut T> {
let (node, index) = self.peek_prev_node();
if let Some(_) = node {
let new_tripod = node.map(|node| self.deploy_tripod(node));
self.switch_tripod(new_tripod, index);
self.current()
} else {
None
}
}
/// Attempts to move the cursor to the element at the given index, if any.
///
/// Returns a reference to the pointed to element, in case of success.
///
/// If there is not such element, or the cursor points to the "twilight" element, does not move.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
///
/// # Panics
///
/// If `at` is strictly greater than `tree.len()`.
pub fn try_move_to(&mut self, at: usize) -> Option<&mut T> {
self.node.as_ref()?;
if self.index == at {
return self.current();
}
let node = self.peek_at_node(at);
if let Some(node) = node {
let new_tripod = Some(self.deploy_tripod(node));
self.switch_tripod(new_tripod, at);
self.current()
} else {
None
}
}
/// Returns a reference to the next element, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn peek_next(&self) -> Option<&T> { self.peek_next_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the previous element, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn peek_prev(&self) -> Option<&T> { self.peek_prev_node().0.map(|node| &node.borrow(self.token).value) }
/// Returns a reference to the element at the given index, if any.
///
/// # Complexity
///
/// - Time: O(log N) in the number of element.
/// - Space: O(1).
pub fn peek_at(&self, at: usize) -> Option<&T> { self.peek_at_node(at).map(|node| &node.borrow(self.token).value) }
// Internal; returns the length of the tree.
fn len(&self) -> usize { self.tree.len(self.token) }
// Internal; returns a reference to the GhostNode at the next index.
fn peek_next_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
self.as_cursor().peek_next_node()
}
// Internal; returns a reference to the GhostNode at the previous index.
fn peek_prev_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
self.as_cursor().peek_prev_node()
}
// Internal; returns a reference to the GhostNode at the specific index.
//
// Panics if the index is "too" out of bounds; returns the "twilight" non-element if the index is only 1 out of bounds.
fn peek_at_node(&self, at: usize) -> Option<&GhostNode<'brand, T>> {
self.as_cursor().peek_at_node(at)
}
}
// Edit cursor operations.
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
/// Inserts a new element in the tree after the current one.
///
/// See `splice_after` for the details.
///
/// A single memory allocation is performed.
pub fn insert_after(&mut self, value: T) {
let mut other = TripodTree::singleton(value, self.token);
self.splice_after(&mut other);
}
/// Inserts a new element in the tree before the current one.
///
/// See `splice_before` for the details.
///
/// A single memory allocation is performed.
pub fn insert_before(&mut self, value: T) {
let mut other = TripodTree::singleton(value, self.token);
self.splice_before(&mut other);
}
/// Removes the current element from the tree.
///
/// See `remove_current_as_tree` for details.
///
/// A single memory deallocation is performed.
pub fn remove_current(&mut self) -> Option<T> {
let removed = self.remove_current_as_tree();
debug_assert!(removed.len(self.token) <= 1, "{} > 1", removed.len(self.token));
removed.root.map(|root| { TripodTree::node_into_inner(root, self.token) })
}
/// Removes the current element from the tree and returns it as a `TripodTree`.
///
/// The removed element is returned, and the cursor is moved to point to the next element, if any.
///
/// If the cursor is pointing at the "twilight" non-element, then no element is removed and `None` is returned.
///
/// # Complexity
///
/// - Time: O(log N) in the number of elements.
/// - Space: O(1).
///
/// No memory allocation nor deallocation occur.
pub fn remove_current_as_tree(&mut self) -> TripodTree<'brand, T> {
// Short circuit if not interesting.
if self.node.is_none() {
return TripodTree::new();
}
self.describe_self("remove_current_as_tree (begin)");
// Memorize index, to restore it.
let index = self.index;
// Push node down until it's a leaf in the deepest sub-tree, recursively => O(log N).
self.sift_down();
// Remove leaf, fixing up parents if any.
let current_tripod = self.node.take().expect("There should be a node");
let _current_size = current_tripod.borrow(self.token).size;
debug_assert_eq!(1, _current_size, "And this node should be a leaf");
let current = if let Some(parent) = current_tripod.borrow_mut(self.token).up.take() {
let parent_tripod = self.deploy_tripod(&parent);
let parent_side = current_tripod.borrow(self.token).is_child_of(parent.borrow(self.token)).expect("Child!");
let current = parent_tripod.borrow_mut(self.token).replace_child(parent_side, parent).expect("Current!");
self.adjust_size(&parent_tripod);
// Removing the left leaf means the parent takes its place, index-wise.
// Removing the right leaf and switching to the parent, however, requires adjusting the index.
if parent_side == Side::Right {
self.index -= 1;
}
// O(log N).
self.rebalance_tree_single(parent_tripod);
self.move_to(index);
current
} else {
// The node is the current root, and it's a leaf => no-one else here!
self.tree.root.take().expect("Non-empty!")
};
self.retract_tripod(current_tripod);
self.describe_self("remove_current_as_tree (end)");
TripodTree::from_quarter(current, self.token)
}
/// Inserts a new tree in the tree after the current one.
///
/// Although the cursor remains pointed to the same element, the position of the element may have changed
/// drastically due to rebalancing.
///
/// If the cursor is pointing at the "twilight" non-element, then the new tree is inserted at the front.
///
/// # Complexity
///
/// - Time: O(log N) in the number of elements.
/// - Space: O(1).
///
/// No memory allocation nor deallocation occur.
pub fn splice_after(&mut self, other: &mut TripodTree<'brand, T>) {
// We'll be getting back to this index.
let original = self.index();
self.splice_impl(Side::Right, other);
self.move_to(original.unwrap_or_else(|| self.len()));
debug_assert_eq!(original, self.index());
}
/// Inserts a new tree in the tree before the current one.
///
/// Although the cursor remains pointed to the same element, the position of the element may have changed
/// drastically due to rebalancing.
///
/// If the cursor is pointing at the "twilight" non-element, then the new tree is inserted at the back.
///
/// # Complexity
///
/// - Time: O(log N) in the number of elements.
/// - Space: O(1).
///
/// No memory allocation nor deallocation occur.
pub fn splice_before(&mut self, other: &mut TripodTree<'brand, T>) {
// We'll be getting back to this index.
let original = self.index();
let other_size = other.len(self.token);
self.splice_impl(Side::Left, other);
self.move_to(original.map(|n| n + other_size).unwrap_or_else(|| self.len()));
debug_assert_eq!(original.map(|n| n + other_size), self.index());
}
/// Splits the tree into two after the current element.
///
/// Returns a tree consisting of everything after the current element.
///
/// If the cursor is pointing at the "twilight" non-element, returns everything.
///
/// # Complexity
///
/// - Time: O(log² N) in the number of elements.
/// - Space: O(1).
///
/// No memory allocation nor deallocation occur.
pub fn split_after(&mut self) -> TripodTree<'brand, T> {
let result = self.split_impl(Side::Right);
self.move_to_back();
result
}
/// Splits the tree into two before the current element.
///
/// Returns a tree consisting of everything before the current element.
///
/// If the cursor is pointing at the "twilight" non-element, returns everything.
///
/// # Complexity
///
/// - Time: O(log N) in the number of elements.
/// - Space: O(1).
///
/// No memory allocation nor deallocation occur.
pub fn split_before(&mut self) -> TripodTree<'brand, T> {
let result = self.split_impl(Side::Left);
self.move_to_front();
result
}
// Internal; sift down current index, until it's a leaf, by pushing it alongst the deepest path.
//
// Complexity: Time O(log N), Space O(1).
fn sift_down(&mut self) {
// O(log N) iterations, each doing O(1) work.
loop {
let current_tripod = self.node.take().expect("Non-twilight");
let _current_size = current_tripod.borrow(self.token).size;
let left_size = current_tripod.borrow(self.token).left_size(self.token);
let right_size = current_tripod.borrow(self.token).right_size(self.token);
debug_assert_eq!(_current_size, 1 + left_size + right_size,
"sift_down - {} != 1 + {} + {}", _current_size, left_size, right_size);
// Leaf!
if left_size == 0 && right_size == 0 {
self.node = Some(current_tripod);
return;
}
// Going down
let side = if left_size > right_size { Side::Left } else { Side::Right };
self.swap_child_from(side, current_tripod);
}
}
// Internal; splice_before/after, without any guarantee with regard to the position of the index.
//
// Complexity: Time O(log² N), Space O(1).
fn splice_impl(&mut self, side: Side, other: &mut TripodTree<'brand, T>) {
self.describe_self("splice_impl (begin)");
let other_root = if let Some(other_root) = other.root.take() {
other_root
} else {
self.describe_self("splice_impl (end) (empty)");
return;
};
if self.tree.is_empty() {
self.index = other_root.borrow(self.token).size;
self.tree.root = Some(other_root);
return;
}
let opposite = side.opposite();
// No root.
if self.index().is_none() {
match side {
// Place at the back.
Side::Left => self.move_to_back(),
// Place at the front.
Side::Right => self.move_to_front(),
}
self.set_subtree(opposite, other_root);
self.describe_self("splice_impl (end) (twilight)");
return;
}
// Otherwise, place at opposite-side-most child of side sub-tree.
if let Some(_) = self.try_move_down(side) {
while let Some(_) = self.try_move_down(opposite) {}
self.set_subtree(opposite, other_root);
} else {
// Unless there's no side child.
self.set_subtree(side, other_root);
}
self.describe_self("splice_impl (end)");
}
// Internal; splits the tree into two, taking all elements on the given side into the new tree.
//
// Complexity: Time O(log² N), Space O(1).
fn split_impl(&mut self, side: Side) -> TripodTree<'brand, T> {
if self.node.is_none() {
self.index = 0;
return mem::replace(self.tree, TripodTree::new());
}
// Special cases, taking a left-most or right-most sub-tree.
{
let node = self.node.as_ref().expect("Non-empty");
match side {
Side::Left if self.range().start == 0 => {
let result = TripodTree { root: Self::take_child(side, node, self.token) };
self.index = 0;
let current_tripod = self.node.take().expect("Non-empty");
self.rebalance_tree_single(current_tripod);
return result;
},
Side::Right if self.range().end == self.len() => {
let result = TripodTree { root: Self::take_child(side, node, self.token) };
let current_tripod = self.node.take().expect("Non-empty");
self.rebalance_tree_single(current_tripod);
return result;
},
_ => (),
}
}
// Computing which elements should go, and which shouldn't, is fairly complicated.
//
// The one exception: when the current node is the root, then one side stays and one side goes!
//
// So... we're going to have a simple plan:
//
// 1. Make the current node root.
// a. Keep its children balanced.
// 2. Strip off its `side` child, this is our tree.
// 3. Repeatedly rebalance until the entire tree is balanced.
// 4. Profit!
self.describe_self("split_impl (begin)");
// 1. Make the current node root => O(log N), from O(log N) iterations each doing O(1) work.
while let Some(parent_side) = self.node.as_ref().and_then(|node| node.borrow(self.token).is_child(self.token)) {
self.move_up();
let parent_tripod = self.node.take().expect("Non-empty");
self.rotate_child_from(parent_side, parent_tripod);
// a. Keep its children balanced.
let parent = self.node.take().expect("Non-empty");
self.rebalance_child(Side::Left, &parent);
self.rebalance_child(Side::Right, &parent);
self.node = Some(parent);
self.describe_self("split_impl (post incremental rotation)");
}
self.describe_self("split_impl (pre split)");
// 2. Strip off its `side` child => O(1).
let result = {
let node = self.node.as_ref().expect("Non-empty");
TripodTree { root: Self::take_child(side, node, self.token) }
};
if side == Side::Left {
debug_assert_eq!(result.len(self.token), self.index);
self.index = 0;
}
self.describe_self("split_impl (post split)");
// 3. Repeatedly rebalance, until it's balanced => O(log N) iterations each doing O(log N) work.
let current_tripod = self.node.take().expect("Non-empty");
self.rebalance_subtree_complete(current_tripod);
result
}
// Internal; sets the tree as the child of the current node. Fixes up indexes and rebalances.
//
// Leaves the cursor pointing to the root.
//
// Requirement: there must be not such child.
//
// Complexity: Time O(log² N), Space O(1).
fn set_subtree(&mut self, side: Side, other_root: QuarterNodePtr<'brand, T>) {
debug_assert!(self.node.is_some());
debug_assert!(side == Side::Right || self.peek_left().is_none());
debug_assert!(side == Side::Left || self.peek_right().is_none());
self.describe_self("set_subtree (begin)");
let root_tripod = self.node.take().expect("Not empty");
let other_tripod = self.deploy_tripod(&other_root);
let other_size = other_tripod.borrow(self.token).size;
let current = root_tripod.borrow_mut(self.token).replace_child(side, other_root).expect("Side child - pointing to self");
other_tripod.borrow_mut(self.token).up.replace(current);
self.retract_tripod(other_tripod);
root_tripod.borrow_mut(self.token).size += other_size;
if side == Side::Left {
self.index += other_size;
}
self.rebalance_tree_complete(root_tripod);
self.describe_self("set_child (end)");
}
// Internal; rebalances the tree up to the root, adjusting the node size as it goes.
//
// The cursor is left pointing to the root. The index is adjusted accordingly.
//
// Complexity: Time O(log² N), Space O(1).
fn rebalance_tree_complete(&mut self, root_tripod: QuarterNodePtr<'brand, T>) {
self.describe_node("rebalance_tree_complete (begin)", &root_tripod);
self.rebalance_subtree_complete(root_tripod);
// O(log N) iterations of O(log N) complexity.
while let Some(_) = self.try_move_up() {
self.describe_self("rebalance_tree_complete (loop)");
let root_tripod = self.node.take().expect("Not empty");
self.adjust_size(&root_tripod);
self.rebalance_subtree_complete(root_tripod)
}
self.describe_self("rebalance_tree_complete (end)");
}
// Internal; rebalances the tree up to the root, of at most 1 single step, adjusting the node size as it goes.
//
// The cursor is left pointing to the root. The index is adjusted accordingly.
//
// Complexity: Time O(log N), Space O(1).
fn rebalance_tree_single(&mut self, root_tripod: QuarterNodePtr<'brand, T>) {
self.describe_node("rebalance_tree_single (begin)", &root_tripod);
self.rebalance_subtree_single(root_tripod);
while let Some(_) = self.try_move_up() {
self.describe_self("rebalance_tree_single (loop)");
let root_tripod = self.node.take().expect("Not empty");
self.adjust_size(&root_tripod);
self.rebalance_subtree_single(root_tripod)
}
self.describe_self("rebalance_tree_single (end)");
}
// Internal; rebalances the current sub-tree, if necessary.
//
// The cursor is left pointing at the root of the sub-tree, whether it changed or not. The index is adjusted
// accordingly.
//
// Complexity: Time O(log N), Space O(1).
fn rebalance_subtree_complete(&mut self, mut root_tripod: QuarterNodePtr<'brand, T>) {
self.describe_node("rebalance_subtree_complete (begin)", &root_tripod);
let mut previous_index = self.index;
loop {
self.rebalance_subtree_single(root_tripod);
if previous_index == self.index {
break;
}
previous_index = self.index;
root_tripod = self.node.take().expect("Non-empty");
self.rebalance_child(Side::Left, &root_tripod);
self.rebalance_child(Side::Right, &root_tripod);
self.describe_node("rebalance_subtree_complete (loop)", &root_tripod);
}
self.describe_self("rebalance_subtree_complete (end)");
}
// Internal; rebalances the current sub-tree by 1 single step, if necessary.
//
// The cursor is left pointing at the root of the sub-tree, whether it changed or not. The index is adjusted
// accordingly.
//
// Complexity: Time O(1), Space O(1).
fn rebalance_subtree_single(&mut self, root_tripod: QuarterNodePtr<'brand, T>) {
debug_assert!(self.node.is_none());
let left_size = root_tripod.borrow(self.token).left_size(self.token);
let right_size = root_tripod.borrow(self.token).right_size(self.token);
if left_size > 2 * right_size + 1 {
let root_tripod = self.prepare_rotation(Side::Left, root_tripod);
self.rotate_child_from(Side::Left, root_tripod);
} else if right_size > 2 * left_size + 1 {
let root_tripod = self.prepare_rotation(Side::Right, root_tripod);
self.rotate_child_from(Side::Right, root_tripod);
} else {
self.node = Some(root_tripod);
}
}
// Internal; rebalances the parent's child on the designated side.
//
// Complexity: Time O(1), Space O(1).
fn rebalance_child(&mut self, side: Side, parent: &GhostNode<'brand, T>) {
if let Some(child) = parent.borrow_mut(self.token).take_child(side) {
let child_tripod = child.borrow(self.token).deploy();
let child_index = child_tripod.borrow(self.token).index(self.token);
let parent_from_child = child_tripod.borrow_mut(self.token).up.take();
let mut tree = TripodTree { root: Some(child) };
let child_tripod = {
let mut cursor = CursorMut { token: self.token, tree: &mut tree, node: None, index: child_index };
cursor.rebalance_subtree_single(child_tripod);
cursor.node.take().expect("Non-empty")
};
let child = tree.root.take().expect("Non-empty");
child.borrow(self.token).retract(child_tripod);
child.borrow_mut(self.token).up = parent_from_child;
parent.borrow_mut(self.token).set_child(side, child);
}
}
// Internal; swaps the current root of the sub-tree with its child.
//
// The cursor is left pointing at the former root, the index is adjusted accordingly.
//
// Invoked with Side::Left:
//
// Pa Pa
// | |
// Root Piv
// / \ / \
// / \ / \
// Piv X => Root X
// / \ / \
// Y Z Y Z
//
// Invoked with Side::Right:
//
// Pa Pa
// | |
// Root Piv
// / \ / \
// / \ / \
// X Piv => X Root
// / \ / \
// Y Z Y Z
//
// Legend:
// - Pa: Parent, potentially tree.root.
// - Root: the current root of the sub-tree.
// - Piv: the pivot, or future root of the sub-tree post-rotation.
//
// Complexity: Time O(1), Space O(1).
fn swap_child_from(&mut self, side: Side, root_tripod: QuarterNodePtr<'brand, T>) {
debug_assert!(self.node.is_none());
self.describe_node("swap_child_from (begin)", &root_tripod);
let opposite = side.opposite();
// Pick out pivot.
let pivot = root_tripod.borrow_mut(self.token).take_child(side).expect("Selected child - otherwise we shouldn't attempt to swap");
let pivot_tripod = self.deploy_tripod(&pivot);
self.describe_node("swap_child_from (pivot)", &pivot_tripod);
// Swap opposite children, if any.
{
let opposite_root = root_tripod.borrow_mut(self.token).take_child(opposite);
let opposite_pivot = pivot_tripod.borrow_mut(self.token).take_child(opposite);
match (opposite_root, opposite_pivot) {
(Some(opposite_root), Some(opposite_pivot)) => {
let root_from_opposite = opposite_root.borrow_mut(self.token).up.take();
let pivot_from_opposite = opposite_pivot.borrow_mut(self.token).up.take();
opposite_pivot.borrow_mut(self.token).up = root_from_opposite;
opposite_root.borrow_mut(self.token).up = pivot_from_opposite;
root_tripod.borrow_mut(self.token).set_child(opposite, opposite_pivot);
pivot_tripod.borrow_mut(self.token).set_child(opposite, opposite_root);
},
(None, Some(opposite_pivot)) => {
let root_from_self = root_tripod.borrow_mut(self.token).child_mut(opposite).take().expect("root.opposite == root");
let pivot_from_opposite = opposite_pivot.borrow_mut(self.token).up.replace(root_from_self).expect("pivot.opposite.up == pivot");
root_tripod.borrow_mut(self.token).set_child(opposite, opposite_pivot);
pivot_tripod.borrow_mut(self.token).set_child(opposite, pivot_from_opposite);
},
(Some(opposite_root), None) => {
let pivot_from_self = pivot_tripod.borrow_mut(self.token).child_mut(opposite).take().expect("pivot.opposite == pivot");
let root_from_opposite = opposite_root.borrow_mut(self.token).up.replace(pivot_from_self).expect("root.opposite.up == root");
pivot_tripod.borrow_mut(self.token).set_child(opposite, opposite_root);
root_tripod.borrow_mut(self.token).set_child(opposite, root_from_opposite);
},
(None, None) => (),
}
};
// Swap parent.
let root_from_pivot = pivot_tripod.borrow_mut(self.token).up.take().expect("pivot.up == root");
let root_from_parent = {
let parent_root = root_tripod.borrow_mut(self.token).up.take();
if let Some(parent_root) = parent_root {
let parent_side = root_tripod.borrow(self.token).is_child_of(parent_root.borrow(self.token)).expect("Child!");
let root_from_parent = parent_root.borrow_mut(self.token).replace_child(parent_side, pivot).expect("parent.child == root");
pivot_tripod.borrow_mut(self.token).up = Some(parent_root);
root_from_parent
} else {
// root_tripod is root.
self.tree.root.replace(pivot).expect("root")
}
};
// Swap selected child and parent, if any.
{
let child_pivot = pivot_tripod.borrow_mut(self.token).take_child(side);
if let Some(child_pivot) = child_pivot {
pivot_tripod.borrow_mut(self.token).set_child(side, root_from_parent);
let pivot_from_child = child_pivot.borrow_mut(self.token).up.replace(root_from_pivot).expect("child.up == pivot");
root_tripod.borrow_mut(self.token).set_child(side, pivot_from_child);
} else {
// Pivot.side pointing to self.
let pivot_from_self = pivot_tripod.borrow_mut(self.token).replace_child(side, root_from_parent);
root_tripod.borrow_mut(self.token).up = pivot_from_self;
root_tripod.borrow_mut(self.token).set_child(side, root_from_pivot);
}
}
self.adjust_size(&root_tripod);
self.adjust_size(&pivot_tripod);
self.retract_tripod(pivot_tripod);
let new_index = {
let opposite_pivot_size = root_tripod.borrow(self.token).child_size(opposite, self.token);
match side {
Side::Left => self.index - 1 - opposite_pivot_size,
Side::Right => self.index + 1 + opposite_pivot_size,
}
};
self.switch_tripod(Some(root_tripod), new_index);
self.describe_self("swap_child_from (end)");
}
// Internal; rotates the current sub-tree so that the selected child becomes the root.
//
// The cursor is left pointing at the new root of the sub-tree (pivot), the index is adjusted accordingly.
//
// Invoked with Side::Left:
//
// Pa Pa
// | |
// Root Piv
// / \ / \
// / \ / \
// Piv X => Y Root
// / \ / \
// Y Piv.OS Piv.OS X
//
// Invoked with Side::Right:
//
// Pa Pa
// | |
// Root Piv
// / \ / \
// / \ / \
// X Piv => Root Y
// / \ / \
// Piv.OS Y X Piv.OS
//
// Legend:
// - Pa: Parent, potentially tree.root.
// - Root: the current root of the sub-tree.
// - Piv: the pivot, or future root of the sub-tree post-rotation.
// - Piv.OS: the child of the pivot, on the opposite side.
//
// Complexity: Time O(1), Space O(1).
fn rotate_child_from(&mut self, side: Side, root_tripod: QuarterNodePtr<'brand, T>) {
debug_assert!(self.node.is_none());
self.describe_node("rotate_child_from (begin)", &root_tripod);
let opposite = side.opposite();
// Pick out pivot.
let pivot = root_tripod.borrow_mut(self.token).take_child(side).expect("Selected child - otherwise we shouldn't attempt to rotate");
let pivot_tripod = self.deploy_tripod(&pivot);
let root_from_pivot = pivot_tripod.borrow_mut(self.token).up.take().expect("Parent - root!");
debug_assert!(root_tripod.borrow(self.token).is_aliased(Some(&root_from_pivot)), "root == pivot.up");
// Extract pivot pointer from opposite-child up.
let pivot_from_opposite_child = {
let opposite_child = pivot_tripod.borrow_mut(self.token).child_mut(opposite).take().expect("Either child or pivot-self");
// Aliased => actual self-points to pivot, which didn't have an opposite-side child.
let (pivot, child) = if pivot_tripod.borrow(self.token).is_aliased(Some(&opposite_child)) {
(opposite_child, root_from_pivot)
} else {
let pivot = opposite_child.borrow_mut(self.token).up.replace(root_from_pivot).expect("opposite_child.up == pivot");
(pivot, opposite_child)
};
debug_assert!(pivot.borrow(self.token).is_aliased(Some(&pivot_tripod)), "pivot.opposite_child.up == pivot");
root_tripod.borrow_mut(self.token).set_child(side, child);
pivot
};
// Switch pointer-to-root to pointer-to-pivot in parent.
let root_from_parent = {
let parent = root_tripod.borrow_mut(self.token).up.replace(pivot);
if let Some(parent) = parent {
let parent_side = root_tripod.borrow(self.token).is_child_of(parent.borrow(self.token)).expect("root.up == parent!");
let result = parent.borrow_mut(self.token).replace_child(parent_side, pivot_from_opposite_child)
.expect("parent.parent_side_child == root");
pivot_tripod.borrow_mut(self.token).up = Some(parent);
result
} else {
self.tree.root.replace(pivot_from_opposite_child).expect("tree.root == root")
}
};
debug_assert!(root_tripod.borrow(self.token).is_aliased(Some(&root_from_parent)), "root == pivot.up");
pivot_tripod.borrow_mut(self.token).set_child(opposite, root_from_parent);
self.adjust_size(&root_tripod);
self.adjust_size(&pivot_tripod);
let index = {
// Piv.OS size.
let opposite_size = root_tripod.borrow(self.token).child_size(side, self.token);
match side {
Side::Left => self.index - 1 - opposite_size,
Side::Right => self.index + 1 + opposite_size,
}
};
self.retract_tripod(root_tripod);
self.switch_tripod(Some(pivot_tripod), index);
self.describe_self("rotate_child_from (end)");
}
// Internal; prepare the side child for promotion to root.
//
// The cursor is not pointing to any element, as the root_tripod is returned. The index is unmodified.
//
// During the rotation, the pivot opposite side child is moved to be the side child of the root. If this child is
// deeper than its sibling, the result is not balanced:
//
// Root Piv
// / \ / \
// / \ / \
// Piv X => Y Root
// / \ / \
// Y Piv.OS Piv.OS X
// \ \
// A A
//
// Hence, if necessary, a rotation must be performed to ensure that the pivot "side" child is the root of the
// deepest sub-tree prior to doing the main rotation.
//
// Complexity: Time O(1), Space O(1).
fn prepare_rotation(&mut self, side: Side, root_tripod: QuarterNodePtr<'brand, T>) -> QuarterNodePtr<'brand, T> {
debug_assert!(self.node.is_none());
self.describe_node("prepare_rotation (begin)", &root_tripod);
let _original_index = self.index();
let _original_address = &*root_tripod as *const _;
let (pivot_selected, pivot_opposite) = {
let pivot_node = root_tripod.borrow(self.token).child(side).expect("Pivot!");
let selected = pivot_node.borrow(self.token).child_size(side, self.token);
let opposite = pivot_node.borrow(self.token).child_size(side.opposite(), self.token);
(selected, opposite)
};
if pivot_opposite >= 2 * pivot_selected {
self.node = Some(root_tripod);
// Move to pivot.
match side {
Side::Left => self.move_left(),
Side::Right => self.move_right(),
}
let pivot_tripod = self.node.take().expect("Pivot");
self.rotate_child_from(side.opposite(), pivot_tripod);
self.move_up();
let root_tripod = self.node.take().expect("Root");
debug_assert_eq!(_original_index, self.index());
debug_assert_eq!(_original_address, &*root_tripod as *const _);
self.describe_node("prepare_rotation (end) (modified)", &root_tripod);
root_tripod
} else {
self.describe_node("prepare_rotation (end) (passthrough)", &root_tripod);
root_tripod
}
}
// Internal; adjusts the size of the node by adding up the size of its children.
//
// Complexity: Time O(1), Space O(1).
fn adjust_size(&mut self, node: &GhostNode<'brand, T>) {
let left_size = node.borrow(self.token).left_size(self.token);
let right_size = node.borrow(self.token).right_size(self.token);
node.borrow_mut(self.token).size = 1 + left_size + right_size;
self.describe_node("adjust_size (adjusted)", node);
}
// Internal; pops of the specified child, if any, adjusting size and pointers.
//
// Complexity: Time O(1), Space O(1).
fn take_child(side: Side, node: &GhostNode<'brand, T>, token: &mut GhostToken<'brand>) -> Option<QuarterNodePtr<'brand, T>> {
let child = node.borrow_mut(token).take_child(side)?;
let node_from_child = child.borrow_mut(token).up.take().expect("child.up == node");
node.borrow_mut(token).set_child(side, node_from_child);
let child_size = child.borrow(token).size;
node.borrow_mut(token).size -= child_size;
Some(child)
}
}
// Debugging code
#[allow(dead_code)]
impl<'a, 'brand, T> CursorMut<'a, 'brand, T> {
// Internal; describe the node: sizes, parent and children, ...
#[cfg(all(test, feature = "test-tree-debug"))]
fn describe_node(&self, caller: &str, node: &GhostNode<'brand, T>) {
let current_size = node.borrow(self.token).size;
let left_size = node.borrow(self.token).left_size(self.token);
let right_size = node.borrow(self.token).right_size(self.token);
eprintln!(
"{} - list: {}, index: {}, node: {:?} (size {}), up: {:?}, left: {:?} (size {}), right: {:?} (size {})",
caller,
self.len(),
self.index,
node as *const _, current_size,
node.borrow(self.token).up.as_ref().map(|node| node as *const _),
node.borrow(self.token).left().map(|node| node as *const _), left_size,
node.borrow(self.token).right().map(|node| node as *const _), right_size
);
}
// Internal (dummy)
#[cfg(not(all(test, feature = "test-tree-debug")))]
fn describe_node(&self, _: &str, _: &GhostNode<'brand, T>) {}
// Internal; describe the cursor itself.
#[cfg(all(test, feature = "test-tree-debug"))]
fn describe_self(&self, caller: &str) {
if let Some(node) = self.node.as_ref() {
self.describe_node(caller, node);
} else {
eprintln!(
"{} - list: {}, index: {}, current: None",
caller,
self.len(),
self.index
);
};
}
#[cfg(not(all(test, feature = "test-tree-debug")))]
fn describe_self(&self, _: &str) {}
}
impl<'a, 'brand, T> Drop for CursorMut<'a, 'brand, T> {
fn drop(&mut self) {
if let Some(tripod) = self.node.take() {
super::retract(tripod, self.token);
}
}
}
#[cfg(test)]
mod tests {
use std::ops::Range;
use super::super::tests::*;
use super::*;
#[derive(Clone, Copy)]
struct Position<'a> {
index: usize,
start: usize,
end: usize,
current: &'a str,
up: Option<&'a str>,
left: Option<&'a str>,
right: Option<&'a str>,
prev: Option<&'a str>,
next: Option<&'a str>,
}
impl<'a> Position<'a> {
const fn new(
index: usize,
range: Range<usize>,
current: &'a str,
up: Option<&'a str>,
left: Option<&'a str>,
right: Option<&'a str>,
prev: Option<&'a str>,
next: Option<&'a str>
)
-> Self
{
let (start, end) = (range.start, range.end);
Self { index, start, end, current, up, left, right, prev, next, }
}
const fn range(&self) -> Range<usize> { self.start..self.end }
}
#[track_caller]
fn assert_twilight(cursor: Cursor<'_, '_, String>) {
assert_eq!(None, cursor.index());
assert_eq!(0..0, cursor.range());
assert_eq!(None, cursor.current());
}
#[track_caller]
fn assert_neighbours(parent: Option<&str>, left: Option<&str>, right: Option<&str>, cursor: Cursor<'_, '_, String>) {
assert_eq!(parent, cursor.peek_up().map(String::as_str), "Parent");
assert_eq!(left, cursor.peek_left().map(String::as_str), "Left Child");
assert_eq!(right, cursor.peek_right().map(String::as_str), "Right Child");
}
#[track_caller]
fn assert_log_neighbours(prev: Option<&str>, next: Option<&str>, cursor: Cursor<'_, '_, String>) {
assert_eq!(prev, cursor.peek_prev().map(String::as_str), "Prev");
assert_eq!(next, cursor.peek_next().map(String::as_str), "Next");
}
#[track_caller]
fn assert_empty(cursor: Cursor<'_, '_, String>) {
assert_twilight(cursor);
assert_neighbours(None, None, None, cursor);
assert_log_neighbours(None, None, cursor);
}
#[track_caller]
fn assert_current(at: usize, range: Range<usize>, element: &str, cursor: Cursor<'_, '_, String>) {
assert_eq!(Some(at), cursor.index());
assert_eq!(range, cursor.range());
assert_eq!(Some(element), cursor.current().map(String::as_str), "Current");
}
#[track_caller]
fn assert_position(pos: Position<'_>, cursor: Cursor<'_, '_, String>) {
assert_current(pos.index, pos.range(), pos.current, cursor);
assert_neighbours(pos.up, pos.left, pos.right, cursor);
assert_log_neighbours(pos.prev, pos.next, cursor);
}
#[track_caller]
fn assert_twilight_mut(cursor: &mut CursorMut<'_, '_, String>) {
assert_eq!(None, cursor.index());
assert_eq!(0..0, cursor.range());
assert_eq!(None, cursor.current());
}
#[track_caller]
fn assert_neighbours_mut(parent: Option<&str>, left: Option<&str>, right: Option<&str>, cursor: &CursorMut<'_, '_, String>) {
assert_eq!(parent, cursor.peek_up().map(|s| &**s), "Parent");
assert_eq!(left, cursor.peek_left().map(|s| &**s), "Left Child");
assert_eq!(right, cursor.peek_right().map(|s| &**s), "Right Child");
}
#[track_caller]
fn assert_log_neighbours_mut(prev: Option<&str>, next: Option<&str>, cursor: &CursorMut<'_, '_, String>) {
assert_eq!(prev, cursor.peek_prev().map(|s| &**s), "Prev");
assert_eq!(next, cursor.peek_next().map(|s| &**s), "Next");
}
#[track_caller]
fn assert_empty_mut(cursor: &mut CursorMut<'_, '_, String>) {
assert_twilight_mut(cursor);
assert_neighbours_mut(None, None, None, cursor);
assert_log_neighbours_mut(None, None, cursor);
}
#[track_caller]
fn assert_current_mut(at: usize, range: Range<usize>, element: &str, cursor: &mut CursorMut<'_, '_, String>) {
assert_eq!(Some(at), cursor.index());
assert_eq!(range, cursor.range());
assert_eq!(Some(element), cursor.current().map(|s| &**s), "Current");
}
#[track_caller]
fn assert_position_mut(pos: Position<'_>, cursor: &mut CursorMut<'_, '_, String>) {
assert_current_mut(pos.index, pos.range(), pos.current, cursor);
assert_neighbours_mut(pos.up, pos.left, pos.right, cursor);
assert_log_neighbours_mut(pos.prev, pos.next, cursor);
}
//
// Movement.
//
#[test]
fn cursor_empty() {
with_tree(&[][..], |token, tree| {
let mut cursor = tree.cursor(token);
assert_empty(cursor);
assert_eq!(None, cursor.try_move_up());
assert_empty(cursor);
assert_eq!(None, cursor.try_move_left());
assert_empty(cursor);
assert_eq!(None, cursor.try_move_right());
assert_empty(cursor);
assert_eq!(None, cursor.try_move_prev());
assert_empty(cursor);
assert_eq!(None, cursor.try_move_next());
assert_empty(cursor);
assert_eq!(None, cursor.try_move_to(0));
assert_empty(cursor);
cursor.move_up();
assert_empty(cursor);
cursor.move_left();
assert_empty(cursor);
cursor.move_right();
assert_empty(cursor);
cursor.move_prev();
assert_empty(cursor);
cursor.move_next();
assert_empty(cursor);
cursor.move_to(0);
assert_empty(cursor);
});
}
#[test]
fn cursor_mut_empty() {
with_tree(&[][..], |token, tree| {
let mut cursor = tree.cursor_mut(token);
assert_empty_mut(&mut cursor);
assert_eq!(None, cursor.try_move_up());
assert_empty_mut(&mut cursor);
assert_eq!(None, cursor.try_move_left());
assert_empty_mut(&mut cursor);
assert_eq!(None, cursor.try_move_right());
assert_empty_mut(&mut cursor);
assert_eq!(None, cursor.try_move_prev());
assert_empty_mut(&mut cursor);
assert_eq!(None, cursor.try_move_next());
assert_empty_mut(&mut cursor);
assert_eq!(None, cursor.try_move_to(0));
assert_empty_mut(&mut cursor);
cursor.move_up();
assert_empty_mut(&mut cursor);
cursor.move_left();
assert_empty_mut(&mut cursor);
cursor.move_right();
assert_empty_mut(&mut cursor);
cursor.move_prev();
assert_empty_mut(&mut cursor);
cursor.move_next();
assert_empty_mut(&mut cursor);
cursor.move_to(0);
assert_empty_mut(&mut cursor);
});
}
#[test]
fn cursor_brush_move_up_left_right() {
const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL"));
const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR"));
const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None);
const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root"));
with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| {
let mut cursor = tree.cursor(token);
assert_position(ROOT, cursor);
cursor.move_up();
assert_twilight(cursor);
cursor.move_left();
assert_position(ROOT, cursor);
cursor.move_up();
cursor.move_right();
assert_position(ROOT, cursor);
cursor.move_right();
assert_position(RIGHT, cursor);
cursor.move_up();
cursor.move_left();
assert_position(LEFT, cursor);
cursor.move_right();
assert_position(LR, cursor);
cursor.move_right();
assert_twilight(cursor);
cursor.move_left();
assert_position(ROOT, cursor);
cursor.move_left();
assert_position(LEFT, cursor);
cursor.move_left();
assert_twilight(cursor);
});
}
#[test]
fn cursor_mut_brush_move_up_left_right() {
const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL"));
const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR"));
const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None);
const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root"));
with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| {
let mut cursor = tree.cursor_mut(token);
assert_position_mut(ROOT, &mut cursor);
cursor.move_up();
assert_twilight_mut(&mut cursor);
cursor.move_left();
assert_position_mut(ROOT, &mut cursor);
cursor.move_up();
cursor.move_right();
assert_position_mut(ROOT, &mut cursor);
cursor.move_right();
assert_position_mut(RIGHT, &mut cursor);
cursor.move_up();
cursor.move_left();
assert_position_mut(LEFT, &mut cursor);
cursor.move_right();
assert_position_mut(LR, &mut cursor);
cursor.move_right();
assert_twilight_mut(&mut cursor);
cursor.move_left();
assert_position_mut(ROOT, &mut cursor);
cursor.move_left();
assert_position_mut(LEFT, &mut cursor);
cursor.move_left();
assert_twilight_mut(&mut cursor);
});
}
#[test]
fn cursor_brush_move_prev_next() {
const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR"));
const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root"));
const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL"));
const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R"));
const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None);
with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| {
let mut cursor = tree.cursor_front(token);
for position in &[LEFT, LR, ROOT, RL, RIGHT] {
assert_position(*position, cursor);
cursor.move_next();
}
assert_twilight(cursor);
for position in &[RIGHT, RL, ROOT, LR, LEFT] {
cursor.move_prev();
assert_position(*position, cursor);
}
cursor.move_prev();
assert_twilight(cursor);
cursor.move_next();
assert_position(LEFT, cursor);
cursor = tree.cursor_back(token);
assert_position(RIGHT, cursor);
});
}
#[test]
fn cursor_mut_brush_move_prev_next() {
const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR"));
const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root"));
const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL"));
const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R"));
const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None);
with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| {
{
let mut cursor = tree.cursor_front_mut(token);
for position in &[LEFT, LR, ROOT, RL, RIGHT] {
assert_position_mut(*position, &mut cursor);
cursor.move_next();
}
assert_twilight_mut(&mut cursor);
for position in &[RIGHT, RL, ROOT, LR, LEFT] {
cursor.move_prev();
assert_position_mut(*position, &mut cursor);
}
cursor.move_prev();
assert_twilight_mut(&mut cursor);
cursor.move_next();
assert_position_mut(LEFT, &mut cursor);
}
let mut cursor = tree.cursor_back_mut(token);
assert_position_mut(RIGHT, &mut cursor);
});
}
#[test]
fn cursor_brush_move_to() {
const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR"));
const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some("L"), Some("Root"));
const ROOT: Position<'static> = Position::new(2, 0..5, "Root", None, Some("L"), Some("R"), Some("LR"), Some("RL"));
const RL: Position<'static> = Position::new(3, 3..4, "RL", Some("R"), None, None, Some("Root"), Some("R"));
const RIGHT: Position<'static> = Position::new(4, 3..5, "R", Some("Root"), Some("RL"), None, Some("RL"), None);
const POSITIONS: [Position<'static>; 5] = [LEFT, LR, ROOT, RL, RIGHT];
with_tree(&["Root", "L", "R", "", "LR", "RL"], |token, tree| {
let mut cursor = tree.cursor(token);
for offset in 0..POSITIONS.len() {
cursor.move_to(POSITIONS.len());
assert_twilight(cursor);
for base in &[1, 0, 2, 4, 3, 0, 2, 4, 1, 3, 2, 0, 3, 1, 4] {
let index = (*base + offset) % POSITIONS.len();
cursor.move_to(index);
assert_position(POSITIONS[index], cursor);
}
}
});
}
#[test]
fn cursor_mut_brush_move_to() {
const LEFT: Position<'static> = Position::new(0, 0..2, "L", Some("Root"), None, Some("LR"), None, Some("LR"));
const LR: Position<'static> = Position::new(1, 1..2, "LR", Some("L"), None, None, Some
gitextract_xxgw4ag_/
├── .gitignore
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
└── src/
├── lib.rs
├── linked_list/
│ ├── cursor.rs
│ └── iter.rs
├── linked_list.rs
├── tripod_list/
│ ├── cursor.rs
│ └── iter.rs
├── tripod_list.rs
├── tripod_tree/
│ ├── cursor.rs
│ └── iter.rs
└── tripod_tree.rs
SYMBOL INDEX (448 symbols across 9 files)
FILE: src/linked_list.rs
type LinkedList (line 27) | pub struct LinkedList<'brand, T> {
function new (line 33) | pub const fn new() -> Self { Self { head_tail: None } }
function iter (line 36) | pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'br...
function cursor_front (line 41) | pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Curs...
function cursor_back (line 46) | pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Curso...
function is_empty (line 51) | pub fn is_empty(&self) -> bool { self.head_tail.is_none() }
function len (line 60) | pub fn len(&self, token: &GhostToken<'brand>) -> usize { self.iter(token...
function clear (line 67) | pub fn clear(&mut self, token: &mut GhostToken<'brand>) {
function front (line 72) | pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a ...
function front_mut (line 79) | pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) ->...
function back (line 86) | pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
function back_mut (line 93) | pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> ...
function push_front (line 100) | pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) {
function pop_front (line 117) | pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
function push_back (line 135) | pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) {
function pop_back (line 152) | pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
function new_halves (line 169) | fn new_halves(value: T) -> (HalfNodePtr<'brand, T>, HalfNodePtr<'brand, ...
function into_inner (line 176) | fn into_inner(left: HalfNodePtr<'brand, T>, right: HalfNodePtr<'brand, T...
function append (line 200) | pub fn append(&mut self, other: &mut Self, token: &mut GhostToken<'brand...
function prepend (line 241) | pub fn prepend(&mut self, other: &mut Self, token: &mut GhostToken<'bran...
function cursor_front_mut (line 247) | pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'bra...
function cursor_back_mut (line 252) | pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'bran...
function split_off (line 265) | pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -...
function remove (line 292) | pub fn remove(&mut self, at: usize, token: &mut GhostToken<'brand>) -> O...
method default (line 318) | fn default() -> Self { Self::new() }
type Node (line 325) | struct Node<'brand, T> {
type GhostNode (line 331) | type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>;
type HalfNodePtr (line 332) | type HalfNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 1, 2>;
type FullNodePtr (line 333) | type FullNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 2, 2>;
function with_list (line 342) | pub(crate) fn with_list<T, R, F>(initial: Vec<T>, fun: F) -> R
FILE: src/linked_list/cursor.rs
type Cursor (line 12) | pub struct Cursor<'a, 'brand, T> {
function new_front (line 19) | pub fn new_front(token: &'a GhostToken<'brand>, list: &'a LinkedList<'br...
function new_back (line 26) | pub fn new_back(token: &'a GhostToken<'brand>, list: &'a LinkedList<'bra...
function move_next (line 36) | pub fn move_next(&mut self) -> Result<(), ()> {
function move_prev (line 49) | pub fn move_prev(&mut self) -> Result<(), ()> {
function current (line 61) | pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borr...
function peek_next (line 64) | pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().map(|no...
function peek_prev (line 67) | pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().map(|no...
function peek_next_node (line 70) | fn peek_next_node(&self) -> Option<&'a GhostNode<'brand, T>> {
function peek_prev_node (line 75) | fn peek_prev_node(&self) -> Option<&'a GhostNode<'brand, T>> {
type CursorMut (line 82) | pub struct CursorMut<'a, 'brand, T> {
function new_front (line 89) | pub fn new_front(token: &'a mut GhostToken<'brand>, list: &'a LinkedList...
function new_back (line 97) | pub fn new_back(token: &'a mut GhostToken<'brand>, list: &'a LinkedList<...
function into_cursor (line 105) | pub fn into_cursor(self) -> Cursor<'a, 'brand, T> {
function move_next (line 115) | pub fn move_next(&mut self) -> Result<(), ()> {
function move_prev (line 123) | pub fn move_prev(&mut self) -> Result<(), ()> {
function current (line 130) | pub fn current(&mut self) -> Option<&mut T> { self.inner.borrow_mut().ma...
function peek_next (line 138) | pub fn peek_next(&self) -> Option<&T> {
function peek_prev (line 150) | pub fn peek_prev(&self) -> Option<&T> {
function peek_next_node (line 157) | fn peek_next_node(&self) -> Option<&GhostNode<'brand, T>> {
function peek_prev_node (line 162) | fn peek_prev_node(&self) -> Option<&GhostNode<'brand, T>> {
function cursor_assert_none (line 176) | fn cursor_assert_none<'a, 'brand, T>(cursor: &Cursor<'a, 'brand, T>)
function cursor_brush_front_empty (line 186) | fn cursor_brush_front_empty() {
function cursor_brush_back_empty (line 201) | fn cursor_brush_back_empty() {
function cursor_brush_move_next (line 216) | fn cursor_brush_move_next() {
function cursor_brush_move_prev (line 259) | fn cursor_brush_move_prev() {
function cursor_mut_assert_none (line 312) | fn cursor_mut_assert_none<'a, 'brand, T>(cursor: &mut CursorMut<'a, 'bra...
function cursor_mut_brush_front_empty (line 322) | fn cursor_mut_brush_front_empty() {
function cursor_mut_brush_back_empty (line 337) | fn cursor_mut_brush_back_empty() {
function cursor_mut_brush_move_next (line 352) | fn cursor_mut_brush_move_next() {
function cursor_mut_brush_move_prev (line 395) | fn cursor_mut_brush_move_prev() {
FILE: src/linked_list/iter.rs
type Iter (line 6) | pub struct Iter<'a, 'brand, T> {
function new (line 13) | pub fn new(token: &'a GhostToken<'brand>, list: &'a LinkedList<'brand, T...
type Item (line 23) | type Item = &'a T;
method next (line 25) | fn next(&mut self) -> Option<Self::Item> {
method next_back (line 44) | fn next_back(&mut self) -> Option<Self::Item> {
function empty (line 69) | fn empty() {
function forward (line 79) | fn forward() {
function backward (line 94) | fn backward() {
function alternate (line 109) | fn alternate() {
function alternate_other (line 125) | fn alternate_other() {
FILE: src/tripod_list.rs
type TripodList (line 26) | pub struct TripodList<'brand, T> {
function new (line 33) | pub fn new() -> Self { Self::default() }
function append (line 44) | pub fn append(&mut self, other: &mut Self, token: &mut GhostToken<'brand...
function prepend (line 80) | pub fn prepend(&mut self, other: &mut Self, token: &mut GhostToken<'bran...
function iter (line 86) | pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'br...
function cursor_front (line 91) | pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Curs...
function cursor_front_mut (line 96) | pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'bra...
function cursor_back (line 101) | pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Curso...
function cursor_back_mut (line 106) | pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'bran...
function is_empty (line 111) | pub fn is_empty(&self) -> bool { self.length == 0 }
function len (line 114) | pub fn len(&self) -> usize { self.length }
function clear (line 121) | pub fn clear(&mut self, token: &mut GhostToken<'brand>) {
function front (line 126) | pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a ...
function front_mut (line 131) | pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) ->...
function back (line 136) | pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
function back_mut (line 141) | pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> ...
function push_front (line 146) | pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) {
function pop_front (line 163) | pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
function push_back (line 186) | pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) {
function pop_back (line 203) | pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
function split_off (line 234) | pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -...
function remove (line 258) | pub fn remove(&mut self, at: usize, token: &mut GhostToken<'brand>) -> T {
function front_node (line 272) | fn front_node(&self) -> Option<&GhostNode<'brand, T>> { self.head_tail.a...
function back_node (line 275) | fn back_node(&self) -> Option<&GhostNode<'brand, T>> { self.head_tail.as...
function new_thirds (line 278) | fn new_thirds(value: T, token: &GhostToken<'brand>) -> (ThirdNodePtr<'br...
function into_inner (line 289) | fn into_inner(thirds: ThirdTuple<'brand, T>) -> T {
method default (line 305) | fn default() -> Self { Self { length: 0, head_tail: None, } }
type Node (line 312) | struct Node<'brand, T> {
function deploy (line 321) | fn deploy(&self) -> ThirdNodePtr<'brand, T> { self.tripod.take().expect(...
function retract (line 324) | fn retract(&self, tripod: ThirdNodePtr<'brand, T>) {
function retract (line 330) | fn retract<'brand, T>(tripod: ThirdNodePtr<'brand, T>, token: &mut Ghost...
type GhostNode (line 338) | type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>;
type ThirdNodePtr (line 339) | type ThirdNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 1, 3>;
type TwoThirdsNodePtr (line 340) | type TwoThirdsNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 2, 3>;
type FullNodePtr (line 341) | type FullNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 3, 3>;
type ThirdTuple (line 342) | type ThirdTuple<'brand, T> = (ThirdNodePtr<'brand, T>, ThirdNodePtr<'bra...
function assert_list_mut (line 355) | fn assert_list_mut<'brand>(expected: &[&str], token: &mut GhostToken<'br...
function assert_list (line 366) | pub(crate) fn assert_list<'brand>(expected: &[&str], token: &mut GhostTo...
function assert_list_append (line 371) | fn assert_list_append(list: Vec<String>, append: Vec<String>, expected: ...
function list_append (line 381) | fn list_append() {
function assert_list_split_off (line 399) | fn assert_list_split_off(list: Vec<String>, at: usize, expected_list: &[...
function list_split_off (line 409) | fn list_split_off() {
function list_split_off_out_of_bounds (line 418) | fn list_split_off_out_of_bounds() {
function assert_list_remove (line 425) | fn assert_list_remove(list: Vec<String>, at: usize, expected_list: &[&st...
function list_remove (line 435) | fn list_remove() {
function list_remove_out_of_bounds (line 444) | fn list_remove_out_of_bounds() {
function create (line 450) | pub(crate) fn create(range: Range<i32>) -> Vec<String> {
function collect (line 454) | pub(crate) fn collect<'a>(iter: Iter<'a, '_, String>) -> Vec<&'a str> {
function with_list (line 458) | pub(crate) fn with_list<T, R, F>(initial: Vec<T>, fun: F) -> R
function with_list_duo (line 477) | pub(crate) fn with_list_duo<T, R, F>(first: Vec<T>, second: Vec<T>, fun:...
FILE: src/tripod_list/cursor.rs
type Cursor (line 8) | pub struct Cursor<'a, 'brand, T> {
function new_front (line 17) | pub fn new_front(token: &'a GhostToken<'brand>, list: &'a TripodList<'br...
function new_back (line 24) | pub fn new_back(token: &'a GhostToken<'brand>, list: &'a TripodList<'bra...
function before_after (line 37) | pub fn before_after(&self) -> (Iter<'a, 'brand, T>, Iter<'a, 'brand, T>) {
function index (line 56) | pub fn index(&self) -> Option<usize> { self.node.map(|_| self.index) }
function move_next (line 62) | pub fn move_next(&mut self) {
function move_prev (line 76) | pub fn move_prev(&mut self) {
function current (line 87) | pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borr...
function peek_next (line 90) | pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().map(|no...
function peek_prev (line 93) | pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().map(|no...
function peek_next_node (line 96) | fn peek_next_node(&self) -> Option<&'a GhostNode<'brand, T>> {
function peek_prev_node (line 105) | fn peek_prev_node(&self) -> Option<&'a GhostNode<'brand, T>> {
method clone (line 115) | fn clone(&self) -> Self { *self }
type CursorMut (line 134) | pub struct CursorMut<'a, 'brand, T> {
function new_front (line 143) | pub fn new_front(token: &'a mut GhostToken<'brand>, list: &'a mut Tripod...
function new_back (line 150) | pub fn new_back(token: &'a mut GhostToken<'brand>, list: &'a mut TripodL...
function as_cursor (line 158) | pub fn as_cursor(&self) -> Cursor<'_, 'brand, T> {
function index (line 170) | pub fn index(&self) -> Option<usize> { self.node.as_ref().map(|_| self.i...
function move_next (line 176) | pub fn move_next(&mut self) {
function move_prev (line 191) | pub fn move_prev(&mut self) {
function current (line 203) | pub fn current(&mut self) -> Option<&mut T> {
function peek_next (line 213) | pub fn peek_next(&self) -> Option<&T> { self.peek_next_node().map(|node|...
function peek_prev (line 220) | pub fn peek_prev(&self) -> Option<&T> { self.peek_prev_node().map(|node|...
function peek_next_node (line 223) | fn peek_next_node(&self) -> Option<&GhostNode<'brand, T>> {
function peek_prev_node (line 232) | fn peek_prev_node(&self) -> Option<&GhostNode<'brand, T>> {
function insert_after (line 252) | pub fn insert_after(&mut self, item: T) {
function insert_before (line 271) | pub fn insert_before(&mut self, item: T) {
function remove_current (line 290) | pub fn remove_current(&mut self) -> Option<T> {
function remove_current_as_list (line 307) | pub fn remove_current_as_list(&mut self) -> Option<TripodList<'brand, T>> {
function splice_after (line 363) | pub fn splice_after(&mut self, other: &mut TripodList<'brand, T>) {
function splice_before (line 411) | pub fn splice_before(&mut self, other: &mut TripodList<'brand, T>) {
function split_after (line 459) | pub fn split_after(&mut self) -> TripodList<'brand, T> {
function split_before (line 493) | pub fn split_before(&mut self) -> TripodList<'brand, T> {
method drop (line 521) | fn drop(&mut self) {
function assert_none (line 537) | fn assert_none<'a, 'brand, T>(cursor: Cursor<'a, 'brand, T>)
function assert_cursor (line 548) | fn assert_cursor(before: &[&str], current: &str, after: &[&str], cursor:...
function assert_twilight (line 561) | fn assert_twilight(before: &[&str], cursor: Cursor<'_, '_, String>) {
function place_cursor (line 575) | fn place_cursor<'a, 'brand>(token: &'a mut GhostToken<'brand>, list: &'a...
function cursor_front_empty (line 590) | fn cursor_front_empty() {
function cursor_back_empty (line 605) | fn cursor_back_empty() {
function cursor_move_next (line 620) | fn cursor_move_next() {
function cursor_move_prev (line 649) | fn cursor_move_prev() {
function cursor_mut_front_empty (line 678) | fn cursor_mut_front_empty() {
function cursor_mut_back_empty (line 693) | fn cursor_mut_back_empty() {
function cursor_mut_move_next (line 708) | fn cursor_mut_move_next() {
function cursor_mut_move_prev (line 737) | fn cursor_mut_move_prev() {
function assert_insert_after (line 766) | fn assert_insert_after(list: Vec<String>, element: String, at: usize, be...
function cursor_mut_insert_after (line 777) | fn cursor_mut_insert_after() {
function assert_insert_before (line 806) | fn assert_insert_before(list: Vec<String>, element: String, at: usize, b...
function cursor_mut_insert_before (line 817) | fn cursor_mut_insert_before() {
function assert_splice_after (line 846) | fn assert_splice_after(list: Vec<String>, other: Vec<String>, at: usize,...
function assert_splice_after_twilight (line 858) | fn assert_splice_after_twilight(list: Vec<String>, other: Vec<String>, b...
function cursor_mut_splice_after (line 870) | fn cursor_mut_splice_after() {
function assert_splice_before (line 904) | fn assert_splice_before(list: Vec<String>, other: Vec<String>, at: usize...
function assert_splice_before_twilight (line 916) | fn assert_splice_before_twilight(list: Vec<String>, other: Vec<String>, ...
function cursor_mut_splice_before (line 928) | fn cursor_mut_splice_before() {
function assert_remove_current (line 962) | fn assert_remove_current(list: Vec<String>, at: usize, result: Option<&s...
function cursor_mut_remove_current (line 974) | fn cursor_mut_remove_current() {
function assert_remove_current_as_list (line 1011) | fn assert_remove_current_as_list(list: Vec<String>, at: usize, result: O...
function cursor_mut_remove_current_as_list (line 1028) | fn cursor_mut_remove_current_as_list() {
function assert_split_after (line 1068) | fn assert_split_after(list: Vec<String>, at: usize, before: &[&str], cur...
function cursor_mut_split_after (line 1083) | fn cursor_mut_split_after() {
function assert_split_before (line 1117) | fn assert_split_before(list: Vec<String>, at: usize, before: &[&str], cu...
function cursor_mut_split_before (line 1132) | fn cursor_mut_split_before() {
FILE: src/tripod_list/iter.rs
type Iter (line 6) | pub struct Iter<'a, 'brand, T> {
function new (line 13) | pub fn new(token: &'a GhostToken<'brand>, list: &'a TripodList<'brand, T...
function empty (line 22) | pub(super) fn empty(token: &'a GhostToken<'brand>) -> Self {
function slice (line 27) | pub(super) fn slice(
type Item (line 38) | type Item = &'a T;
method next (line 40) | fn next(&mut self) -> Option<Self::Item> {
method next_back (line 59) | fn next_back(&mut self) -> Option<Self::Item> {
function empty (line 84) | fn empty() {
function forward (line 94) | fn forward() {
function backward (line 109) | fn backward() {
function alternate (line 124) | fn alternate() {
function alternate_other (line 140) | fn alternate_other() {
FILE: src/tripod_tree.rs
type TripodTree (line 35) | pub struct TripodTree<'brand, T> {
function new (line 41) | pub const fn new() -> Self { Self { root: None, } }
function singleton (line 44) | pub fn singleton(value: T, token: &mut GhostToken<'brand>) -> Self {
function iter (line 55) | pub fn iter<'a>(&'a self, token: &'a GhostToken<'brand>) -> Iter<'a, 'br...
function iter_range (line 68) | pub fn iter_range<'a, R>(&'a self, range: R, token: &'a GhostToken<'bran...
function cursor (line 78) | pub fn cursor<'a>(&'a self, token: &'a GhostToken<'brand>) -> Cursor<'a,...
function cursor_mut (line 83) | pub fn cursor_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -...
function cursor_front (line 88) | pub fn cursor_front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Curs...
function cursor_front_mut (line 93) | pub fn cursor_front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'bra...
function cursor_back (line 98) | pub fn cursor_back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Curso...
function cursor_back_mut (line 103) | pub fn cursor_back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'bran...
function is_empty (line 108) | pub fn is_empty(&self) -> bool { self.root.is_none() }
function len (line 111) | pub fn len(&self, token: &GhostToken<'brand>) -> usize {
function clear (line 123) | pub fn clear(&mut self, token: &mut GhostToken<'brand>) {
function front (line 171) | pub fn front<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a ...
function back (line 183) | pub fn back<'a>(&'a self, token: &'a GhostToken<'brand>) -> Option<&'a T> {
function at (line 195) | pub fn at<'a>(&'a self, at: usize, token: &'a GhostToken<'brand>) -> Opt...
function push_front (line 211) | pub fn push_front(&mut self, value: T, token: &mut GhostToken<'brand>) {
function pop_front (line 223) | pub fn pop_front(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
function push_back (line 235) | pub fn push_back(&mut self, value: T, token: &mut GhostToken<'brand>) {
function pop_back (line 247) | pub fn pop_back(&mut self, token: &mut GhostToken<'brand>) -> Option<T> {
function append (line 261) | pub fn append(&mut self, other: &mut TripodTree<'brand, T>, token: &mut ...
function prepend (line 275) | pub fn prepend(&mut self, other: &mut TripodTree<'brand, T>, token: &mut...
function split_off (line 293) | pub fn split_off(&mut self, at: usize, token: &mut GhostToken<'brand>) -...
function split (line 316) | pub fn split<R>(&mut self, range: R, token: &mut GhostToken<'brand>) -> ...
function into_range (line 353) | fn into_range<R>(&self, range: R, token: &GhostToken<'brand>) -> Range<u...
function from_value (line 375) | fn from_value(value: T, token: &mut GhostToken<'brand>) -> QuarterNodePt...
function from_quarter (line 391) | fn from_quarter(node: QuarterNodePtr<'brand, T>, token: &GhostToken<'bra...
function node_into_inner (line 401) | fn node_into_inner(node: QuarterNodePtr<'brand, T>, token: &mut GhostTok...
function node_into_full (line 408) | fn node_into_full(node: QuarterNodePtr<'brand, T>, token: &mut GhostToke...
function full_into_inner (line 420) | fn full_into_inner(full: FullNodePtr<'brand, T>) -> T {
function front_mut (line 442) | pub fn front_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) ->...
function back_mut (line 457) | pub fn back_mut<'a>(&'a mut self, token: &'a mut GhostToken<'brand>) -> ...
function at_mut (line 472) | pub fn at_mut<'a>(&'a mut self, mut at: usize, token: &'a mut GhostToken...
method default (line 502) | fn default() -> Self { Self::new() }
type Side (line 507) | pub enum Side {
method opposite (line 516) | pub fn opposite(self) -> Side {
type Node (line 528) | struct Node<'brand, T> {
function index (line 542) | fn index(&self, token: &GhostToken<'brand>) -> usize {
function left_size (line 547) | fn left_size(&self, token: &GhostToken<'brand>) -> usize {
function right_size (line 552) | fn right_size(&self, token: &GhostToken<'brand>) -> usize {
function child_size (line 557) | fn child_size(&self, side: Side, token: &GhostToken<'brand>) -> usize {
function is_aliased (line 563) | fn is_aliased(&self, node: Option<&GhostNode<'brand, T>>) -> bool {
function is_child (line 568) | fn is_child(&self, token: &GhostToken<'brand>) -> Option<Side> {
function is_child_of (line 573) | fn is_child_of(&self, candidate: &Self) -> Option<Side> {
function up (line 584) | fn up(&self) -> Option<&GhostNode<'brand, T>> {
function left (line 591) | fn left(&self) -> Option<&GhostNode<'brand, T>> {
function right (line 598) | fn right(&self) -> Option<&GhostNode<'brand, T>> {
function child (line 605) | fn child(&self, side: Side) -> Option<&GhostNode<'brand, T>> {
function replace_child (line 612) | fn replace_child(&mut self, side: Side, new: QuarterNodePtr<'brand, T>) ...
function set_child (line 617) | fn set_child(&mut self, side: Side, new: QuarterNodePtr<'brand, T>) {
function take_child (line 623) | fn take_child(&mut self, side: Side) -> Option<QuarterNodePtr<'brand, T>> {
function child_ref (line 632) | fn child_ref(&self, side: Side) -> &Option<QuarterNodePtr<'brand, T>> {
function child_mut (line 640) | fn child_mut(&mut self, side: Side) -> &mut Option<QuarterNodePtr<'brand...
function deploy (line 648) | fn deploy(&self) -> QuarterNodePtr<'brand, T> { self.tripod.take().expec...
function retract (line 651) | fn retract(&self, tripod: QuarterNodePtr<'brand, T>) {
function retract (line 657) | fn retract<'brand, T>(tripod: QuarterNodePtr<'brand, T>, token: &mut Gho...
type GhostNode (line 664) | type GhostNode<'brand, T> = GhostCell<'brand, Node<'brand, T>>;
type QuarterNodePtr (line 666) | type QuarterNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 1, 4>;
type HalfNodePtr (line 667) | type HalfNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 2, 4>;
type FullNodePtr (line 668) | type FullNodePtr<'brand, T> = StaticRc<GhostNode<'brand, T>, 4, 4>;
function assert_tree (line 678) | pub(super) fn assert_tree(expected: &[&str], cursor: Cursor<'_, '_, Stri...
function assert_element (line 685) | fn assert_element(expected: Option<&str>, actual: Option<&String>) {
function assert_element_mut (line 691) | fn assert_element_mut(expected: Option<&str>, actual: Option<&mut String...
function tree_new (line 696) | fn tree_new() {
function tree_test (line 703) | fn tree_test() {
function tree_access (line 718) | fn tree_access() {
function tree_access_mut (line 738) | fn tree_access_mut() {
function tree_pop_push (line 757) | fn tree_pop_push() {
function tree_append (line 778) | fn tree_append() {
function tree_prepend (line 795) | fn tree_prepend() {
function tree_split_off (line 812) | fn tree_split_off() {
function tree_split (line 828) | fn tree_split() {
function with_tree (line 891) | pub(super) fn with_tree<R, F>(flat: &[&str], fun: F) -> R
function with_tree_duo (line 906) | pub(super) fn with_tree_duo<R, F>(first: &[&str], second: &[&str], fun: ...
function inflate (line 923) | pub(super) fn inflate<'brand>(flat: &[&str], token: &mut GhostToken<'bra...
function flatten (line 965) | pub(super) fn flatten(mut cursor: Cursor<'_, '_, String>) -> Vec<String> {
function left_child_index (line 1013) | fn left_child_index(index: usize) -> usize { 2 * index + 1 }
function right_child_index (line 1015) | fn right_child_index(index: usize) -> usize { 2 * index + 2 }
FILE: src/tripod_tree/cursor.rs
type Cursor (line 21) | pub struct Cursor<'a, 'brand, T> {
function new (line 31) | pub fn new(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T...
function index (line 40) | pub fn index(&self) -> Option<usize> { self.node.map(|_| self.index) }
function range (line 45) | pub fn range(&self) -> Range<usize> {
function move_to_root (line 55) | pub fn move_to_root(&mut self) { *self = Self::new(self.token, self.tree) }
function move_up (line 60) | pub fn move_up(&mut self) {
function move_left (line 72) | pub fn move_left(&mut self) {
function move_right (line 84) | pub fn move_right(&mut self) {
function move_down (line 96) | pub fn move_down(&mut self, side: Side) {
function try_move_up (line 108) | pub fn try_move_up(&mut self) -> Option<&'a T> {
function try_move_left (line 125) | pub fn try_move_left(&mut self) -> Option<&'a T> {
function try_move_right (line 142) | pub fn try_move_right(&mut self) -> Option<&'a T> {
function try_move_down (line 160) | pub fn try_move_down(&mut self, side: Side) -> Option<&'a T> {
function current (line 173) | pub fn current(&self) -> Option<&'a T> { self.node.map(|node| &node.borr...
function peek_up (line 176) | pub fn peek_up(&self) -> Option<&'a T> { self.peek_up_node().0.map(|node...
function peek_left (line 179) | pub fn peek_left(&self) -> Option<&'a T> { self.peek_left_node().0.map(|...
function peek_right (line 182) | pub fn peek_right(&self) -> Option<&'a T> { self.peek_right_node().0.map...
function peek_down (line 185) | pub fn peek_down(&self, side: Side) -> Option<&'a T> { self.peek_down_no...
function root_of (line 188) | fn root_of(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T...
function peek_up_node (line 196) | fn peek_up_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
function peek_left_node (line 221) | fn peek_left_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
function peek_right_node (line 239) | fn peek_right_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
function peek_down_node (line 257) | fn peek_down_node(&self, side: Side) -> (Option<&'a GhostNode<'brand, T>...
function new_front (line 288) | pub fn new_front(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'br...
function new_back (line 304) | pub fn new_back(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'bra...
function move_to_front (line 320) | pub fn move_to_front(&mut self) { *self = Self::new_front(self.token, se...
function move_to_back (line 328) | pub fn move_to_back(&mut self) { *self = Self::new_back(self.token, self...
function move_next (line 339) | pub fn move_next(&mut self) {
function move_prev (line 355) | pub fn move_prev(&mut self) {
function move_to (line 375) | pub fn move_to(&mut self, at: usize) {
function try_move_next (line 391) | pub fn try_move_next(&mut self) -> Option<&'a T> {
function try_move_prev (line 413) | pub fn try_move_prev(&mut self) -> Option<&'a T> {
function try_move_to (line 439) | pub fn try_move_to(&mut self, at: usize) -> Option<&'a T> {
function peek_next (line 459) | pub fn peek_next(&self) -> Option<&'a T> { self.peek_next_node().0.map(|...
function peek_prev (line 467) | pub fn peek_prev(&self) -> Option<&'a T> { self.peek_prev_node().0.map(|...
function peek_at (line 475) | pub fn peek_at(&self, at: usize) -> Option<&'a T> { self.peek_at_node(at...
function len (line 478) | fn len(&self) -> usize { self.tree.len(self.token) }
function peek_next_node (line 481) | fn peek_next_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
function peek_prev_node (line 492) | fn peek_prev_node(&self) -> (Option<&'a GhostNode<'brand, T>>, usize) {
function peek_at_node (line 505) | fn peek_at_node(&self, at: usize) -> Option<&'a GhostNode<'brand, T>> {
method clone (line 573) | fn clone(&self) -> Self { *self }
type CursorMut (line 592) | pub struct CursorMut<'a, 'brand, T> {
function new (line 602) | pub fn new(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodTree<'...
function as_cursor (line 610) | pub fn as_cursor(&self) -> Cursor<'_, 'brand, T> {
function index (line 622) | pub fn index(&self) -> Option<usize> { self.node.as_ref().map(|_| self.i...
function range (line 627) | pub fn range(&self) -> Range<usize> { self.as_cursor().range() }
function move_up (line 632) | pub fn move_up(&mut self) {
function move_left (line 644) | pub fn move_left(&mut self) {
function move_right (line 656) | pub fn move_right(&mut self) {
function move_down (line 668) | pub fn move_down(&mut self, side: Side) {
function move_to_root (line 678) | pub fn move_to_root(&mut self) {
function try_move_up (line 701) | pub fn try_move_up(&mut self) -> Option<&mut T> {
function try_move_left (line 719) | pub fn try_move_left(&mut self) -> Option<&mut T> {
function try_move_right (line 737) | pub fn try_move_right(&mut self) -> Option<&mut T> {
function try_move_down (line 755) | pub fn try_move_down(&mut self, side: Side) -> Option<&mut T> {
function current (line 768) | pub fn current(&mut self) -> Option<&mut T> {
function peek_up (line 774) | pub fn peek_up(&self) -> Option<&T> { self.peek_up_node().0.map(|node| &...
function peek_left (line 777) | pub fn peek_left(&self) -> Option<&T> { self.peek_left_node().0.map(|nod...
function peek_right (line 780) | pub fn peek_right(&self) -> Option<&T> { self.peek_right_node().0.map(|n...
function peek_down (line 783) | pub fn peek_down(&self, side: Side) -> Option<&T> { self.peek_down_node(...
function root_of (line 786) | fn root_of<'b>(token: &'b GhostToken<'brand>, tree: &'b TripodTree<'bran...
function deploy_tripod (line 794) | fn deploy_tripod(&self, node: &GhostNode<'brand, T>) -> QuarterNodePtr<'...
function retract_tripod (line 797) | fn retract_tripod(&mut self, node: QuarterNodePtr<'brand, T>) {
function switch_tripod (line 802) | fn switch_tripod(&mut self, new_tripod: Option<QuarterNodePtr<'brand, T>...
function peek_up_node (line 811) | fn peek_up_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
function peek_left_node (line 816) | fn peek_left_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
function peek_right_node (line 821) | fn peek_right_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
function peek_down_node (line 826) | fn peek_down_node(&self, side: Side) -> (Option<&GhostNode<'brand, T>>, ...
function new_front (line 839) | pub fn new_front(token: &'a mut GhostToken<'brand>, tree: &'a mut Tripod...
function new_back (line 855) | pub fn new_back(token: &'a mut GhostToken<'brand>, tree: &'a mut TripodT...
function move_next (line 874) | pub fn move_next(&mut self) {
function move_prev (line 890) | pub fn move_prev(&mut self) {
function move_to (line 910) | pub fn move_to(&mut self, at: usize) {
function move_to_front (line 929) | pub fn move_to_front(&mut self) {
function move_to_back (line 943) | pub fn move_to_back(&mut self) {
function try_move_next (line 959) | pub fn try_move_next(&mut self) -> Option<&mut T> {
function try_move_prev (line 981) | pub fn try_move_prev(&mut self) -> Option<&mut T> {
function try_move_to (line 1007) | pub fn try_move_to(&mut self, at: usize) -> Option<&mut T> {
function peek_next (line 1032) | pub fn peek_next(&self) -> Option<&T> { self.peek_next_node().0.map(|nod...
function peek_prev (line 1040) | pub fn peek_prev(&self) -> Option<&T> { self.peek_prev_node().0.map(|nod...
function peek_at (line 1048) | pub fn peek_at(&self, at: usize) -> Option<&T> { self.peek_at_node(at).m...
function len (line 1051) | fn len(&self) -> usize { self.tree.len(self.token) }
function peek_next_node (line 1054) | fn peek_next_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
function peek_prev_node (line 1059) | fn peek_prev_node(&self) -> (Option<&GhostNode<'brand, T>>, usize) {
function peek_at_node (line 1066) | fn peek_at_node(&self, at: usize) -> Option<&GhostNode<'brand, T>> {
function insert_after (line 1078) | pub fn insert_after(&mut self, value: T) {
function insert_before (line 1088) | pub fn insert_before(&mut self, value: T) {
function remove_current (line 1098) | pub fn remove_current(&mut self) -> Option<T> {
function remove_current_as_tree (line 1117) | pub fn remove_current_as_tree(&mut self) -> TripodTree<'brand, T> {
function splice_after (line 1182) | pub fn splice_after(&mut self, other: &mut TripodTree<'brand, T>) {
function splice_before (line 1206) | pub fn splice_before(&mut self, other: &mut TripodTree<'brand, T>) {
function split_after (line 1230) | pub fn split_after(&mut self) -> TripodTree<'brand, T> {
function split_before (line 1250) | pub fn split_before(&mut self) -> TripodTree<'brand, T> {
function sift_down (line 1261) | fn sift_down(&mut self) {
function splice_impl (line 1288) | fn splice_impl(&mut self, side: Side, other: &mut TripodTree<'brand, T>) {
function split_impl (line 1337) | fn split_impl(&mut self, side: Side) -> TripodTree<'brand, T> {
function set_subtree (line 1431) | fn set_subtree(&mut self, side: Side, other_root: QuarterNodePtr<'brand,...
function rebalance_tree_complete (line 1463) | fn rebalance_tree_complete(&mut self, root_tripod: QuarterNodePtr<'brand...
function rebalance_tree_single (line 1486) | fn rebalance_tree_single(&mut self, root_tripod: QuarterNodePtr<'brand, ...
function rebalance_subtree_complete (line 1509) | fn rebalance_subtree_complete(&mut self, mut root_tripod: QuarterNodePtr...
function rebalance_subtree_single (line 1540) | fn rebalance_subtree_single(&mut self, root_tripod: QuarterNodePtr<'bran...
function rebalance_child (line 1560) | fn rebalance_child(&mut self, side: Side, parent: &GhostNode<'brand, T>) {
function swap_child_from (line 1615) | fn swap_child_from(&mut self, side: Side, root_tripod: QuarterNodePtr<'b...
function rotate_child_from (line 1750) | fn rotate_child_from(&mut self, side: Side, root_tripod: QuarterNodePtr<...
function prepare_rotation (line 1846) | fn prepare_rotation(&mut self, side: Side, root_tripod: QuarterNodePtr<'...
function adjust_size (line 1894) | fn adjust_size(&mut self, node: &GhostNode<'brand, T>) {
function take_child (line 1906) | fn take_child(side: Side, node: &GhostNode<'brand, T>, token: &mut Ghost...
function describe_node (line 1924) | fn describe_node(&self, caller: &str, node: &GhostNode<'brand, T>) {
function describe_node (line 1943) | fn describe_node(&self, _: &str, _: &GhostNode<'brand, T>) {}
function describe_self (line 1947) | fn describe_self(&self, caller: &str) {
function describe_self (line 1961) | fn describe_self(&self, _: &str) {}
method drop (line 1965) | fn drop(&mut self) {
type Position (line 1981) | struct Position<'a> {
function new (line 1994) | const fn new(
function range (line 2011) | const fn range(&self) -> Range<usize> { self.start..self.end }
function assert_twilight (line 2015) | fn assert_twilight(cursor: Cursor<'_, '_, String>) {
function assert_neighbours (line 2022) | fn assert_neighbours(parent: Option<&str>, left: Option<&str>, right: Op...
function assert_log_neighbours (line 2029) | fn assert_log_neighbours(prev: Option<&str>, next: Option<&str>, cursor:...
function assert_empty (line 2035) | fn assert_empty(cursor: Cursor<'_, '_, String>) {
function assert_current (line 2042) | fn assert_current(at: usize, range: Range<usize>, element: &str, cursor:...
function assert_position (line 2049) | fn assert_position(pos: Position<'_>, cursor: Cursor<'_, '_, String>) {
function assert_twilight_mut (line 2056) | fn assert_twilight_mut(cursor: &mut CursorMut<'_, '_, String>) {
function assert_neighbours_mut (line 2063) | fn assert_neighbours_mut(parent: Option<&str>, left: Option<&str>, right...
function assert_log_neighbours_mut (line 2070) | fn assert_log_neighbours_mut(prev: Option<&str>, next: Option<&str>, cur...
function assert_empty_mut (line 2076) | fn assert_empty_mut(cursor: &mut CursorMut<'_, '_, String>) {
function assert_current_mut (line 2083) | fn assert_current_mut(at: usize, range: Range<usize>, element: &str, cur...
function assert_position_mut (line 2090) | fn assert_position_mut(pos: Position<'_>, cursor: &mut CursorMut<'_, '_,...
function cursor_empty (line 2101) | fn cursor_empty() {
function cursor_mut_empty (line 2145) | fn cursor_mut_empty() {
function cursor_brush_move_up_left_right (line 2189) | fn cursor_brush_move_up_left_right() {
function cursor_mut_brush_move_up_left_right (line 2235) | fn cursor_mut_brush_move_up_left_right() {
function cursor_brush_move_prev_next (line 2281) | fn cursor_brush_move_prev_next() {
function cursor_mut_brush_move_prev_next (line 2317) | fn cursor_mut_brush_move_prev_next() {
function cursor_brush_move_to (line 2355) | fn cursor_brush_move_to() {
function cursor_mut_brush_move_to (line 2384) | fn cursor_mut_brush_move_to() {
function cursor_mut_move_to_self (line 2413) | fn cursor_mut_move_to_self() {
function cursor_mut_remove_current_twilight (line 2447) | fn cursor_mut_remove_current_twilight() {
function cursor_mut_remove_current_root (line 2473) | fn cursor_mut_remove_current_root() {
function cursor_mut_remove_current_front_to_back (line 2540) | fn cursor_mut_remove_current_front_to_back() {
function cursor_mut_remove_current_back_to_front (line 2605) | fn cursor_mut_remove_current_back_to_front() {
function cursor_mut_insert_after_from_twilight (line 2674) | fn cursor_mut_insert_after_from_twilight() {
function cursor_mut_insert_before_from_twilight (line 2704) | fn cursor_mut_insert_before_from_twilight() {
function cursor_mut_insert_as_leaf (line 2732) | fn cursor_mut_insert_as_leaf() {
function cursor_mut_splice_empty (line 2816) | fn cursor_mut_splice_empty() {
function cursor_mut_splice_twilight (line 2881) | fn cursor_mut_splice_twilight() {
function cursor_mut_splice_after (line 2966) | fn cursor_mut_splice_after() {
function cursor_mut_splice_before (line 3032) | fn cursor_mut_splice_before() {
function cursor_mut_split_twilight (line 3098) | fn cursor_mut_split_twilight() {
function cursor_mut_split_after (line 3135) | fn cursor_mut_split_after() {
function cursor_mut_split_before (line 3176) | fn cursor_mut_split_before() {
FILE: src/tripod_tree/iter.rs
type Iter (line 11) | pub struct Iter<'a, 'brand, T> {
function new (line 18) | pub fn new(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand, T...
function range (line 26) | pub fn range(token: &'a GhostToken<'brand>, tree: &'a TripodTree<'brand,...
function at (line 33) | fn at(&self, index: usize) -> Option<&'a T> {
type Item (line 41) | type Item = &'a T;
method next (line 43) | fn next(&mut self) -> Option<Self::Item> {
method size_hint (line 48) | fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
method count (line 50) | fn count(self) -> usize { self.range.count() }
method last (line 52) | fn last(mut self) -> Option<Self::Item> {
method nth (line 58) | fn nth(&mut self, n: usize) -> Option<Self::Item> {
method next_back (line 65) | fn next_back(&mut self) -> Option<Self::Item> {
method nth_back (line 70) | fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
method clone (line 77) | fn clone(&self) -> Self { Self { range: self.range.clone(), cursor: self...
constant TREE (line 85) | const TREE: &[&str] = &["8", "4", "C", "2", "6", "A", "E", "1", "3", "5"...
function iter_range (line 88) | fn iter_range() {
function iter_next (line 131) | fn iter_next() {
function iter_size_hint (line 142) | fn iter_size_hint() {
function iter_count (line 151) | fn iter_count() {
function iter_last (line 160) | fn iter_last() {
function iter_nth (line 169) | fn iter_nth() {
function iter_next_back (line 180) | fn iter_next_back() {
function iter_nth_back (line 191) | fn iter_nth_back() {
Condensed preview — 15 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (280K chars).
[
{
"path": ".gitignore",
"chars": 25,
"preview": ".cargo\ntarget\nCargo.lock\n"
},
{
"path": "Cargo.toml",
"chars": 776,
"preview": "[package]\nname = \"ghost-collections\"\nversion = \"0.1.0\"\nauthors = [\"Matthieu M. <matthieum.147192@gmail.com>\"]\nedition = "
},
{
"path": "LICENSE-APACHE",
"chars": 10833,
"preview": " Apache License\n Version 2.0, January 2004\n http"
},
{
"path": "LICENSE-MIT",
"chars": 1050,
"preview": "Copyright 2021 matthieu-m\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software"
},
{
"path": "README.md",
"chars": 7572,
"preview": "A proof of concept implementation of cyclic data structures in stable, safe, Rust.\n\nThis demonstrates the combined power"
},
{
"path": "src/lib.rs",
"chars": 724,
"preview": "//! A repository of collections written entirely in safe, zero-cost, stable, Rust.\n//!\n//! # Safety\n//!\n//! This repos"
},
{
"path": "src/linked_list/cursor.rs",
"chars": 15405,
"preview": "use ghost_cell::GhostToken;\n\nuse super::{GhostNode, LinkedList};\n\n#[cfg(feature = \"experimental-ghost-cursor\")]\nuse ghos"
},
{
"path": "src/linked_list/iter.rs",
"chars": 4157,
"preview": "use ghost_cell::GhostToken;\n\nuse super::{GhostNode, LinkedList};\n\n/// An iterator over a LinkedList, self-sufficient onc"
},
{
"path": "src/linked_list.rs",
"chars": 11893,
"preview": "//! A LinkedList, with externally supplied token.\n//!\n//! A number of operations normally implemented by traits cannot b"
},
{
"path": "src/tripod_list/cursor.rs",
"chars": 39431,
"preview": "use core::mem;\n\nuse ghost_cell::GhostToken;\n\nuse super::{GhostNode, Iter, ThirdNodePtr, TripodList};\n\n/// A Cursor over "
},
{
"path": "src/tripod_list/iter.rs",
"chars": 4591,
"preview": "use ghost_cell::GhostToken;\n\nuse super::{GhostNode, TripodList};\n\n/// An iterator over a TripodList, self-sufficient onc"
},
{
"path": "src/tripod_list.rs",
"chars": 17002,
"preview": "//! A LinkedList, with externally supplied token.\n//!\n//! Unlike LinkedList, a TripodList has one additional pointer per"
},
{
"path": "src/tripod_tree/cursor.rs",
"chars": 113757,
"preview": "use core::{\n cmp,\n mem,\n ops::Range,\n};\n\nuse ghost_cell::GhostToken;\n\nuse super::{GhostNode, QuarterNodePtr, Si"
},
{
"path": "src/tripod_tree/iter.rs",
"chars": 5259,
"preview": "use core::{\n mem,\n ops::Range,\n};\n\nuse ghost_cell::GhostToken;\n\nuse super::{Cursor, TripodTree};\n\n/// An iterator "
},
{
"path": "src/tripod_tree.rs",
"chars": 34182,
"preview": "//! An Indexed Balanced Binary Tree, with externally supplied token.\n//!\n//! The `TripodTree` is building block for Bina"
}
]
About this extraction
This page contains the full source code of the matthieu-m/ghost-collections GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 15 files (260.4 KB), approximately 69.0k tokens, and a symbol index with 448 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.