1 //! Mock version of std::fs::File;
2 use mockall::mock;
3
4 use crate::sync::oneshot;
5 use std::{
6 cell::RefCell,
7 collections::VecDeque,
8 fs::{Metadata, Permissions},
9 future::Future,
10 io::{self, Read, Seek, SeekFrom, Write},
11 path::PathBuf,
12 pin::Pin,
13 task::{Context, Poll},
14 };
15
16 mock! {
17 #[derive(Debug)]
18 pub File {
19 pub fn create(pb: PathBuf) -> io::Result<Self>;
20 // These inner_ methods exist because std::fs::File has two
21 // implementations for each of these methods: one on "&mut self" and
22 // one on "&&self". Defining both of those in terms of an inner_ method
23 // allows us to specify the expectation the same way, regardless of
24 // which method is used.
25 pub fn inner_flush(&self) -> io::Result<()>;
26 pub fn inner_read(&self, dst: &mut [u8]) -> io::Result<usize>;
27 pub fn inner_seek(&self, pos: SeekFrom) -> io::Result<u64>;
28 pub fn inner_write(&self, src: &[u8]) -> io::Result<usize>;
29 pub fn metadata(&self) -> io::Result<Metadata>;
30 pub fn open(pb: PathBuf) -> io::Result<Self>;
31 pub fn set_len(&self, size: u64) -> io::Result<()>;
32 pub fn set_permissions(&self, _perm: Permissions) -> io::Result<()>;
33 pub fn set_max_buf_size(&self, max_buf_size: usize);
34 pub fn sync_all(&self) -> io::Result<()>;
35 pub fn sync_data(&self) -> io::Result<()>;
36 pub fn try_clone(&self) -> io::Result<Self>;
37 }
38 #[cfg(windows)]
39 impl std::os::windows::io::AsRawHandle for File {
40 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle;
41 }
42 #[cfg(windows)]
43 impl std::os::windows::io::FromRawHandle for File {
44 unsafe fn from_raw_handle(h: std::os::windows::io::RawHandle) -> Self;
45 }
46 #[cfg(unix)]
47 impl std::os::unix::io::AsRawFd for File {
48 fn as_raw_fd(&self) -> std::os::unix::io::RawFd;
49 }
50
51 #[cfg(unix)]
52 impl std::os::unix::io::FromRawFd for File {
53 unsafe fn from_raw_fd(h: std::os::unix::io::RawFd) -> Self;
54 }
55 }
56
57 impl Read for MockFile {
read(&mut self, dst: &mut [u8]) -> io::Result<usize>58 fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
59 self.inner_read(dst)
60 }
61 }
62
63 impl Read for &'_ MockFile {
read(&mut self, dst: &mut [u8]) -> io::Result<usize>64 fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
65 self.inner_read(dst)
66 }
67 }
68
69 impl Seek for &'_ MockFile {
seek(&mut self, pos: SeekFrom) -> io::Result<u64>70 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
71 self.inner_seek(pos)
72 }
73 }
74
75 impl Write for &'_ MockFile {
write(&mut self, src: &[u8]) -> io::Result<usize>76 fn write(&mut self, src: &[u8]) -> io::Result<usize> {
77 self.inner_write(src)
78 }
79
flush(&mut self) -> io::Result<()>80 fn flush(&mut self) -> io::Result<()> {
81 self.inner_flush()
82 }
83 }
84
85 tokio_thread_local! {
86 static QUEUE: RefCell<VecDeque<Box<dyn FnOnce() + Send>>> = RefCell::new(VecDeque::new())
87 }
88
89 #[derive(Debug)]
90 pub(super) struct JoinHandle<T> {
91 rx: oneshot::Receiver<T>,
92 }
93
spawn_blocking<F, R>(f: F) -> JoinHandle<R> where F: FnOnce() -> R + Send + 'static, R: Send + 'static,94 pub(super) fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
95 where
96 F: FnOnce() -> R + Send + 'static,
97 R: Send + 'static,
98 {
99 let (tx, rx) = oneshot::channel();
100 let task = Box::new(move || {
101 let _ = tx.send(f());
102 });
103
104 QUEUE.with(|cell| cell.borrow_mut().push_back(task));
105
106 JoinHandle { rx }
107 }
108
spawn_mandatory_blocking<F, R>(f: F) -> Option<JoinHandle<R>> where F: FnOnce() -> R + Send + 'static, R: Send + 'static,109 pub(super) fn spawn_mandatory_blocking<F, R>(f: F) -> Option<JoinHandle<R>>
110 where
111 F: FnOnce() -> R + Send + 'static,
112 R: Send + 'static,
113 {
114 let (tx, rx) = oneshot::channel();
115 let task = Box::new(move || {
116 let _ = tx.send(f());
117 });
118
119 QUEUE.with(|cell| cell.borrow_mut().push_back(task));
120
121 Some(JoinHandle { rx })
122 }
123
124 impl<T> Future for JoinHandle<T> {
125 type Output = Result<T, io::Error>;
126
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>127 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
128 use std::task::Poll;
129
130 match Pin::new(&mut self.rx).poll(cx) {
131 Poll::Ready(Ok(v)) => Poll::Ready(Ok(v)),
132 Poll::Ready(Err(e)) => panic!("error = {e:?}"),
133 Poll::Pending => Poll::Pending,
134 }
135 }
136 }
137
138 pub(super) mod pool {
139 use super::*;
140
len() -> usize141 pub(in super::super) fn len() -> usize {
142 QUEUE.with(|cell| cell.borrow().len())
143 }
144
run_one()145 pub(in super::super) fn run_one() {
146 let task = QUEUE
147 .with(|cell| cell.borrow_mut().pop_front())
148 .expect("expected task to run, but none ready");
149
150 task();
151 }
152 }
153