pub struct Rope { /* private fields */ }
Expand description
A utf8 text rope.
The time complexity of nearly all edit and query operations on Rope
are
worst-case O(log N)
in the length of the rope. Rope
is designed to work
efficiently even for huge (in the gigabytes) and pathological (all on one
line) texts.
§Editing Operations
The editing operations on Rope
are insertion and removal of text. For
example:
let mut rope = Rope::from_str("Hello みんなさん!");
rope.remove(6..21);
rope.insert(6, "world");
assert_eq!(rope, "Hello world!");
§Query Operations
Rope
provides a rich set of efficient query functions, including querying
rope length in bytes/char
s/lines, fetching individual char
s or lines,
and converting between different indexing metrics.
For example, to find the starting byte index of a given line:
use ropey::LineType::LF_CR;
let rope = Rope::from_str("Hello みんなさん!\nHow are you?\nThis text has multiple lines!");
assert_eq!(rope.line_to_byte_idx(0, LF_CR), 0);
assert_eq!(rope.line_to_byte_idx(1, LF_CR), 23);
assert_eq!(rope.line_to_byte_idx(2, LF_CR), 36);
§Slicing
You can take immutable slices of a Rope
using slice()
:
let mut rope = Rope::from_str("Hello みんなさん!");
let middle = rope.slice(3..12);
assert_eq!(middle, "lo みん");
§Cloning
Cloning Rope
s is extremely cheap, running in O(1)
time and taking a
small constant amount of memory for the new clone, regardless of text size.
This is accomplished by data sharing between Rope
clones. The memory used
by clones only grows incrementally as the their contents diverge due to
edits. All of this is thread safe, so clones can be sent freely between
threads.
The primary intended use case for this feature is to allow asynchronous (in
the general sense, not necessarily in the async
sense) processing of
Rope
s. For example, saving a large document to disk in a separate thread
while the user continues to perform edits.
Implementations§
Source§impl Rope
impl Rope
Sourcepub fn from_reader<T>(reader: T) -> Result<Rope, Error>where
T: Read,
pub fn from_reader<T>(reader: T) -> Result<Rope, Error>where
T: Read,
Creates a Rope
from the output of a reader.
This is a convenience function, and provides no specific guarantees about performance or internal implementation aside from the runtime complexity listed below.
When more precise control over IO behavior, buffering, etc. is desired,
you should handle IO yourself and use RopeBuilder
to build the
Rope
.
Runs in O(N) time.
§Errors
- If the reader returns an error,
from_reader
stops and returns that error. - If non-utf8 data is encountered, an IO error with kind
InvalidData
is returned.
Note: some data from the reader is likely consumed even if there is an error.
Sourcepub fn write_to<T>(&self, writer: T) -> Result<(), Error>where
T: Write,
pub fn write_to<T>(&self, writer: T) -> Result<(), Error>where
T: Write,
Writes the contents of the Rope
to a writer.
This is a convenience function, and provides no specific guarantees about performance or internal implementation aside from the runtime complexity listed below.
When more precise control over IO behavior, buffering, etc. is
desired, you should handle IO yourself and use the Chunks
iterator to iterate through the Rope
’s contents.
Runs in O(N) time.
§Errors
- If the writer returns an error,
write_to
stops and returns that error.
Note: some data may have been written even if an error is returned.
Sourcepub fn insert(&mut self, byte_idx: usize, text: &str)
pub fn insert(&mut self, byte_idx: usize, text: &str)
Inserts text
at byte index byte_idx
.
Runs in O(M log N) time, where N is the length of the Rope
and M
is the length of text
.
§Example
let mut rope = Rope::from_str("Hello!");
rope.insert(5, " world");
assert_eq!("Hello world!", rope);
§Panics
- If
byte_idx
is out of bounds (i.e.byte_idx > len()
). - If
byte_idx
is not on a char boundary.
Sourcepub fn insert_char(&mut self, byte_idx: usize, ch: char)
pub fn insert_char(&mut self, byte_idx: usize, ch: char)
Sourcepub fn remove<R>(&mut self, byte_range: R)where
R: RangeBounds<usize>,
pub fn remove<R>(&mut self, byte_range: R)where
R: RangeBounds<usize>,
Removes the text in the given byte index range.
Uses range syntax, e.g. 2..7
, 2..
, etc.
Runs in O(M + log N) time, where N is the length of the Rope
and M
is the length of the range being removed.
§Example
let mut rope = Rope::from_str("Hello world!");
rope.remove(5..);
assert_eq!("Hello", rope);
§Panics
- If the start of the range is greater than the end.
- If the end of the range is out of bounds (i.e.
end > len()
). - If the range ends are not on char boundaries.
Sourcepub fn slice<R>(&self, byte_range: R) -> RopeSlice<'_>where
R: RangeBounds<usize>,
pub fn slice<R>(&self, byte_range: R) -> RopeSlice<'_>where
R: RangeBounds<usize>,
Gets an immutable slice of the Rope
.
Uses range syntax, e.g. 2..7
, 2..
, etc.
§Example
let rope = Rope::from_str("Hello world!");
let slice = rope.slice(..5);
assert_eq!("Hello", slice);
Runs in O(log N) time.
§Panics
- If the start of the range is greater than the end.
- If the end of the range is out of bounds (i.e.
end > len()
). - If the range ends are not on char boundaries.
Sourcepub fn len_utf16(&self) -> usize
pub fn len_utf16(&self) -> usize
Total number of utf16 code units that would be in the text if it were encoded as utf16.
Runs in best case O(1) time, worst-case O(log N).
Sourcepub fn len_lines(&self, line_type: LineType) -> usize
pub fn len_lines(&self, line_type: LineType) -> usize
Total number of lines in the text, according to the passed line type.
Runs in best case O(1) time, worst-case O(log N).
Sourcepub fn is_char_boundary(&self, byte_idx: usize) -> bool
pub fn is_char_boundary(&self, byte_idx: usize) -> bool
Returns whether byte_idx
is a char
boundary.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn floor_char_boundary(&self, byte_idx: usize) -> usize
pub fn floor_char_boundary(&self, byte_idx: usize) -> usize
Returns the byte index of the closest char boundary less than or
equal to byte_idx
.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn ceil_char_boundary(&self, byte_idx: usize) -> usize
pub fn ceil_char_boundary(&self, byte_idx: usize) -> usize
Returns the byte index of the closest char boundary greater than or
equal to byte_idx
.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn trailing_line_break_idx(&self, line_type: LineType) -> Option<usize>
pub fn trailing_line_break_idx(&self, line_type: LineType) -> Option<usize>
If the text ends with a line break, returns its byte index.
Otherwise returns None
.
Note: a CRLF pair is always treated as a single unit, and thus
this function will return the index of the CR in such cases, even
with LineType::LF
where CR is not on its own recognized as a line
break.
Runs in O(log N) time.
Sourcepub fn byte(&self, byte_idx: usize) -> u8
pub fn byte(&self, byte_idx: usize) -> u8
Returns the byte at byte_idx
.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx >= len()
).
Sourcepub fn char(&self, byte_idx: usize) -> char
pub fn char(&self, byte_idx: usize) -> char
Returns the char
at byte_idx
.
Note that this takes a byte index, not a char index.
Runs in O(log N) time.
§Panics
- If
byte_idx
is out of bounds (i.e.byte_idx >= len()
). - If
byte_idx
is not a char boundary.
Sourcepub fn line(&self, line_idx: usize, line_type: LineType) -> RopeSlice<'_>
pub fn line(&self, line_idx: usize, line_type: LineType) -> RopeSlice<'_>
Returns the line at line_idx
, according to the given line type.
Note: lines are zero-indexed.
Runs in O(log N) time.
§Panics
Panics if line_idx
is out of bounds (i.e. line_idx >= len_lines()
).
Sourcepub fn chunk(&self, byte_idx: usize) -> (&str, usize)
pub fn chunk(&self, byte_idx: usize) -> (&str, usize)
Returns the chunk containing the byte at byte_idx
.
Also returns the byte index of the beginning of the chunk.
Note: for convenience, a one-past-the-end byte_idx
returns the last
chunk of the RopeSlice
.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn byte_to_utf16_idx(&self, byte_idx: usize) -> usize
pub fn byte_to_utf16_idx(&self, byte_idx: usize) -> usize
Returns the utf16 code unit index of the given byte.
Ropey stores text internally as utf8, but sometimes it is necessary to interact with external APIs that still use utf16. This function is primarily intended for such situations, and is otherwise not very useful.
Note: if the byte is not on a char boundary, this returns the utf16 code unit index corresponding to the char that the byte belongs to.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn utf16_to_byte_idx(&self, utf16_idx: usize) -> usize
pub fn utf16_to_byte_idx(&self, utf16_idx: usize) -> usize
Returns the byte index of the given utf16 code unit.
Ropey stores text internally as utf8, but sometimes it is necessary to interact with external APIs that still use utf16. This function is primarily intended for such situations, and is otherwise not very useful.
Note: if the utf16 code unit is in the middle of a char, returns the byte index of the char that it belongs to.
Runs in O(log N) time.
§Panics
Panics if utf16_cu_idx
is out of bounds
(i.e. utf16_idx > len_utf16()
).
Sourcepub fn byte_to_line_idx(&self, byte_idx: usize, line_type: LineType) -> usize
pub fn byte_to_line_idx(&self, byte_idx: usize, line_type: LineType) -> usize
Returns the line index of the line that the given byte belongs to.
Notes:
- Counts lines according to the passed line type.
- Lines are zero-indexed. Therefore this is functionally equivalent to counting the line breaks before the specified byte.
byte_idx
can be one-past-the-end, which will return the last line index.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn line_to_byte_idx(&self, line_idx: usize, line_type: LineType) -> usize
pub fn line_to_byte_idx(&self, line_idx: usize, line_type: LineType) -> usize
Returns the byte index of the start of the given line.
Notes:
- Counts lines according to the passed line type.
- Lines are zero-indexed.
line_idx
can be one-past-the-end, which will return one-past-the-end byte index.
Runs in O(log N) time.
§Panics
Panics if line_idx
is out of bounds (i.e. line_idx > len_lines()
).
Sourcepub fn bytes(&self) -> Bytes<'_>
pub fn bytes(&self) -> Bytes<'_>
Creates an iterator over the bytes of the Rope
.
Runs in O(log N) time.
Sourcepub fn bytes_at(&self, byte_idx: usize) -> Bytes<'_>
pub fn bytes_at(&self, byte_idx: usize) -> Bytes<'_>
Creates an iterator over the bytes of the Rope
, starting at byte
byte_idx
.
If byte_idx == len()
then an iterator at the end of the
Rope
is created (i.e. next()
will return None
).
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn chars(&self) -> Chars<'_>
pub fn chars(&self) -> Chars<'_>
Creates an iterator over the chars of the Rope
.
Runs in O(log N) time.
Sourcepub fn chars_at(&self, byte_idx: usize) -> Chars<'_>
pub fn chars_at(&self, byte_idx: usize) -> Chars<'_>
Creates an iterator over the chars of the Rope
, starting
at byte_idx
.
Note that this takes a byte index, not a char index.
If byte_idx == len()
then an iterator at the end of the
Rope
is created (i.e. next()
will return None
).
Runs in O(log N) time.
§Panics
- If
byte_idx
is out of bounds (i.e.byte_idx > len()
). - If
byte_idx
is not a char boundary.
Sourcepub fn char_indices(&self) -> CharIndices<'_>
pub fn char_indices(&self) -> CharIndices<'_>
Sourcepub fn char_indices_at(&self, byte_idx: usize) -> CharIndices<'_>
pub fn char_indices_at(&self, byte_idx: usize) -> CharIndices<'_>
Creates an iterator over the chars of the Rope
and their byte
positions, starting at byte_idx
.
Note that this takes a byte index, not a char index.
If byte_idx == len()
then an iterator at the end of the Rope
is
created (i.e. next()
will return None
).
On each call to next
or
prev
this iterator returns the byte index
where the returned character starts.
Runs in O(log N) time.
§Panics
- If
byte_idx
is out of bounds (i.e.byte_idx > len()
). - If
byte_idx
is not a char boundary.
Sourcepub fn lines(&self, line_type: LineType) -> Lines<'_>
pub fn lines(&self, line_type: LineType) -> Lines<'_>
Creates an iterator over the lines of the Rope
.
Note: the iterator will iterate over lines according to the passed line type.
Runs in O(log N) time.
Sourcepub fn lines_at(&self, line_idx: usize, line_type: LineType) -> Lines<'_>
pub fn lines_at(&self, line_idx: usize, line_type: LineType) -> Lines<'_>
Creates an iterator over the lines of the Rope
, starting at line
line_idx
.
Notes:
- The iterator will iterate over lines according to the passed line type.
- If
line_idx == len_lines()
then an iterator at the end of theRope
is created (i.e.next()
will returnNone
).
Runs in O(log N) time.
§Panics
Panics if line_idx
is out of bounds (i.e. line_idx > len_lines()
).
Sourcepub fn chunks(&self) -> Chunks<'_>
pub fn chunks(&self) -> Chunks<'_>
Creates an iterator over the chunks of the Rope
.
Runs in O(log N) time.
Sourcepub fn chunks_at(&self, byte_idx: usize) -> (Chunks<'_>, usize)
pub fn chunks_at(&self, byte_idx: usize) -> (Chunks<'_>, usize)
Creates an iterator over the chunks of the Rope
, with the iterator
starting at the chunk containing byte_idx
.
Also returns the byte index of the beginning of the chunk to be
yielded by next()
.
If byte_idx == len()
an iterator at the end of the Rope
(yielding None
on a call to next()
) is created, and the returned
byte index is the end of the text.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Sourcepub fn chunk_cursor(&self) -> ChunkCursor<'_>
pub fn chunk_cursor(&self) -> ChunkCursor<'_>
Creates a cursor for navigating the chunks of the text, starting on the first chunk.
Runs in O(log N) time.
Sourcepub fn chunk_cursor_at(&self, byte_idx: usize) -> ChunkCursor<'_>
pub fn chunk_cursor_at(&self, byte_idx: usize) -> ChunkCursor<'_>
Creates a cursor for navigating the chunks of the text, with the
cursor starting at the chunk containing byte_idx
.
For convenience, byte_idx == len()
is accepted, and puts the
cursor on the last chunk. Note that for non-zero-length texts this
is redundant with byte_idx == len() - 1
.
Runs in O(log N) time.
§Panics
Panics if byte_idx
is out of bounds (i.e. byte_idx > len()
).
Source§impl Rope
Non-panicking versions of some of Rope
’s methods.
impl Rope
Non-panicking versions of some of Rope
’s methods.
Sourcepub fn try_insert(&mut self, byte_idx: usize, text: &str) -> Result<(), Error>
pub fn try_insert(&mut self, byte_idx: usize, text: &str) -> Result<(), Error>
Non-panicking version of insert()
.
On failure this leaves the rope untouched and returns the cause of the failure.
Sourcepub fn try_insert_char(
&mut self,
byte_idx: usize,
ch: char,
) -> Result<(), Error>
pub fn try_insert_char( &mut self, byte_idx: usize, ch: char, ) -> Result<(), Error>
Non-panicking version of insert_char()
.
On failure this leaves the rope untouched and returns the cause of the failure.
Sourcepub fn try_remove<R>(&mut self, byte_range: R) -> Result<(), Error>where
R: RangeBounds<usize>,
pub fn try_remove<R>(&mut self, byte_range: R) -> Result<(), Error>where
R: RangeBounds<usize>,
Non-panicking version of remove()
.
On failure this leaves the rope untouched and returns the cause of the failure.
Sourcepub fn try_slice<R>(&self, byte_range: R) -> Result<RopeSlice<'_>, Error>where
R: RangeBounds<usize>,
pub fn try_slice<R>(&self, byte_range: R) -> Result<RopeSlice<'_>, Error>where
R: RangeBounds<usize>,
Non-panicking version of slice()
.
On failure this returns the cause of the failure.
Sourcepub fn get_byte(&self, byte_idx: usize) -> Option<u8>
pub fn get_byte(&self, byte_idx: usize) -> Option<u8>
Non-panicking version of byte()
.
If byte_idx
is out of bounds, returns None
.
Sourcepub fn get_char(&self, byte_idx: usize) -> Result<char, Error>
pub fn get_char(&self, byte_idx: usize) -> Result<char, Error>
Non-panicking version of char()
.
Will fail if byte_idx
is either:
- Not a char boundary.
- Out of bounds.
On failure returns the cause of failure.
Trait Implementations§
Source§impl<'a> From<&'a Rope> for Option<&'a str>
Attempts to borrow the text contents, but will return None
if the
contents is not contiguous in memory.
impl<'a> From<&'a Rope> for Option<&'a str>
Attempts to borrow the text contents, but will return None
if the
contents is not contiguous in memory.
Runs in O(1) time.
Source§impl<'a> FromIterator<&'a str> for Rope
impl<'a> FromIterator<&'a str> for Rope
Source§impl FromIterator<String> for Rope
impl FromIterator<String> for Rope
Source§impl Ord for Rope
impl Ord for Rope
Source§impl PartialOrd for Rope
impl PartialOrd for Rope
Source§impl RopeExt for Rope
impl RopeExt for Rope
Source§fn slice_line(&self, row: usize) -> RopeSlice<'_>
fn slice_line(&self, row: usize) -> RopeSlice<'_>
\r
if present, but not \n
. Read moreSource§fn slice_lines(&self, rows_range: Range<usize>) -> RopeSlice<'_>
fn slice_lines(&self, rows_range: Range<usize>) -> RopeSlice<'_>
Source§fn iter_lines(&self) -> RopeLines<'_> ⓘ
fn iter_lines(&self) -> RopeLines<'_> ⓘ
Source§fn line_len(&self, row: usize) -> usize
fn line_len(&self, row: usize) -> usize
\r
if present, but not \n
. Read moreSource§fn line_start_offset(&self, row: usize) -> usize
fn line_start_offset(&self, row: usize) -> usize
Source§fn offset_to_point(&self, offset: usize) -> Point
fn offset_to_point(&self, offset: usize) -> Point
Source§fn point_to_offset(&self, point: Point) -> usize
fn point_to_offset(&self, point: Point) -> usize
Source§fn position_to_offset(&self, pos: &Position) -> usize
fn position_to_offset(&self, pos: &Position) -> usize
Source§fn offset_to_position(&self, offset: usize) -> Position
fn offset_to_position(&self, offset: usize) -> Position
Source§fn line_end_offset(&self, row: usize) -> usize
fn line_end_offset(&self, row: usize) -> usize
\n
) of the line at the given row (0-based) index. Read moreSource§fn char_at(&self, offset: usize) -> Option<char>
fn char_at(&self, offset: usize) -> Option<char>
Source§fn word_range(&self, offset: usize) -> Option<Range<usize>>
fn word_range(&self, offset: usize) -> Option<Range<usize>>
Source§fn offset_utf16_to_offset(&self, offset_utf16: usize) -> usize
fn offset_utf16_to_offset(&self, offset_utf16: usize) -> usize
Source§fn offset_to_offset_utf16(&self, offset: usize) -> usize
fn offset_to_offset_utf16(&self, offset: usize) -> usize
impl Eq for Rope
Auto Trait Implementations§
impl Freeze for Rope
impl RefUnwindSafe for Rope
impl Send for Rope
impl Sync for Rope
impl Unpin for Rope
impl UnwindSafe for Rope
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<K> MapSeekTarget<K> for Kwhere
K: Ord,
impl<K> MapSeekTarget<K> for Kwhere
K: Ord,
fn cmp_cursor(&self, cursor_location: &K) -> Ordering
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian()
.