Skip to content

Commit 450ebda

Browse files
authored
Merge pull request #159 from axel-van-abkoude/update-ring-buffer
Update ring buffer exercise
2 parents fcf7d50 + 02029b6 commit 450ebda

1 file changed

Lines changed: 70 additions & 16 deletions

File tree

  • exercises/2-foundations-of-rust/3-advanced-syntax/4-ring-buffer/src

exercises/2-foundations-of-rust/3-advanced-syntax/4-ring-buffer/src/main.rs

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
/// One way to implement a queue is to use a linked list; however, that requires a lot of dynamic memory manipulation to add/remove individual items.
2-
/// A more low-level approach is to use a circular buffer: the compromise is that the capacity of the queue is then "fixed". For a background on circular buffers,
3-
/// you can consult https://en.wikipedia.org/wiki/Circular_buffer
1+
//! One way to implement a queue is to use a linked list; however, that requires a lot of dynamic memory manipulation to add/remove individual items.
2+
//! A more low-level approach is to use a circular buffer: the compromise is that the capacity of the queue is then "fixed". For a background on circular buffers,
3+
//! you can consult https://en.wikipedia.org/wiki/Circular_buffer
44
55
// A partial implementation is provided below; please finish it and add some more methods; please remember to run 'cargo fmt' and 'cargo clippy' after
66
// every step to get feedback from the rust compiler!
@@ -15,19 +15,23 @@
1515
// 4) in a queue that has size N, how many elements can be stored at one time? (test your answer experimentally)
1616

1717
// 5) EXTRA EXERCISES:
18-
// - add a method "has_room" so that "queue.has_room()" is true if and only if writing to the queue will succeed
19-
// - add a method "peek" so that "queue.peek()" returns the same thing as "queue.read()", but leaves the element in the queue
18+
// - implement the method "has_room" so that "queue.has_room()" is true if and only if writing to the queue will succeed
19+
// - implement the method "peek" so that "queue.peek()" returns the same thing as "queue.read()", but leaves the element in the queue
20+
// - eliminate edge cases of the data structure (HINT: what is the behaviour of (n % 0))
21+
// - test your implementation by running 'cargo test'
22+
23+
const RING_SIZE: usize = 16;
2024

2125
struct RingBuffer {
22-
data: [u8; 16],
26+
data: [u8; RING_SIZE],
2327
start: usize,
2428
end: usize,
2529
}
2630

2731
impl RingBuffer {
2832
fn new() -> RingBuffer {
2933
RingBuffer {
30-
data: [0; 16],
34+
data: [0; RING_SIZE],
3135
start: 0,
3236
end: 0,
3337
}
@@ -43,18 +47,25 @@ impl RingBuffer {
4347
/// This function tries to put `value` on the queue; and returns true if this succeeds
4448
/// It returns false if writing to the queue failed (which can happen if there is not enough room)
4549
46-
fn write(&mut self, value: u8) -> bool {
50+
fn write(&mut self, value: u8) -> Result<(), &'static str> {
4751
self.data[self.end] = value;
4852
let pos = (self.end + 1) % self.data.len();
4953
if pos == self.start {
50-
// the buffer can hold no more new data
51-
false
54+
Err("the buffer can hold no more new data")
5255
} else {
5356
self.end = pos;
5457

55-
true
58+
Ok(())
5659
}
5760
}
61+
62+
fn has_room(&mut self) -> bool {
63+
todo!()
64+
}
65+
66+
fn peek(&mut self) -> Option<u8> {
67+
todo!()
68+
}
5869
}
5970

6071
/// This function creates an "owned slice" a user-selectable size by allocating it as a vector (filled with zeros) using vec![], and then turning it
@@ -76,12 +87,55 @@ impl Iterator for RingBuffer {
7687

7788
fn main() {
7889
let mut queue = RingBuffer::new();
79-
assert!(queue.write(1));
80-
assert!(queue.write(2));
81-
assert!(queue.write(3));
82-
assert!(queue.write(4));
83-
assert!(queue.write(5));
90+
assert!(queue.write(1).is_ok());
91+
assert!(queue.write(2).is_ok());
92+
assert!(queue.write(3).is_ok());
93+
assert!(queue.write(4).is_ok());
94+
assert!(queue.write(5).is_ok());
8495
for elem in queue {
8596
println!("{elem}");
8697
}
8798
}
99+
100+
#[cfg(test)]
101+
mod tests {
102+
use super::*;
103+
104+
#[test]
105+
fn test_empty() {
106+
// To make this test pass you will need to edit the write function.
107+
let mut queue = RingBuffer::new(0);
108+
assert!(queue.write(1).is_err());
109+
}
110+
111+
#[test]
112+
fn test_single() {
113+
let mut queue = RingBuffer::new(1);
114+
assert!(queue.write(1).is_err());
115+
}
116+
117+
#[test]
118+
fn test_enough_size() {
119+
let mut queue = RingBuffer::new(3);
120+
assert!(queue.write(1).is_ok());
121+
assert!(queue.has_room());
122+
assert!(queue.write(2).is_ok());
123+
assert!(queue.read() == Some(1));
124+
assert!(queue.write(3).is_ok());
125+
assert!(queue.peek() == Some(2));
126+
assert!(queue.read() == Some(2));
127+
assert!(queue.write(4).is_ok());
128+
}
129+
130+
#[test]
131+
fn test_not_enough_size() {
132+
let mut queue = RingBuffer::new(3);
133+
assert!(queue.write(1).is_ok());
134+
assert!(queue.read() == Some(1));
135+
assert!(queue.write(2).is_ok());
136+
assert!(queue.read() == Some(2));
137+
assert!(queue.write(3).is_ok());
138+
assert!(queue.write(4).is_ok());
139+
assert!(queue.write(5).is_err());
140+
}
141+
}

0 commit comments

Comments
 (0)