1//! Mock version of std::fs::File;
2use mockall::mock;
3
4use crate::sync::oneshot;
5use 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
16mock! {
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 sync_all(&self) -> io::Result<()>;
34 pub fn sync_data(&self) -> io::Result<()>;
35 pub fn try_clone(&self) -> io::Result<Self>;
36 }
37 #[cfg(windows)]
38 impl std::os::windows::io::AsRawHandle for File {
39 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle;
40 }
41 #[cfg(windows)]
42 impl std::os::windows::io::FromRawHandle for File {
43 unsafe fn from_raw_handle(h: std::os::windows::io::RawHandle) -> Self;
44 }
45 #[cfg(unix)]
46 impl std::os::unix::io::AsRawFd for File {
47 fn as_raw_fd(&self) -> std::os::unix::io::RawFd;
48 }
49
50 #[cfg(unix)]
51 impl std::os::unix::io::FromRawFd for File {
52 unsafe fn from_raw_fd(h: std::os::unix::io::RawFd) -> Self;
53 }
54}
55
56impl Read for MockFile {
57 fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
58 self.inner_read(dst)
59 }
60}
61
62impl Read for &'_ MockFile {
63 fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
64 self.inner_read(dst)
65 }
66}
67
68impl Seek for &'_ MockFile {
69 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
70 self.inner_seek(pos)
71 }
72}
73
74impl Write for &'_ MockFile {
75 fn write(&mut self, src: &[u8]) -> io::Result<usize> {
76 self.inner_write(src)
77 }
78
79 fn flush(&mut self) -> io::Result<()> {
80 self.inner_flush()
81 }
82}
83
84tokio_thread_local! {
85 static QUEUE: RefCell<VecDeque<Box<dyn FnOnce() + Send>>> = RefCell::new(VecDeque::new())
86}
87
88#[derive(Debug)]
89pub(super) struct JoinHandle<T> {
90 rx: oneshot::Receiver<T>,
91}
92
93pub(super) fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
94where
95 F: FnOnce() -> R + Send + 'static,
96 R: Send + 'static,
97{
98 let (tx, rx) = oneshot::channel();
99 let task = Box::new(move || {
100 let _ = tx.send(f());
101 });
102
103 QUEUE.with(|cell| cell.borrow_mut().push_back(task));
104
105 JoinHandle { rx }
106}
107
108pub(super) fn spawn_mandatory_blocking<F, R>(f: F) -> Option<JoinHandle<R>>
109where
110 F: FnOnce() -> R + Send + 'static,
111 R: Send + 'static,
112{
113 let (tx, rx) = oneshot::channel();
114 let task = Box::new(move || {
115 let _ = tx.send(f());
116 });
117
118 QUEUE.with(|cell| cell.borrow_mut().push_back(task));
119
120 Some(JoinHandle { rx })
121}
122
123impl<T> Future for JoinHandle<T> {
124 type Output = Result<T, io::Error>;
125
126 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
127 use std::task::Poll;
128
129 match Pin::new(&mut self.rx).poll(cx) {
130 Poll::Ready(Ok(v)) => Poll::Ready(Ok(v)),
131 Poll::Ready(Err(e)) => panic!("error = {:?}", e),
132 Poll::Pending => Poll::Pending,
133 }
134 }
135}
136
137pub(super) mod pool {
138 use super::*;
139
140 pub(in super::super) fn len() -> usize {
141 QUEUE.with(|cell| cell.borrow().len())
142 }
143
144 pub(in super::super) fn run_one() {
145 let task = QUEUE
146 .with(|cell| cell.borrow_mut().pop_front())
147 .expect("expected task to run, but none ready");
148
149 task();
150 }
151}
152