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