1use {
2 bytes::{Buf, Bytes, BytesMut},
3 futures_lite::prelude::*,
4 std::{
5 convert::Infallible,
6 future,
7 io::{Cursor, Error, ErrorKind},
8 marker::PhantomData,
9 mem,
10 ops::DerefMut,
11 pin::Pin,
12 task::{Context, Poll},
13 },
14};
15
16#[cfg(feature = "rtn")]
17pub use crate::body_rtn::{SendBody, SendBodyExt};
18
19pub trait Body {
21 type Chunk: Buf;
23
24 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>>;
31
32 fn size_hint(&self) -> Hint;
34}
35
36#[derive(Clone, Copy, Debug)]
40pub enum Hint {
41 Empty,
43
44 Full {
50 len: Option<u64>,
54 },
55
56 Chunked {
62 end: bool,
64 },
65}
66
67impl Hint {
68 #[inline]
70 pub fn is_empty(self) -> bool {
71 matches!(self, Self::Empty)
72 }
73
74 #[inline]
76 pub fn is_full(self) -> bool {
77 matches!(self, Self::Full { .. })
78 }
79
80 #[inline]
82 pub fn is_chunked(self) -> bool {
83 matches!(self, Self::Chunked { .. })
84 }
85
86 #[inline]
88 pub fn end(self) -> bool {
89 match self {
90 Self::Empty => true,
91 Self::Full { len } => len == Some(0),
92 Self::Chunked { end } => end,
93 }
94 }
95
96 #[inline]
98 pub fn size(self) -> Option<u64> {
99 match self {
100 Self::Empty => Some(0),
101 Self::Full { len } => len,
102 Self::Chunked { end } => {
103 if end {
104 Some(0)
105 } else {
106 None
107 }
108 }
109 }
110 }
111}
112
113pub enum Void {}
115
116impl Buf for Void {
117 #[inline]
118 fn remaining(&self) -> usize {
119 match *self {}
120 }
121
122 #[inline]
123 fn chunk(&self) -> &[u8] {
124 match *self {}
125 }
126
127 #[inline]
128 fn advance(&mut self, _: usize) {
129 match *self {}
130 }
131}
132
133impl<B> Body for &mut B
134where
135 B: Body,
136{
137 type Chunk = B::Chunk;
138
139 #[inline]
140 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
141 (**self).chunk().await
142 }
143
144 #[inline]
145 fn size_hint(&self) -> Hint {
146 (**self).size_hint()
147 }
148}
149
150impl Body for () {
151 type Chunk = Void;
152
153 #[inline]
154 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
155 None
156 }
157
158 #[inline]
159 fn size_hint(&self) -> Hint {
160 Hint::Empty
161 }
162}
163
164impl<'slice> Body for &'slice [u8] {
165 type Chunk = &'slice [u8];
166
167 #[inline]
168 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
169 if self.is_empty() {
170 None
171 } else {
172 Some(Ok(mem::take(self)))
173 }
174 }
175
176 #[inline]
177 fn size_hint(&self) -> Hint {
178 Hint::Full {
179 len: Some(self.len() as u64),
180 }
181 }
182}
183
184impl<'str> Body for &'str str {
185 type Chunk = &'str [u8];
186
187 #[inline]
188 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
189 if self.is_empty() {
190 None
191 } else {
192 let s = mem::take(self);
193 Some(Ok(s.as_bytes()))
194 }
195 }
196
197 #[inline]
198 fn size_hint(&self) -> Hint {
199 Hint::Full {
200 len: Some(self.len() as u64),
201 }
202 }
203}
204
205impl Body for String {
206 type Chunk = Cursor<Self>;
207
208 #[inline]
209 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
210 if self.is_empty() {
211 None
212 } else {
213 let s = mem::take(self);
214 Some(Ok(Cursor::new(s)))
215 }
216 }
217
218 #[inline]
219 fn size_hint(&self) -> Hint {
220 Hint::Full {
221 len: Some(self.len() as u64),
222 }
223 }
224}
225
226impl Body for Vec<u8> {
227 type Chunk = Cursor<Self>;
228
229 #[inline]
230 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
231 if self.is_empty() {
232 None
233 } else {
234 let s = mem::take(self);
235 Some(Ok(Cursor::new(s)))
236 }
237 }
238
239 #[inline]
240 fn size_hint(&self) -> Hint {
241 Hint::Full {
242 len: Some(self.len() as u64),
243 }
244 }
245}
246
247impl<B> Body for Option<B>
248where
249 B: Body,
250{
251 type Chunk = B::Chunk;
252
253 #[inline]
254 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
255 match self {
256 Some(body) => body.chunk().await,
257 None => None,
258 }
259 }
260
261 #[inline]
262 fn size_hint(&self) -> Hint {
263 match self {
264 Some(body) => body.size_hint(),
265 None => Hint::Empty,
266 }
267 }
268}
269
270impl Body for Infallible {
271 type Chunk = Void;
272
273 #[inline]
274 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
275 match *self {}
276 }
277
278 #[inline]
279 fn size_hint(&self) -> Hint {
280 match *self {}
281 }
282}
283
284impl Body for Bytes {
285 type Chunk = Self;
286
287 #[inline]
288 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
289 if self.is_empty() {
290 None
291 } else {
292 let s = mem::take(self);
293 Some(Ok(s))
294 }
295 }
296
297 #[inline]
298 fn size_hint(&self) -> Hint {
299 Hint::Full {
300 len: Some(self.len() as u64),
301 }
302 }
303}
304
305pub struct Full<B>(Option<B>);
323
324impl<B> Full<B> {
325 #[inline]
327 pub const fn new(body: B) -> Self {
328 Self(Some(body))
329 }
330}
331
332impl<B> Body for Full<B>
333where
334 B: Buf,
335{
336 type Chunk = B;
337
338 #[inline]
339 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
340 self.0.take().map(Ok)
341 }
342
343 #[inline]
344 fn size_hint(&self) -> Hint {
345 Hint::Full {
346 len: Some(
347 self.0
348 .as_ref()
349 .map(|b| b.remaining() as u64)
350 .unwrap_or_default(),
351 ),
352 }
353 }
354}
355
356pub struct Deferred<F>(Option<F>);
377
378impl<F> Deferred<F> {
379 #[inline]
380 pub fn new<U>(fu: U) -> Self
381 where
382 U: IntoFuture<IntoFuture = F>,
383 {
384 Self(Some(fu.into_future()))
385 }
386}
387
388impl<F, I> Body for Deferred<F>
389where
390 F: Future<Output = Result<I, Error>> + Unpin,
391 I: Buf,
392{
393 type Chunk = I;
394
395 #[inline]
396 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
397 match &mut self.0 {
398 Some(fu) => {
399 let mut fu = Pin::new(fu);
400 let res = future::poll_fn(|cx| fu.as_mut().poll(cx)).await;
401 self.0 = None;
402 Some(res)
403 }
404 None => None,
405 }
406 }
407
408 #[inline]
409 fn size_hint(&self) -> Hint {
410 Hint::Full {
411 len: if self.0.is_none() { Some(0) } else { None },
412 }
413 }
414}
415
416pub struct Chunked<S>(pub S);
446
447impl<S, I> Body for Chunked<S>
448where
449 S: Stream<Item = Result<I, Error>> + Unpin,
450 I: Buf,
451{
452 type Chunk = I;
453
454 #[inline]
455 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
456 self.0.next().await
457 }
458
459 #[inline]
460 fn size_hint(&self) -> Hint {
461 let (_, upper_bound) = self.0.size_hint();
462 Hint::Chunked {
463 end: upper_bound == Some(0),
464 }
465 }
466}
467
468pub trait IntoBody: Sized {
470 type Chunk: Buf;
471 type Body: Body<Chunk = Self::Chunk>;
472
473 fn into_body(self) -> Self::Body;
474}
475
476impl<B> IntoBody for B
477where
478 B: Body,
479{
480 type Chunk = B::Chunk;
481 type Body = Self;
482
483 #[inline]
484 fn into_body(self) -> Self::Body {
485 self
486 }
487}
488
489pub trait PollBody {
554 type Chunk: Buf;
555
556 fn poll_chunk(
557 self: Pin<&mut Self>,
558 cx: &mut Context<'_>,
559 ) -> Poll<Option<Result<Self::Chunk, Error>>>;
560
561 fn size_hint(&self) -> Hint;
562}
563
564impl<P> Body for Pin<P>
565where
566 P: DerefMut<Target: PollBody>,
567{
568 type Chunk = <P::Target as PollBody>::Chunk;
569
570 #[inline]
571 async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
572 future::poll_fn(|cx| self.as_mut().poll_chunk(cx)).await
573 }
574
575 #[inline]
576 fn size_hint(&self) -> Hint {
577 self.as_ref().size_hint()
578 }
579}
580
581pub type BoxedLocal<'body, C = Bytes> = Pin<Box<dyn PollBody<Chunk = C> + 'body>>;
583
584impl<'body, C> Default for BoxedLocal<'body, C>
585where
586 C: Buf + 'body,
587{
588 fn default() -> Self {
589 Box::pin(empty())
590 }
591}
592
593pub type Boxed<'body, C = Bytes> = Pin<Box<dyn PollBody<Chunk = C> + Send + 'body>>;
595
596impl<'body, C> Default for Boxed<'body, C>
597where
598 C: Buf + Send + 'body,
599{
600 fn default() -> Self {
601 Box::pin(empty())
602 }
603}
604
605fn empty<C>() -> impl PollBody<Chunk = C>
606where
607 C: Buf,
608{
609 struct Empty<C>(PhantomData<C>);
610
611 impl<C> PollBody for Empty<C>
612 where
613 C: Buf,
614 {
615 type Chunk = C;
616
617 fn poll_chunk(
618 self: Pin<&mut Self>,
619 _: &mut Context<'_>,
620 ) -> Poll<Option<Result<Self::Chunk, Error>>> {
621 Poll::Ready(None)
622 }
623
624 fn size_hint(&self) -> Hint {
625 Hint::Empty
626 }
627 }
628
629 Empty(PhantomData)
630}
631
632pub trait BodyExt: IntoBody {
634 #[inline]
635 async fn take_full(self) -> Result<Option<Self::Chunk>, Error> {
636 let mut body = self.into_body();
637 let size = body.size_hint();
638
639 assert!(
640 matches!(size, Hint::Full { .. }),
641 "the body size must be full",
642 );
643
644 let chunk = body.chunk().await;
645
646 match &chunk {
647 Some(Ok(chunk)) => {
648 debug_assert!(
649 !size.end() || !chunk.has_remaining(),
650 "an empty body shouldn't have remaining chunks",
651 );
652 }
653 Some(Err(_)) => {}
654 None => debug_assert!(size.end(), "the body must be empty"),
655 }
656
657 debug_assert!(body.size_hint().end(), "the body must ends after the chunk");
658
659 chunk.transpose()
660 }
661
662 #[inline]
663 async fn text(self) -> Result<String, Error> {
664 let mut body = self.into_body();
665 let cap = body.size_hint().size().unwrap_or(1024);
666 let mut s = String::with_capacity(cap as usize);
667 while let Some(res) = body.chunk().await {
668 match str::from_utf8(res?.chunk()) {
669 Ok(chunk) => s.push_str(chunk),
670 Err(_) => {
671 return Err(Error::new(
672 ErrorKind::InvalidData,
673 "stream did not contain valid UTF-8",
674 ));
675 }
676 }
677 }
678
679 Ok(s)
680 }
681
682 #[inline]
683 async fn vec(self) -> Result<Vec<u8>, Error> {
684 let mut body = self.into_body();
685 let cap = body.size_hint().size().unwrap_or(1024);
686 let mut v = Vec::with_capacity(cap as usize);
687 while let Some(res) = body.chunk().await {
688 v.extend_from_slice(res?.chunk());
689 }
690
691 Ok(v)
692 }
693
694 #[inline]
695 async fn bytes(self) -> Result<Bytes, Error>
696 where
697 Self::Chunk: Into<Bytes>,
698 {
699 let bytes_mut = self.bytes_mut().await?;
700 Ok(bytes_mut.freeze())
701 }
702
703 #[inline]
704 async fn bytes_mut(self) -> Result<BytesMut, Error>
705 where
706 Self::Chunk: Into<Bytes>,
707 {
708 let mut out = BytesMut::new();
709 let mut body = self.into_body();
710 while let Some(res) = body.chunk().await {
711 match res?.into().try_into_mut() {
712 Ok(bytes_mut) => out.unsplit(bytes_mut),
713 Err(bytes) => out.extend_from_slice(&bytes),
714 }
715 }
716
717 Ok(out)
718 }
719
720 #[inline]
721 fn read(self) -> impl AsyncRead {
722 Reader {
723 body: self.into_poll_body(),
724 state: State::Start,
725 }
726 }
727
728 #[inline]
729 fn stream(self) -> impl Stream<Item = Result<Self::Chunk, Error>> {
730 Streamer {
731 body: self.into_poll_body(),
732 }
733 }
734
735 #[inline]
736 fn into_poll_body(self) -> impl PollBody<Chunk = Self::Chunk> {
737 unfold(self.into_body(), |mut body| async {
738 match body.chunk().await {
739 Some(res) => Step::Next { body, res },
740 None => Step::End(body),
741 }
742 })
743 }
744
745 #[inline]
746 fn boxed_local<'body>(self) -> BoxedLocal<'body, Self::Chunk>
747 where
748 Self: 'body,
749 {
750 Box::pin(self.into_poll_body())
751 }
752}
753
754impl<B> BodyExt for B where B: IntoBody {}
755
756enum Step<B, C> {
757 Next { body: B, res: Result<C, Error> },
758 End(B),
759}
760
761#[inline]
762fn unfold<B, F, U>(body: B, f: F) -> Unfold<B, F, U>
763where
764 B: Body,
765 F: FnMut(B) -> U,
766 U: Future<Output = Step<B, B::Chunk>>,
767{
768 Unfold {
769 body: Some(body),
770 f,
771 fu: None,
772 }
773}
774
775pin_project_lite::pin_project! {
776 struct Unfold<B, F, U> {
777 body: Option<B>,
778 f: F,
779 #[pin]
780 fu: Option<U>,
781 }
782}
783
784impl<B, F, U> PollBody for Unfold<B, F, U>
785where
786 B: Body,
787 F: FnMut(B) -> U,
788 U: Future<Output = Step<B, B::Chunk>>,
789{
790 type Chunk = B::Chunk;
791
792 #[inline]
793 fn poll_chunk(
794 self: Pin<&mut Self>,
795 cx: &mut Context<'_>,
796 ) -> Poll<Option<Result<Self::Chunk, Error>>> {
797 let mut me = self.project();
798 if let Some(body) = me.body.take() {
799 me.fu.set(Some((me.f)(body)));
800 }
801
802 let fu = me.fu.as_pin_mut().expect("future should always be here");
803
804 match fu.poll(cx) {
805 Poll::Ready(Step::Next { body, res }) => {
806 *me.body = Some(body);
807 Poll::Ready(Some(res))
808 }
809 Poll::Ready(Step::End(body)) => {
810 *me.body = Some(body);
811 Poll::Ready(None)
812 }
813 Poll::Pending => Poll::Pending,
814 }
815 }
816
817 #[inline]
818 fn size_hint(&self) -> Hint {
819 self.body
820 .as_ref()
821 .expect("called before the chunk retrieval was completed")
822 .size_hint()
823 }
824}
825
826pin_project_lite::pin_project! {
827 struct Reader<B, C> {
828 #[pin]
829 body: B,
830 state: State<C>,
831 }
832}
833
834impl<B> AsyncRead for Reader<B, B::Chunk>
835where
836 B: PollBody,
837{
838 #[inline]
839 fn poll_read(
840 self: Pin<&mut Self>,
841 cx: &mut Context<'_>,
842 buf: &mut [u8],
843 ) -> Poll<Result<usize, Error>> {
844 let mut me = self.project();
845
846 if let State::End = me.state {
847 return Poll::Ready(Ok(0));
848 }
849
850 if buf.is_empty() {
851 return Poll::Ready(Ok(0));
852 }
853
854 if !me.state.has_remaining() {
855 loop {
856 match me.body.as_mut().poll_chunk(cx) {
857 Poll::Ready(Some(Ok(c))) => {
858 if c.has_remaining() {
859 *me.state = State::Next(c);
860 break;
861 }
862 }
863 Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(e)),
864 Poll::Ready(None) => {
865 *me.state = State::End;
866 return Poll::Ready(Ok(0));
867 }
868 Poll::Pending => return Poll::Pending,
869 }
870 }
871 }
872
873 let n = usize::min(me.state.remaining(), buf.len());
874 debug_assert_ne!(n, 0, "at least one byte must be read");
875
876 me.state.copy_to_slice(&mut buf[..n]);
877 Poll::Ready(Ok(n))
878 }
879}
880
881enum State<B> {
882 Start,
883 Next(B),
884 End,
885}
886
887impl<B> Buf for State<B>
888where
889 B: Buf,
890{
891 #[inline]
892 fn remaining(&self) -> usize {
893 match self {
894 Self::Next(b) => b.remaining(),
895 Self::Start | Self::End => 0,
896 }
897 }
898
899 #[inline]
900 fn chunk(&self) -> &[u8] {
901 match self {
902 Self::Next(b) => b.chunk(),
903 Self::Start | Self::End => &[],
904 }
905 }
906
907 #[inline]
908 fn advance(&mut self, cnt: usize) {
909 match self {
910 Self::Next(b) => b.advance(cnt),
911 Self::Start | Self::End => debug_assert_eq!(cnt, 0, "can't advance further"),
912 }
913 }
914}
915
916pin_project_lite::pin_project! {
917 struct Streamer<B> {
918 #[pin]
919 body: B,
920 }
921}
922
923impl<B> Stream for Streamer<B>
924where
925 B: PollBody,
926{
927 type Item = Result<B::Chunk, Error>;
928
929 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
930 self.project().body.poll_chunk(cx)
931 }
932}
933
934#[cfg(test)]
935mod tests {
936 use {
937 super::*,
938 futures_lite::{future, stream},
939 std::{io::ErrorKind, pin, slice},
940 };
941
942 #[test]
943 fn slice() {
944 let src = "hi";
945 let actual = future::block_on(src.as_bytes().take_full()).expect("take full body");
946
947 assert_eq!(
948 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
949 src.as_bytes(),
950 );
951 }
952
953 #[test]
954 fn str() {
955 let src = "hi";
956 let actual = future::block_on(src.take_full()).expect("take full body");
957
958 assert_eq!(
959 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
960 src.as_bytes(),
961 );
962 }
963
964 #[test]
965 fn full() {
966 let src = "hi";
967 let full = Full::new(src.as_bytes());
968 let actual = future::block_on(full.take_full()).expect("take full body");
969
970 assert_eq!(
971 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
972 src.as_bytes(),
973 );
974 }
975
976 #[test]
977 fn deferred() {
978 let src = "hi";
979 let deferred = Deferred::new(future::ready(Ok(src.as_bytes())));
980 let actual = future::block_on(deferred.take_full()).expect("take full body");
981
982 assert_eq!(
983 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
984 src.as_bytes(),
985 );
986 }
987
988 #[test]
989 fn chunked() {
990 let src = [Ok("a"), Ok("b"), Err(Error::from(ErrorKind::UnexpectedEof))]
991 .map(|r| r.map(str::as_bytes));
992
993 let n = src.len();
994
995 let mut chunked = Chunked(stream::iter(src));
996 for _ in 0..n {
997 let actual = future::block_on(chunked.chunk());
998 match actual {
999 Some(Ok(a)) => assert!(matches!(a, b"a" | b"b")),
1000 Some(Err(e)) => assert_eq!(e.kind(), ErrorKind::UnexpectedEof),
1001 None => unreachable!(),
1002 }
1003 }
1004 }
1005
1006 #[test]
1007 fn text() {
1008 let src = ["he", "ll", "o"].map(str::as_bytes).map(Ok);
1009 let body = Chunked(stream::iter(src));
1010 let text = future::block_on(body.text()).expect("read body text");
1011 assert_eq!(text, "hello");
1012 }
1013
1014 #[test]
1015 fn vec() {
1016 let src = [1, 2, 3, 4].each_ref().map(slice::from_ref).map(Ok);
1017 let body = Chunked(stream::iter(src));
1018 let vec = future::block_on(body.vec()).expect("read body text");
1019 assert_eq!(vec, [1, 2, 3, 4]);
1020 }
1021
1022 #[test]
1023 fn bytes() {
1024 let src = ["he", "ll", "o"].map(str::as_bytes).map(Ok);
1025 let body = Chunked(stream::iter(src));
1026 let bytes = future::block_on(body.bytes()).expect("read body bytes");
1027 assert_eq!(bytes, "hello");
1028 }
1029
1030 #[test]
1031 fn bytes_mut() {
1032 let src = ["he", "ll", "o"].map(str::as_bytes).map(Ok);
1033 let body = Chunked(stream::iter(src));
1034 let bytes_mut = future::block_on(body.bytes_mut()).expect("read body bytes");
1035 assert_eq!(bytes_mut, "hello");
1036 }
1037
1038 #[test]
1039 fn read() {
1040 let src = ["h", "e", "ll", "o"].map(str::as_bytes).map(Ok);
1041 let body = Chunked(stream::iter(src));
1042 let mut reader = pin::pin!(body.read());
1043
1044 let mut out = String::new();
1045 let res = future::block_on(reader.read_to_string(&mut out));
1046 assert_eq!(res.ok(), Some(5));
1047 assert_eq!(out, "hello");
1048 }
1049
1050 #[test]
1051 fn read_partial() {
1052 let src = ["h", "e", "ll", "o"].map(str::as_bytes).map(Ok);
1053 let body = Chunked(stream::iter(src));
1054 let mut reader = pin::pin!(body.read());
1055
1056 for (size, part) in [
1057 (1, b"h\0"),
1058 (1, b"e\0"),
1059 (2, b"ll"),
1060 (1, b"o\0"),
1061 (0, b"\0\0"),
1062 ] {
1063 let mut buf = [0; 2];
1064 let n = future::block_on(reader.read(&mut buf)).expect("read body part to the buffer");
1065 assert_eq!(n, size);
1066 assert_eq!(&buf, part);
1067 }
1068 }
1069
1070 #[test]
1071 fn into_poll_body() {
1072 let src = "hi";
1073 let body = Full::new(src.as_bytes());
1074 let poll_body = pin::pin!(body.into_poll_body());
1075 let actual = future::block_on(poll_body.take_full()).expect("take full body");
1076
1077 assert_eq!(
1078 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
1079 src.as_bytes(),
1080 );
1081 }
1082
1083 #[test]
1084 fn boxed_local() {
1085 let src = "hi";
1086 let body = Full::new(src.as_bytes());
1087 let boxed_body = body.boxed_local();
1088 let actual = future::block_on(boxed_body.take_full()).expect("take full body");
1089
1090 assert_eq!(
1091 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
1092 src.as_bytes(),
1093 );
1094 }
1095
1096 #[cfg(feature = "rtn")]
1097 #[test]
1098 fn boxed() {
1099 let src = "hi";
1100 let body = Full::new(src.as_bytes());
1101 let boxed_body = body.boxed();
1102 let actual = future::block_on(boxed_body.take_full()).expect("take full body");
1103
1104 assert_eq!(
1105 actual.as_ref().map(Buf::chunk).unwrap_or_default(),
1106 src.as_bytes(),
1107 );
1108 }
1109}