virtual_fs/
static_file.rs1use std::{
2 convert::TryInto,
3 io::{self, Cursor},
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use shared_buffer::OwnedBuffer;
9use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
10
11use crate::{FsError, VirtualFile};
12
13#[derive(Debug, Clone, PartialEq)]
15pub struct StaticFile(Cursor<OwnedBuffer>);
16
17impl StaticFile {
18 pub fn new(bytes: impl Into<OwnedBuffer>) -> Self {
19 StaticFile(Cursor::new(bytes.into()))
20 }
21
22 pub fn contents(&self) -> &OwnedBuffer {
24 self.0.get_ref()
25 }
26}
27
28#[async_trait::async_trait]
29impl VirtualFile for StaticFile {
30 fn last_accessed(&self) -> u64 {
31 0
32 }
33
34 fn last_modified(&self) -> u64 {
35 0
36 }
37
38 fn created_time(&self) -> u64 {
39 0
40 }
41
42 fn size(&self) -> u64 {
43 self.0.get_ref().len().try_into().unwrap()
44 }
45
46 fn set_len(&mut self, _new_size: u64) -> Result<(), FsError> {
47 Err(FsError::PermissionDenied)
48 }
49
50 fn unlink(&mut self) -> Result<(), FsError> {
51 Err(FsError::PermissionDenied)
52 }
53
54 fn poll_read_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
55 let remaining = self.size() - self.0.position();
56 Poll::Ready(Ok(remaining.try_into().unwrap()))
57 }
58
59 fn poll_write_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
60 Poll::Ready(Err(std::io::ErrorKind::PermissionDenied.into()))
61 }
62}
63
64impl AsyncRead for StaticFile {
65 fn poll_read(
66 mut self: Pin<&mut Self>,
67 cx: &mut Context<'_>,
68 buf: &mut tokio::io::ReadBuf<'_>,
69 ) -> Poll<io::Result<()>> {
70 Pin::new(&mut self.0).poll_read(cx, buf)
71 }
72}
73
74impl AsyncWrite for StaticFile {
77 fn poll_write(
78 self: Pin<&mut Self>,
79 _cx: &mut Context<'_>,
80 _buf: &[u8],
81 ) -> Poll<io::Result<usize>> {
82 Poll::Ready(Err(std::io::ErrorKind::PermissionDenied.into()))
83 }
84 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
85 Poll::Ready(Ok(()))
86 }
87 fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
88 Poll::Ready(Ok(()))
89 }
90}
91
92impl AsyncSeek for StaticFile {
93 fn start_seek(mut self: Pin<&mut Self>, pos: io::SeekFrom) -> io::Result<()> {
94 Pin::new(&mut self.0).start_seek(pos)
95 }
96
97 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
98 Pin::new(&mut self.0).poll_complete(cx)
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use tokio::io::AsyncReadExt;
105
106 use super::*;
107
108 #[tokio::test]
109 async fn read_a_static_file_to_end() {
110 let mut file = StaticFile::new(OwnedBuffer::from_static(b"Hello, World!"));
111 let mut buffer = [0; 5];
112
113 let bytes_read = file.read(&mut buffer).await.unwrap();
114 assert_eq!(bytes_read, 5);
115 assert_eq!(&buffer[..bytes_read], b"Hello");
116 assert_eq!(file.0.position(), 5);
117
118 let bytes_read = file.read(&mut buffer).await.unwrap();
119 assert_eq!(bytes_read, 5);
120 assert_eq!(&buffer[..bytes_read], b", Wor");
121 assert_eq!(file.0.position(), 10);
122
123 let bytes_read = file.read(&mut buffer).await.unwrap();
124 assert_eq!(bytes_read, 3);
125 assert_eq!(&buffer[..bytes_read], b"ld!");
126 assert_eq!(file.0.position(), 13);
127
128 let bytes_read = file.read(&mut buffer).await.unwrap();
129 assert_eq!(bytes_read, 0);
130 assert_eq!(&buffer[..bytes_read], b"");
131 assert_eq!(file.0.position(), 13);
132 }
133}