Skip to content

Commit

Permalink
feat: add support for mutable peeking
Browse files Browse the repository at this point in the history
  • Loading branch information
nfejzic committed Oct 7, 2023
1 parent 38302d0 commit 93d664a
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ribbon"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
authors = ["Nadir Fejzic <nadirfejzo@gmail.com>"]
description = "Tape machine for peeking through windows of iterators."
Expand Down
37 changes: 35 additions & 2 deletions src/band.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,22 @@ where
self.peek_at(0)
}

fn peek_front_mut(&mut self) -> Option<&mut I::Item> {
self.peek_at_mut(0)
}

fn pop_back(&mut self) -> Option<I::Item> {
let back = self.tape[self.tail()].take()?;
self.len -= 1;
Some(back)
}

fn peek_back(&self) -> Option<&I::Item> {
let idx = self.len().saturating_sub(1);
self.peek_at(idx)
self.peek_at(self.tail())
}

fn peek_back_mut(&mut self) -> Option<&mut I::Item> {
self.peek_at_mut(self.tail())
}

fn peek_at(&self, index: usize) -> Option<&I::Item> {
Expand All @@ -117,6 +124,15 @@ where
self.tape.get(idx)?.as_ref()
}

fn peek_at_mut(&mut self, index: usize) -> Option<&mut I::Item> {
if index >= LEN {
return None;
}

let idx = (self.head + index) % LEN;
self.tape.get_mut(idx)?.as_mut()
}

fn len(&self) -> usize {
self.len
}
Expand Down Expand Up @@ -254,6 +270,23 @@ mod tests {
assert_eq!(band.progress(), None);
}

#[test]
fn peek_back() {
let mut band = (0..10).band::<5>();

assert_eq!(band.len(), 0);
band.expand_n(5);

assert_eq!(band.len(), 5);
assert_eq!(band.peek_back(), Some(&4));

if let Some(item) = band.peek_back_mut() {
*item = 42;
}

assert_eq!(band.peek_back(), Some(&42));
}

#[test]
fn is_iterator() {
let mut band = (0..10).band::<5>();
Expand Down
78 changes: 71 additions & 7 deletions src/ribbon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ pub trait Ribbon<T> {
/// ```
fn pop_front(&mut self) -> Option<T>;

/// Returns a reference to the item stored at the head of `Ribbon` and returns it (if
/// available).
/// Returns a reference to the item stored at the head of `Ribbon` if item exists. Returns
/// `None` otherwise.
///
/// # Example
///
Expand All @@ -106,7 +106,25 @@ pub trait Ribbon<T> {
self.peek_at(0)
}

/// Removes the item stored at the tail of `Ribbon` and returns it (if available).
/// Returns a mutable reference to the item stored at the head of `Ribbon` if item exists.
/// Returns `None` otherwise.
///
/// # Example
///
/// ```rust
/// use ribbon::{Ribbon, Tape};
///
/// let mut tape = Tape::new(0..10);
///
/// tape.expand_n(2);
/// assert_eq!(tape.len(), 2);
/// assert_eq!(tape.peek_front(), Some(&0));
/// assert_eq!(tape.len(), 2);
/// ```
fn peek_front_mut(&mut self) -> Option<&mut T>;

/// Removes the item stored at the tail of `Ribbon` and returns it if it exists. Returns `None`
/// otherwise.
///
/// # Example
///
Expand All @@ -124,8 +142,8 @@ pub trait Ribbon<T> {
/// ```
fn pop_back(&mut self) -> Option<T>;

/// Returns a reference to the item stored at the tail of `Ribbon` and returns it (if
/// available).
/// Returns a reference to the item stored at the tail of `Ribbon` if item exists. Returns
/// `None` otherwise.
///
/// # Example
///
Expand All @@ -148,8 +166,33 @@ pub trait Ribbon<T> {
self.peek_at(self.len() - 1)
}

/// Returns a reference to the item stored at the given index of `Ribbon` and returns it (if
/// available). Returns `None` if index out of bounds.
/// Returns a mutable reference to the item stored at the tail of `Ribbon` if item exists.
/// Returns `None` otherwise.
///
/// # Example
///
/// ```rust
/// use ribbon::{Ribbon, Tape};
///
/// let mut tape = Tape::new(0..10);
///
/// tape.expand_n(3);
/// assert_eq!(tape.len(), 3);
/// assert_eq!(tape.peek_back(), Some(&2));
///
/// if let Some(item) = tape.peek_back_mut() { *item = 42; }
/// assert_eq!(tape.peek_back(), Some(&42));
///
/// tape.expand();
/// assert_eq!(tape.peek_back(), Some(&3));
///
/// tape.expand();
/// assert_eq!(tape.peek_back(), Some(&4));
/// ```
fn peek_back_mut(&mut self) -> Option<&mut T>;

/// Returns a reference to the item stored at the given index of `Ribbon` if item exists.
/// Returns `None` if index out of bounds.
///
/// # Example
///
Expand All @@ -166,6 +209,27 @@ pub trait Ribbon<T> {
/// ```
fn peek_at(&self, index: usize) -> Option<&T>;

/// Returns a mutable reference to the item stored at the given index of `Ribbon` if item
/// exists. Returns None otherwise, or if index out of bounds.
///
/// # Example
///
/// ```rust
/// use ribbon::{Ribbon, Tape};
///
/// let mut tape = Tape::new(0..10);
///
/// tape.expand_n(5);
/// assert_eq!(tape.len(), 5);
/// assert_eq!(tape.peek_at(0), Some(&0));
///
/// if let Some(item) = tape.peek_at_mut(0) { *item = 42; }
///
/// assert_eq!(tape.peek_at(0), Some(&42));
/// assert_eq!(tape.peek_at(3), Some(&3));
/// ```
fn peek_at_mut(&mut self, index: usize) -> Option<&mut T>;

/// Returns the number of items currently found on the `Ribbon`.
///
/// # Example
Expand Down
12 changes: 12 additions & 0 deletions src/tape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ where
self.tape.front()
}

fn peek_front_mut(&mut self) -> Option<&mut I::Item> {
self.tape.front_mut()
}

fn pop_back(&mut self) -> Option<I::Item> {
self.tape.pop_back()
}
Expand All @@ -72,10 +76,18 @@ where
self.tape.back()
}

fn peek_back_mut(&mut self) -> Option<&mut I::Item> {
self.tape.back_mut()
}

fn peek_at(&self, index: usize) -> Option<&I::Item> {
self.tape.get(index)
}

fn peek_at_mut(&mut self, index: usize) -> Option<&mut I::Item> {
self.tape.get_mut(index)
}

fn len(&self) -> usize {
self.tape.len()
}
Expand Down

0 comments on commit 93d664a

Please sign in to comment.