1use crate::config::{FileServeConfig, FsTaskSpawner};
2use crate::file::ChunkedReadFile;
3
4use std::io;
5use core::{mem, task, future};
6use core::pin::Pin;
7
8pub enum Body<W: FsTaskSpawner, C: FileServeConfig> {
10 Full(bytes::Bytes),
12 Chunked(ChunkedReadFile<W, C>)
14}
15
16impl<W: FsTaskSpawner, C: FileServeConfig> Body<W, C> {
17 #[inline(always)]
18 pub const fn empty() -> Self {
20 Self::Full(bytes::Bytes::new())
21 }
22
23 pub fn poll_next(self: Pin<&mut Self>, ctx: &mut task::Context<'_>) -> task::Poll<Option<Result<bytes::Bytes, io::Error>>> {
25 match self.get_mut() {
26 Self::Full(bytes) => {
27 if bytes.is_empty() {
28 task::Poll::Ready(None)
29 } else {
30 let mut result = bytes::Bytes::new();
31 mem::swap(&mut result, bytes);
32 task::Poll::Ready(Some(Ok(result)))
33 }
34 },
35 Self::Chunked(chunked) => match future::Future::poll(Pin::new(chunked), ctx) {
36 task::Poll::Pending => task::Poll::Pending,
37 task::Poll::Ready(Ok(Some(result))) => {
38 task::Poll::Ready(Some(Ok(result)))
39 }
40 task::Poll::Ready(Ok(None)) => task::Poll::Ready(None),
41 task::Poll::Ready(Err(error)) => task::Poll::Ready(Some(Err(error))),
42 }
43 }
44 }
45
46 #[inline(always)]
47 pub fn is_finished(&self) -> bool {
49 match self {
50 Self::Full(bytes) => bytes.is_empty(),
51 Self::Chunked(chunked) => chunked.is_finished(),
52 }
53 }
54
55 #[inline(always)]
56 pub fn len(&self) -> u64 {
58 match self {
59 Self::Full(bytes) => bytes.len() as u64,
60 Self::Chunked(chunked) => chunked.remaining()
61 }
62 }
63}
64
65impl<W: FsTaskSpawner, C: FileServeConfig> From<bytes::Bytes> for Body<W, C> {
66 #[inline(always)]
67 fn from(bytes: bytes::Bytes) -> Self {
68 Body::Full(bytes)
69 }
70}
71
72impl<W: FsTaskSpawner, C: FileServeConfig> From<ChunkedReadFile<W, C>> for Body<W, C> {
73 #[inline(always)]
74 fn from(chunked: ChunkedReadFile<W, C>) -> Self {
75 Body::Chunked(chunked)
76 }
77}
78
79impl<W: FsTaskSpawner, C: FileServeConfig> From<Option<ChunkedReadFile<W, C>>> for Body<W, C> {
80 #[inline(always)]
81 fn from(chunked: Option<ChunkedReadFile<W, C>>) -> Self {
82 match chunked {
83 Some(chunked) => chunked.into(),
84 None => Self::empty()
85 }
86 }
87}