http_fs/
body.rs

1use crate::config::{FileServeConfig, FsTaskSpawner};
2use crate::file::ChunkedReadFile;
3
4use std::io;
5use core::{mem, task, future};
6use core::pin::Pin;
7
8///File serving body for `hyper` Service
9pub enum Body<W: FsTaskSpawner, C: FileServeConfig> {
10    ///Full
11    Full(bytes::Bytes),
12    ///Chunked file read
13    Chunked(ChunkedReadFile<W, C>)
14}
15
16impl<W: FsTaskSpawner, C: FileServeConfig> Body<W, C> {
17    #[inline(always)]
18    ///Creates empty body
19    pub const fn empty() -> Self {
20        Self::Full(bytes::Bytes::new())
21    }
22
23    ///Method to fetch next chunk within `Future` interface
24    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    ///Returns whether body is finished to be served.
48    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    ///Remaining length
57    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}