mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-22 21:07:43 +00:00
feat: init content map
This commit is contained in:
parent
3b271b5ede
commit
bd1b0a2215
13 changed files with 303 additions and 62 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
@ -1,7 +1,5 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"smstring"
|
||||
],
|
||||
"cSpell.words": ["smstring", "yspan"],
|
||||
"rust-analyzer.runnableEnv": {
|
||||
"RUST_BACKTRACE": "full"
|
||||
}
|
||||
|
|
|
@ -2,21 +2,13 @@
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
use fxhash::FxHashMap;
|
||||
use proptest::prelude::*;
|
||||
use proptest::proptest;
|
||||
|
||||
use crate::value::proptest::gen_insert_value;
|
||||
|
||||
use crate::{
|
||||
container::{Container},
|
||||
fx_map,
|
||||
value::InsertValue,
|
||||
LoroCore, LoroValue,
|
||||
};
|
||||
|
||||
|
||||
use crate::{container::Container, fx_map, value::InsertValue, LoroCore, LoroValue};
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
|
|
|
@ -4,11 +4,13 @@ use enum_as_inner::EnumAsInner;
|
|||
|
||||
use crate::id::ID;
|
||||
|
||||
pub(super) type TextPointer = Range<usize>;
|
||||
|
||||
#[derive(Debug, EnumAsInner)]
|
||||
pub(super) enum TextOpContent {
|
||||
Insert {
|
||||
id: ID,
|
||||
text: Range<usize>,
|
||||
text: TextPointer,
|
||||
pos: usize,
|
||||
},
|
||||
Delete {
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
use crate::{op::Op, span::IdSpan, VersionVector};
|
||||
use crate::{
|
||||
op::{utils::downcast_ref, Op},
|
||||
span::IdSpan,
|
||||
VersionVector,
|
||||
};
|
||||
|
||||
use self::cursor_map::CursorMap;
|
||||
use self::{content_map::ContentMap, cursor_map::CursorMap};
|
||||
|
||||
use super::text_content::TextOpContent;
|
||||
|
||||
mod content_map;
|
||||
mod cursor_map;
|
||||
mod y_span;
|
||||
|
||||
struct Tracker {
|
||||
content: ContentMap,
|
||||
index: CursorMap,
|
||||
}
|
||||
|
||||
|
@ -14,7 +21,23 @@ impl Tracker {
|
|||
fn turn_on(&mut self, _id: IdSpan) {}
|
||||
fn turn_off(&mut self, _id: IdSpan) {}
|
||||
fn checkout(&mut self, _vv: VersionVector) {}
|
||||
fn apply(&mut self, _content: &Op) {}
|
||||
|
||||
fn apply(&mut self, op: &Op) {
|
||||
match &op.content {
|
||||
crate::op::OpContent::Normal { content } => {
|
||||
if let Some(textContent) = downcast_ref::<TextOpContent>(&**content) {
|
||||
match textContent {
|
||||
TextOpContent::Insert { id, text, pos } => {
|
||||
let yspan = self.content.new_yspan_at_pos(*id, *pos, text.clone());
|
||||
}
|
||||
TextOpContent::Delete { id, pos, len } => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::op::OpContent::Undo { .. } => todo!(),
|
||||
crate::op::OpContent::Redo { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -23,6 +46,7 @@ mod test {
|
|||
|
||||
fn create_tracker() -> Tracker {
|
||||
Tracker {
|
||||
content: Default::default(),
|
||||
index: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,141 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use rle::{rle_tree::SafeCursorMut, RleTree};
|
||||
use moveit::new::of;
|
||||
use rle::{
|
||||
rle_tree::{Position, SafeCursor, SafeCursorMut, UnsafeCursor},
|
||||
HasLength, RleTree,
|
||||
};
|
||||
|
||||
use crate::{container::text::text_content::TextPointer, id::ID};
|
||||
|
||||
use super::y_span::{StatusChange, YSpan, YSpanTreeTrait};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct ContentMap(RleTree<YSpan, YSpanTreeTrait>);
|
||||
|
||||
struct CursorWithId<'tree> {
|
||||
id: ID,
|
||||
cursor: UnsafeCursor<'tree, 'static, YSpan, YSpanTreeTrait>,
|
||||
}
|
||||
|
||||
impl ContentMap {
|
||||
#[inline]
|
||||
pub fn new_yspan_at_pos(&mut self, id: ID, pos: usize, text: TextPointer) -> YSpan {
|
||||
let (left, right) = self.get_sibling_at(pos);
|
||||
YSpan {
|
||||
origin_left: left.map(|x| x.id).unwrap_or_else(ID::null),
|
||||
origin_right: right.map(|x| x.id).unwrap_or_else(ID::null),
|
||||
id,
|
||||
text,
|
||||
status: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sibling_at(&self, pos: usize) -> (Option<CursorWithId<'_>>, Option<CursorWithId<'_>>) {
|
||||
self.with_tree(|tree| {
|
||||
if let Some(cursor) = tree.get(pos) {
|
||||
let cursor: SafeCursor<'_, 'static, YSpan, YSpanTreeTrait> =
|
||||
unsafe { std::mem::transmute(cursor) };
|
||||
let (mut prev, mut next) = match cursor.pos() {
|
||||
Position::Start => {
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
let id = cursor.as_ref().id;
|
||||
(
|
||||
None,
|
||||
Some(CursorWithId {
|
||||
id,
|
||||
cursor: cursor.unwrap(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
Position::Middle => {
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
let id = cursor.as_ref().id;
|
||||
let offset = cursor.offset();
|
||||
let mut prev_offset_cursor = cursor.unwrap();
|
||||
prev_offset_cursor.offset -= 1;
|
||||
(
|
||||
Some(CursorWithId {
|
||||
id: id.inc(offset as i32 - 1),
|
||||
cursor: prev_offset_cursor,
|
||||
}),
|
||||
Some(CursorWithId {
|
||||
id: id.inc(offset as i32),
|
||||
cursor: cursor.unwrap(),
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
Position::End => {
|
||||
if cursor.as_ref().can_be_origin() {
|
||||
let mut prev_offset_cursor = cursor.unwrap();
|
||||
prev_offset_cursor.offset -= 1;
|
||||
(
|
||||
Some(CursorWithId {
|
||||
id: cursor.as_ref().last_id(),
|
||||
cursor: prev_offset_cursor,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if prev.is_none() {
|
||||
let mut prev_cursor = cursor.prev();
|
||||
while let Some(prev_inner) = prev_cursor {
|
||||
if prev_inner.as_ref().status.is_activated() {
|
||||
let cursor = prev_inner;
|
||||
let offset = cursor.as_ref().len() - 1;
|
||||
let mut cursor = cursor.unwrap();
|
||||
cursor.offset = offset;
|
||||
cursor.pos = Position::Middle;
|
||||
prev = Some(CursorWithId {
|
||||
id: prev_inner.as_ref().last_id(),
|
||||
cursor,
|
||||
});
|
||||
break;
|
||||
}
|
||||
prev_cursor = prev_inner.prev();
|
||||
}
|
||||
}
|
||||
|
||||
if next.is_none() {
|
||||
let mut next_cursor = cursor.next();
|
||||
while let Some(next_inner) = next_cursor {
|
||||
if next_inner.as_ref().status.is_activated() {
|
||||
let mut cursor = next_inner.unwrap();
|
||||
cursor.offset = 0;
|
||||
cursor.pos = Position::Start;
|
||||
next = Some(CursorWithId {
|
||||
id: next_inner.as_ref().id,
|
||||
cursor,
|
||||
});
|
||||
break;
|
||||
}
|
||||
next_cursor = next_inner.next();
|
||||
}
|
||||
}
|
||||
|
||||
(prev, next)
|
||||
} else {
|
||||
(None, None)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ContentMap {
|
||||
type Target = RleTree<YSpan, YSpanTreeTrait>;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::span::IdSpan;
|
|||
|
||||
use super::y_span::{YSpan, YSpanTreeTrait};
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, EnumAsInner)]
|
||||
pub(super) enum Marker {
|
||||
Insert {
|
||||
|
@ -15,6 +16,7 @@ pub(super) enum Marker {
|
|||
len: usize,
|
||||
},
|
||||
Delete(IdSpan),
|
||||
// TODO: REDO, UNDO
|
||||
}
|
||||
|
||||
impl Sliceable for Marker {
|
||||
|
@ -31,7 +33,10 @@ impl Sliceable for Marker {
|
|||
|
||||
impl HasLength for Marker {
|
||||
fn len(&self) -> usize {
|
||||
todo!()
|
||||
match self {
|
||||
Marker::Insert { ptr, len } => *len,
|
||||
Marker::Delete(span) => span.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::{id::Counter, ContentType, InsertContent, ID};
|
||||
use crate::{
|
||||
container::text::text_content::TextPointer, id::Counter, ContentType, InsertContent, ID,
|
||||
};
|
||||
use rle::{rle_tree::tree_trait::CumulateTreeTrait, HasLength, Mergable, Sliceable};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
|
@ -36,7 +38,7 @@ pub(super) struct YSpan {
|
|||
pub origin_left: ID,
|
||||
pub origin_right: ID,
|
||||
pub id: ID,
|
||||
pub len: usize,
|
||||
pub text: TextPointer,
|
||||
pub status: Status,
|
||||
}
|
||||
|
||||
|
@ -52,6 +54,20 @@ pub(super) enum StatusChange {
|
|||
|
||||
pub(super) type YSpanTreeTrait = CumulateTreeTrait<YSpan, 10>;
|
||||
|
||||
impl YSpan {
|
||||
#[inline]
|
||||
pub fn last_id(&self) -> ID {
|
||||
self.id
|
||||
.inc(std::iter::ExactSizeIterator::len(&self.text) as i32 - 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn can_be_origin(&self) -> bool {
|
||||
debug_assert!(rle::HasLength::len(&self.text) > 0);
|
||||
self.status.is_activated()
|
||||
}
|
||||
}
|
||||
|
||||
impl Mergable for YSpan {
|
||||
fn is_mergable(&self, other: &Self, _: &()) -> bool {
|
||||
other.id.client_id == self.id.client_id
|
||||
|
@ -60,11 +76,12 @@ impl Mergable for YSpan {
|
|||
&& self.id.counter + self.len() as Counter - 1 == other.origin_left.counter
|
||||
&& self.origin_right == other.origin_right
|
||||
&& self.status == other.status
|
||||
&& self.text.is_mergable(&other.text, &())
|
||||
}
|
||||
|
||||
fn merge(&mut self, other: &Self, _: &()) {
|
||||
self.origin_right = other.origin_right;
|
||||
self.len += other.len;
|
||||
self.text.merge(&other.text, &());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +92,7 @@ impl Sliceable for YSpan {
|
|||
origin_left: self.origin_left,
|
||||
origin_right: self.origin_right,
|
||||
id: self.id,
|
||||
len: to - from,
|
||||
text: self.text.slice(from, to),
|
||||
status: self.status.clone(),
|
||||
}
|
||||
} else {
|
||||
|
@ -89,7 +106,7 @@ impl Sliceable for YSpan {
|
|||
client_id: self.id.client_id,
|
||||
counter: self.id.counter + from as Counter,
|
||||
},
|
||||
len: to - from,
|
||||
text: self.text.slice(from, to),
|
||||
status: self.status.clone(),
|
||||
}
|
||||
}
|
||||
|
@ -103,9 +120,10 @@ impl InsertContent for YSpan {
|
|||
}
|
||||
|
||||
impl HasLength for YSpan {
|
||||
#[inline]
|
||||
fn len(&self) -> usize {
|
||||
if self.status.is_activated() {
|
||||
self.len
|
||||
rle::HasLength::len(&self.text)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
@ -119,7 +137,7 @@ mod test {
|
|||
id::ROOT_ID,
|
||||
ContentType, Op, OpContent, ID,
|
||||
};
|
||||
use rle::RleVec;
|
||||
use rle::{HasLength, RleVec};
|
||||
|
||||
use super::YSpan;
|
||||
|
||||
|
@ -133,7 +151,7 @@ mod test {
|
|||
origin_left: ID::new(0, 0),
|
||||
origin_right: ID::null(),
|
||||
id: ID::new(0, 1),
|
||||
len: 1,
|
||||
text: 0..1,
|
||||
status: Default::default(),
|
||||
}),
|
||||
},
|
||||
|
@ -149,7 +167,7 @@ mod test {
|
|||
origin_left: ID::new(0, 1),
|
||||
origin_right: ID::null(),
|
||||
id: ID::new(0, 2),
|
||||
len: 1,
|
||||
text: 1..2,
|
||||
status: Default::default(),
|
||||
}),
|
||||
},
|
||||
|
@ -163,7 +181,7 @@ mod test {
|
|||
assert_eq!(merged.insert_content().id(), ContentType::Text);
|
||||
let text_content =
|
||||
crate::op::utils::downcast_ref::<YSpan>(&**merged.insert_content()).unwrap();
|
||||
assert_eq!(text_content.len, 2);
|
||||
assert_eq!(text_content.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -176,7 +194,7 @@ mod test {
|
|||
origin_left: ID::new(0, 0),
|
||||
origin_right: ID::null(),
|
||||
id: ID::new(0, 1),
|
||||
len: 4,
|
||||
text: 2..6,
|
||||
status: Default::default(),
|
||||
}),
|
||||
},
|
||||
|
@ -192,7 +210,7 @@ mod test {
|
|||
origin_left: ID::new(0, 0),
|
||||
origin_right: ID::new(0, 1),
|
||||
id: ID::new(0, 5),
|
||||
len: 4,
|
||||
text: 3..7,
|
||||
status: Default::default(),
|
||||
}),
|
||||
},
|
||||
|
@ -204,11 +222,11 @@ mod test {
|
|||
assert_eq!(vec.merged_len(), 2);
|
||||
assert_eq!(
|
||||
vec.slice_iter(2, 6)
|
||||
.map(|x| crate::op::utils::downcast_ref::<YSpan>(
|
||||
&**x.into_inner().insert_content()
|
||||
)
|
||||
.unwrap()
|
||||
.len)
|
||||
.map(|x| rle::HasLength::len(
|
||||
&crate::op::utils::downcast_ref::<YSpan>(&**x.into_inner().insert_content())
|
||||
.unwrap()
|
||||
.text
|
||||
))
|
||||
.collect::<Vec<usize>>(),
|
||||
vec![2, 2]
|
||||
)
|
||||
|
|
|
@ -2,9 +2,10 @@ use self::node::{InternalNode, LeafNode, Node};
|
|||
use crate::Rle;
|
||||
pub(self) use bumpalo::collections::vec::Vec as BumpVec;
|
||||
use bumpalo::Bump;
|
||||
pub use cursor::{SafeCursor, SafeCursorMut};
|
||||
pub use cursor::{SafeCursor, SafeCursorMut, UnsafeCursor};
|
||||
use ouroboros::self_referencing;
|
||||
use std::marker::{PhantomData, PhantomPinned};
|
||||
pub use tree_trait::Position;
|
||||
use tree_trait::RleTreeTrait;
|
||||
|
||||
mod cursor;
|
||||
|
@ -92,7 +93,12 @@ impl<'bump, T: Rle, A: RleTreeTrait<T>> RleTreeRaw<'bump, T, A> {
|
|||
return None;
|
||||
}
|
||||
|
||||
return Some(SafeCursor::new(leaf.into(), result.child_index, result.pos));
|
||||
return Some(SafeCursor::new(
|
||||
leaf.into(),
|
||||
result.child_index,
|
||||
result.offset,
|
||||
result.pos,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +125,12 @@ impl<'bump, T: Rle, A: RleTreeTrait<T>> RleTreeRaw<'bump, T, A> {
|
|||
return None;
|
||||
}
|
||||
|
||||
return Some(SafeCursor::new(leaf.into(), result.child_index, result.pos));
|
||||
return Some(SafeCursor::new(
|
||||
leaf.into(),
|
||||
result.child_index,
|
||||
result.offset,
|
||||
result.pos,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@ use crate::{Rle, RleTreeTrait};
|
|||
use super::{node::LeafNode, tree_trait::Position};
|
||||
|
||||
pub struct UnsafeCursor<'tree, 'bump, T: Rle, A: RleTreeTrait<T>> {
|
||||
pub(crate) leaf: NonNull<LeafNode<'bump, T, A>>,
|
||||
pub(crate) index: usize,
|
||||
pub(crate) pos: Position,
|
||||
pub leaf: NonNull<LeafNode<'bump, T, A>>,
|
||||
pub index: usize,
|
||||
pub offset: usize,
|
||||
pub pos: Position,
|
||||
_phantom: PhantomData<&'tree usize>,
|
||||
}
|
||||
|
||||
|
@ -18,6 +19,7 @@ impl<'tree, 'bump, T: Rle, A: RleTreeTrait<T>> Clone for UnsafeCursor<'tree, 'bu
|
|||
leaf: self.leaf,
|
||||
index: self.index,
|
||||
pos: self.pos,
|
||||
offset: self.offset,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -45,11 +47,17 @@ impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> Copy for SafeCursor<'tree,
|
|||
|
||||
impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> UnsafeCursor<'tree, 'bump, T, A> {
|
||||
#[inline]
|
||||
pub(crate) fn new(leaf: NonNull<LeafNode<'bump, T, A>>, index: usize, pos: Position) -> Self {
|
||||
pub(crate) fn new(
|
||||
leaf: NonNull<LeafNode<'bump, T, A>>,
|
||||
index: usize,
|
||||
offset: usize,
|
||||
pos: Position,
|
||||
) -> Self {
|
||||
Self {
|
||||
leaf,
|
||||
index,
|
||||
pos,
|
||||
offset,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -81,20 +89,20 @@ impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> UnsafeCursor<'tree, 'bump,
|
|||
pub unsafe fn next(&self) -> Option<Self> {
|
||||
let leaf = self.leaf.as_ref();
|
||||
if leaf.children.len() > self.index + 1 {
|
||||
return Some(Self::new(self.leaf, self.index + 1, self.pos));
|
||||
return Some(Self::new(self.leaf, self.index + 1, 0, Position::Start));
|
||||
}
|
||||
|
||||
leaf.next.map(|next| Self::new(next, 0, self.pos))
|
||||
leaf.next.map(|next| Self::new(next, 0, 0, Position::Start))
|
||||
}
|
||||
|
||||
pub unsafe fn prev(&self) -> Option<Self> {
|
||||
let leaf = self.leaf.as_ref();
|
||||
if self.index > 0 {
|
||||
return Some(Self::new(self.leaf, self.index - 1, self.pos));
|
||||
return Some(Self::new(self.leaf, self.index - 1, 0, Position::Start));
|
||||
}
|
||||
|
||||
leaf.prev
|
||||
.map(|prev| Self::new(prev, prev.as_ref().children.len() - 1, self.pos))
|
||||
.map(|prev| Self::new(prev, prev.as_ref().children.len() - 1, 0, Position::Start))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,12 +138,30 @@ impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> SafeCursor<'tree, 'bump, T
|
|||
pub fn index(&self) -> usize {
|
||||
self.0.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> SafeCursor<'tree, 'bump, T, A> {
|
||||
#[inline]
|
||||
pub(crate) fn new(leaf: NonNull<LeafNode<'bump, T, A>>, index: usize, pos: Position) -> Self {
|
||||
Self(UnsafeCursor::new(leaf, index, pos))
|
||||
pub fn pos(&self) -> Position {
|
||||
self.0.pos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.0.offset
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new(
|
||||
leaf: NonNull<LeafNode<'bump, T, A>>,
|
||||
index: usize,
|
||||
offset: usize,
|
||||
pos: Position,
|
||||
) -> Self {
|
||||
Self(UnsafeCursor::new(leaf, index, offset, pos))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> UnsafeCursor<'tree, 'bump, T, A> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,12 +193,17 @@ impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> SafeCursorMut<'tree, 'bump
|
|||
|
||||
impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> SafeCursorMut<'tree, 'bump, T, A> {
|
||||
#[inline]
|
||||
pub(crate) fn new(leaf: NonNull<LeafNode<'bump, T, A>>, index: usize, pos: Position) -> Self {
|
||||
Self(UnsafeCursor::new(leaf, index, pos))
|
||||
pub(crate) fn new(
|
||||
leaf: NonNull<LeafNode<'bump, T, A>>,
|
||||
index: usize,
|
||||
offset: usize,
|
||||
pos: Position,
|
||||
) -> Self {
|
||||
Self(UnsafeCursor::new(leaf, index, offset, pos))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_mut_(&mut self) -> &'tree mut T {
|
||||
fn as_tree_mut(&mut self) -> &'tree mut T {
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
|
||||
|
@ -189,6 +220,36 @@ impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> SafeCursorMut<'tree, 'bump
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unwrap(self) -> UnsafeCursor<'tree, 'bump, T, A> {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn next(&self) -> Option<Self> {
|
||||
unsafe { self.0.next().map(|x| Self(x)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn prev(&self) -> Option<Self> {
|
||||
unsafe { self.0.prev().map(|x| Self(x)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index(&self) -> usize {
|
||||
self.0.index
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pos(&self) -> Position {
|
||||
self.0.pos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn offset(&self) -> usize {
|
||||
self.0.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tree, 'bump: 'tree, T: Rle, A: RleTreeTrait<T>> AsMut<T>
|
||||
|
|
|
@ -70,6 +70,7 @@ impl<'rf, 'bump, T: Rle, A: RleTreeTrait<T>> Iterator for Iter<'rf, 'bump, T, A>
|
|||
return Some(SafeCursor::new(
|
||||
node.into(),
|
||||
self.child_index - 1,
|
||||
0,
|
||||
Position::Start,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -51,13 +51,13 @@ impl<'bump, T: Rle, A: RleTreeTrait<T>> LeafNode<'bump, T, A> {
|
|||
#[inline]
|
||||
pub fn get_cursor<'tree>(&'tree self, pos: A::Int) -> SafeCursor<'tree, 'bump, T, A> {
|
||||
let result = A::find_pos_leaf(self, pos);
|
||||
SafeCursor::new(self.into(), result.child_index, result.pos)
|
||||
SafeCursor::new(self.into(), result.child_index, result.offset, result.pos)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_cursor_mut<'b>(&'b mut self, pos: A::Int) -> SafeCursorMut<'b, 'bump, T, A> {
|
||||
let result = A::find_pos_leaf(self, pos);
|
||||
SafeCursorMut::new(self.into(), result.child_index, result.pos)
|
||||
SafeCursorMut::new(self.into(), result.child_index, result.offset, result.pos)
|
||||
}
|
||||
|
||||
pub fn push_child<F>(
|
||||
|
|
|
@ -12,10 +12,11 @@ use super::node::{InternalNode, LeafNode, Node};
|
|||
/// - Or it is before/after a node.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Position {
|
||||
Before,
|
||||
Start,
|
||||
Middle,
|
||||
// can after and end be merged together?
|
||||
End,
|
||||
Before,
|
||||
After,
|
||||
}
|
||||
|
||||
|
|
10
justfile
10
justfile
|
@ -4,13 +4,13 @@ build:
|
|||
test *FLAGS:
|
||||
RUST_BACKTRACE=full cargo nextest run {{FLAGS}}
|
||||
|
||||
# test without proptest
|
||||
test-fast *FLAGS:
|
||||
RUSTFLAGS='--cfg no_proptest' cargo nextest run {{FLAGS}}
|
||||
# test with proptest
|
||||
test-prop *FLAGS:
|
||||
RUST_BACKTRACE=full RUSTFLAGS='--cfg proptest' cargo nextest run {{FLAGS}}
|
||||
|
||||
# test with slower proptest
|
||||
test-slow *FLAGS:
|
||||
RUSTFLAGS='--cfg slow_proptest' cargo nextest run {{FLAGS}}
|
||||
test-slowprop *FLAGS:
|
||||
RUST_BACKTRACE=full RUSTFLAGS='--cfg slow_proptest' cargo nextest run {{FLAGS}}
|
||||
|
||||
check-unsafe:
|
||||
env RUSTFLAGS="-Funsafe-code --cap-lints=warn" cargo check
|
||||
|
|
Loading…
Reference in a new issue