1use std::collections::VecDeque;
2use std::io::IoSlice;
3
4use bytes::{Buf, BufMut, Bytes, BytesMut};
5
6pub(crate) struct BufList<T> {
7 bufs: VecDeque<T>,
8}
9
10impl<T: Buf> BufList<T> {
11 pub(crate) fn new() -> BufList<T> {
12 BufList {
13 bufs: VecDeque::new(),
14 }
15 }
16
17 #[inline]
18 pub(crate) fn push(&mut self, buf: T) {
19 debug_assert!(buf.has_remaining());
20 self.bufs.push_back(buf);
21 }
22
23 #[inline]
24 pub(crate) fn bufs_cnt(&self) -> usize {
25 self.bufs.len()
26 }
27}
28
29impl<T: Buf> Buf for BufList<T> {
30 #[inline]
31 fn remaining(&self) -> usize {
32 self.bufs.iter().map(|buf| buf.remaining()).sum()
33 }
34
35 #[inline]
36 fn chunk(&self) -> &[u8] {
37 self.bufs.front().map(Buf::chunk).unwrap_or_default()
38 }
39
40 #[inline]
41 fn advance(&mut self, mut cnt: usize) {
42 while cnt > 0 {
43 {
44 let front = &mut self.bufs[0];
45 let rem = front.remaining();
46 if rem > cnt {
47 front.advance(cnt);
48 return;
49 } else {
50 front.advance(rem);
51 cnt -= rem;
52 }
53 }
54 self.bufs.pop_front();
55 }
56 }
57
58 #[inline]
59 fn chunks_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize {
60 if dst.is_empty() {
61 return 0;
62 }
63 let mut vecs = 0;
64 for buf in &self.bufs {
65 vecs += buf.chunks_vectored(&mut dst[vecs..]);
66 if vecs == dst.len() {
67 break;
68 }
69 }
70 vecs
71 }
72
73 #[inline]
74 fn copy_to_bytes(&mut self, len: usize) -> Bytes {
75 match self.bufs.front_mut() {
78 Some(front) if front.remaining() == len => {
79 let b = front.copy_to_bytes(len);
80 self.bufs.pop_front();
81 b
82 }
83 Some(front) if front.remaining() > len => front.copy_to_bytes(len),
84 _ => {
85 assert!(len <= self.remaining(), "`len` greater than remaining");
86 let mut bm = BytesMut::with_capacity(len);
87 bm.put(self.take(len));
88 bm.freeze()
89 }
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use std::ptr;
97
98 use super::*;
99
100 fn hello_world_buf() -> BufList<Bytes> {
101 BufList {
102 bufs: vec![Bytes::from("Hello"), Bytes::from(" "), Bytes::from("World")].into(),
103 }
104 }
105
106 #[test]
107 fn to_bytes_shorter() {
108 let mut bufs = hello_world_buf();
109 let old_ptr = bufs.chunk().as_ptr();
110 let start = bufs.copy_to_bytes(4);
111 assert_eq!(start, "Hell");
112 assert!(ptr::eq(old_ptr, start.as_ptr()));
113 assert_eq!(bufs.chunk(), b"o");
114 assert!(ptr::eq(old_ptr.wrapping_add(4), bufs.chunk().as_ptr()));
115 assert_eq!(bufs.remaining(), 7);
116 }
117
118 #[test]
119 fn to_bytes_eq() {
120 let mut bufs = hello_world_buf();
121 let old_ptr = bufs.chunk().as_ptr();
122 let start = bufs.copy_to_bytes(5);
123 assert_eq!(start, "Hello");
124 assert!(ptr::eq(old_ptr, start.as_ptr()));
125 assert_eq!(bufs.chunk(), b" ");
126 assert_eq!(bufs.remaining(), 6);
127 }
128
129 #[test]
130 fn to_bytes_longer() {
131 let mut bufs = hello_world_buf();
132 let start = bufs.copy_to_bytes(7);
133 assert_eq!(start, "Hello W");
134 assert_eq!(bufs.remaining(), 4);
135 }
136
137 #[test]
138 fn one_long_buf_to_bytes() {
139 let mut buf = BufList::new();
140 buf.push(b"Hello World" as &[_]);
141 assert_eq!(buf.copy_to_bytes(5), "Hello");
142 assert_eq!(buf.chunk(), b" World");
143 }
144
145 #[test]
146 #[should_panic(expected = "`len` greater than remaining")]
147 fn buf_to_bytes_too_many() {
148 hello_world_buf().copy_to_bytes(42);
149 }
150}