1use core::{cell::Cell, ops::{Deref, DerefMut}};
2
3use crate::{Buffer, BufferError};
4
5pub trait BufferWriter: DerefMut<Target = [u8]> {
6 fn commit(&self, n: usize) -> Result<(), BufferError>;
7
8 fn write(&mut self, buf: &[u8]) -> Result<(), BufferError>;
9
10 fn remaining_capacity(&self) -> usize;
11}
12
13pub struct Write<'a, T: AsMut<[u8]> + AsRef<[u8]>> {
14 buffer: &'a mut Buffer<T>,
15 bytes_written: Cell<usize>
16}
17
18impl <'a, T: AsMut<[u8]> + AsRef<[u8]>> Write<'a, T> {
19 pub(crate) fn new(buffer: &'a mut Buffer<T>) -> Self {
20 Self {
21 buffer,
22 bytes_written: Cell::new(0)
23 }
24 }
25}
26
27impl <'a, T: AsMut<[u8]> + AsRef<[u8]>> BufferWriter for Write<'a, T> {
28
29 fn commit(&self, n: usize) -> Result<(), BufferError> {
30 if self.remaining_capacity() < n {
31 Err(BufferError::NoCapacity)
32 } else {
33 self.bytes_written.set(
34 self.bytes_written.get() + n
35 );
36 Ok(())
37 }
38 }
39
40 fn write(&mut self, buf: &[u8]) -> Result<(), BufferError> {
41 self.buffer.push(buf)
42 }
43
44 fn remaining_capacity(&self) -> usize {
45 self.buffer.capacity() - self.buffer.write_position - self.bytes_written.get()
46 }
47}
48
49impl <'a, T: AsMut<[u8]> + AsRef<[u8]>> Drop for Write<'a, T> {
50 fn drop(&mut self) {
51
52 self.buffer.write_position += self.bytes_written.get();
53 if self.buffer.write_position > self.buffer.source.as_ref().len() {
54 panic!("illegal state: Write<'a, T> committed more bytes than available!")
55 }
56
57 }
58}
59
60impl <'a, T: AsMut<[u8]> + AsRef<[u8]>> Deref for Write<'a, T>{
61 type Target = [u8];
62
63 fn deref(&self) -> &Self::Target {
64 let tgt = self.buffer.source.as_ref();
65 let offset = self.buffer.write_position + self.bytes_written.get();
66 &tgt[offset..]
67 }
68}
69
70impl <'a, T: AsMut<[u8]> + AsRef<[u8]>> DerefMut for Write<'a, T>{
71 fn deref_mut(&mut self) -> &mut Self::Target {
72 let tgt = self.buffer.source.as_mut();
73 let offset = self.buffer.write_position + self.bytes_written.get();
74 &mut tgt[offset..]
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use crate::{Buffer, BufferWriter, ReadWrite};
81
82
83 #[test]
84 fn test_write() {
85 let mut b = [0u8; 8];
86 let mut buf = Buffer::new(&mut b);
87
88 buf.write_base(&[1, 2]).unwrap();
89
90
91 let mut write = buf.create_writer();
92 write[0] = 3;
93 write[1] = 4;
94
95 write.commit(2).unwrap();
96 drop(write);
97
98 assert_eq!(buf.data(), &[1, 2, 3, 4]);
99 }
100
101 #[test]
102 fn test_multi_write() {
103 let mut b = [0u8; 8];
104 let mut buf = Buffer::new(&mut b);
105
106 let mut write = buf.create_writer();
107 write[0] = 1;
108 write[1] = 2;
109 write.commit(2).unwrap();
110 drop(write);
111
112 let mut write = buf.create_writer();
113 write[0] = 3;
114 write[1] = 4;
115 write.commit(2).unwrap();
116 drop(write);
117
118 assert_eq!(buf.data(), &[1, 2, 3, 4]);
119 assert_eq!(buf.write_position, 4);
120 }
121
122}