1 use std::collections::VecDeque;
2 use std::io::IoSlice;
3 
4 use bytes::{Buf, BufMut, Bytes, BytesMut};
5 
6 pub(crate) struct BufList<T> {
7     bufs: VecDeque<T>,
8 }
9 
10 impl<T: Buf> BufList<T> {
new() -> BufList<T>11     pub(crate) fn new() -> BufList<T> {
12         BufList {
13             bufs: VecDeque::new(),
14         }
15     }
16 
17     #[inline]
push(&mut self, buf: T)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")]
bufs_cnt(&self) -> usize25     pub(crate) fn bufs_cnt(&self) -> usize {
26         self.bufs.len()
27     }
28 }
29 
30 impl<T: Buf> Buf for BufList<T> {
31     #[inline]
remaining(&self) -> usize32     fn remaining(&self) -> usize {
33         self.bufs.iter().map(|buf| buf.remaining()).sum()
34     }
35 
36     #[inline]
chunk(&self) -> &[u8]37     fn chunk(&self) -> &[u8] {
38         self.bufs.front().map(Buf::chunk).unwrap_or_default()
39     }
40 
41     #[inline]
advance(&mut self, mut cnt: usize)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]
chunks_vectored<'t>(&'t self, dst: &mut [IoSlice<'t>]) -> usize60     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]
copy_to_bytes(&mut self, len: usize) -> Bytes75     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)]
96 mod tests {
97     use std::ptr;
98 
99     use super::*;
100 
hello_world_buf() -> BufList<Bytes>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]
to_bytes_shorter()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]
to_bytes_eq()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]
to_bytes_longer()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]
one_long_buf_to_bytes()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")]
buf_to_bytes_too_many()148     fn buf_to_bytes_too_many() {
149         hello_world_buf().copy_to_bytes(42);
150     }
151 }
152