🔧 refactor cursor API and normalize chunking logic
- Change `rope_tell()` return type from Option<usize> to usize, always returning cursor's absolute position (offset if unmoved). - Update all call sites to remove `.unwrap_or(...)` around `rope_tell()`. - Add new method `<Rope>::truncate(pos)`, replacing `split_off(...).map(|_| ())`. - Refactor FASTA/FASTQ normalizers to use a single mutable write cursor (`wc`) and document the protocol. - Simplify `end_segment()` logic: commit segment with 0x00 if length ≥ k, else reset. - Improve documentation for write-cursor protocol and rope truncation semantics.
This commit is contained in:
+15
-10
@@ -185,11 +185,16 @@ pub trait RopeCursor<'a> {
|
||||
Some(abs.saturating_sub(self.state().offset.get()))
|
||||
}
|
||||
|
||||
/// Current position as an absolute rope index, or `None` if the cursor
|
||||
/// has not moved yet. Use this when you need to pass a value to
|
||||
/// [`seek`](RopeCursor::seek) with [`SeekMode::Absolute`].
|
||||
fn rope_tell(&self) -> Option<usize> {
|
||||
self.state().current.get()
|
||||
/// Current position as an absolute rope index.
|
||||
///
|
||||
/// Unlike [`tell`](RopeCursor::tell), this method **always** returns a
|
||||
/// value: if the cursor has not moved yet, it returns the cursor's offset
|
||||
/// (the rope index of local position 0).
|
||||
///
|
||||
/// Use the returned value with [`SeekMode::Rope`] to restore a position,
|
||||
/// or as a truncation point after a write pass.
|
||||
fn rope_tell(&self) -> usize {
|
||||
self.state().current.get().unwrap_or(self.state().offset.get())
|
||||
}
|
||||
|
||||
/// Number of bytes visible through this cursor (`rope.len() - offset`).
|
||||
@@ -295,7 +300,7 @@ impl<'a> ForwardCursor<'a> {
|
||||
/// an `offset` equal to `self.absolute_tell()`. If `self` has not moved
|
||||
/// yet, the new cursor starts at the same offset as `self`.
|
||||
pub fn cursor(&self) -> ForwardCursor<'a> {
|
||||
let new_offset = self.rope_tell().unwrap_or(self.state.offset.get());
|
||||
let new_offset = self.rope_tell();
|
||||
ForwardCursor {
|
||||
rope: self.rope,
|
||||
state: CursorState::with_offset(new_offset),
|
||||
@@ -431,7 +436,7 @@ impl<'a> BackwardCursor<'a> {
|
||||
/// position of `self`. If `self` has not moved yet, the new cursor has the
|
||||
/// same offset as `self` (no restriction).
|
||||
pub fn cursor(&self) -> BackwardCursor<'a> {
|
||||
let new_offset = self.rope_tell().unwrap_or(self.state.offset.get());
|
||||
let new_offset = self.rope_tell();
|
||||
BackwardCursor {
|
||||
rope: self.rope,
|
||||
state: CursorState::with_offset(new_offset),
|
||||
@@ -723,7 +728,7 @@ mod tests {
|
||||
let sub = c.cursor(); // offset=2 (absolute_tell=2)
|
||||
assert_eq!(sub.read_next().unwrap(), b'C'); // reads index 2
|
||||
assert_eq!(sub.tell(), Some(0)); // relative: 2-2=0
|
||||
assert_eq!(sub.rope_tell(), Some(2));
|
||||
assert_eq!(sub.rope_tell(), 2);
|
||||
assert_eq!(sub.read_next().unwrap(), b'D');
|
||||
assert_eq!(sub.tell(), Some(1)); // relative: 3-2=1
|
||||
}
|
||||
@@ -810,11 +815,11 @@ mod tests {
|
||||
sub.read_next().unwrap(); // reads index 0, absolute_tell=0
|
||||
sub.read_next().unwrap(); // reads index 1, absolute_tell=1
|
||||
assert_eq!(sub.tell(), Some(1));
|
||||
assert_eq!(sub.rope_tell(), Some(1));
|
||||
assert_eq!(sub.rope_tell(), 1);
|
||||
// sub2 with offset=1
|
||||
let sub2 = sub.cursor(); // offset=1
|
||||
sub2.read_next().unwrap(); // reads index 1, absolute=1
|
||||
assert_eq!(sub2.tell(), Some(0)); // relative: 1-1=0
|
||||
assert_eq!(sub2.rope_tell(), Some(1));
|
||||
assert_eq!(sub2.rope_tell(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +155,14 @@ impl Rope {
|
||||
})
|
||||
}
|
||||
|
||||
/// Discard all bytes at and after `pos`, keeping `[0, pos)`.
|
||||
///
|
||||
/// Equivalent to `split_off(pos)` with the tail dropped.
|
||||
/// Returns `Err` if `pos > self.length`.
|
||||
pub fn truncate(&mut self, pos: usize) -> Result<(), RopeError> {
|
||||
self.split_off(pos).map(|_| ())
|
||||
}
|
||||
|
||||
/// Create a forward cursor positioned before the first byte.
|
||||
pub fn fw_cursor(&self) -> ForwardCursor<'_> {
|
||||
ForwardCursor::new(self)
|
||||
|
||||
Reference in New Issue
Block a user