| //! Mock version of std::fs::File; |
| use mockall::mock; |
| |
| use crate::sync::oneshot; |
| use std::{ |
| cell::RefCell, |
| collections::VecDeque, |
| fs::{Metadata, Permissions}, |
| future::Future, |
| io::{self, Read, Seek, SeekFrom, Write}, |
| path::PathBuf, |
| pin::Pin, |
| task::{Context, Poll}, |
| }; |
| |
| mock! { |
| #[derive(Debug)] |
| pub File { |
| pub fn create(pb: PathBuf) -> io::Result<Self>; |
| // These inner_ methods exist because std::fs::File has two |
| // implementations for each of these methods: one on "&mut self" and |
| // one on "&&self". Defining both of those in terms of an inner_ method |
| // allows us to specify the expectation the same way, regardless of |
| // which method is used. |
| pub fn inner_flush(&self) -> io::Result<()>; |
| pub fn inner_read(&self, dst: &mut [u8]) -> io::Result<usize>; |
| pub fn inner_seek(&self, pos: SeekFrom) -> io::Result<u64>; |
| pub fn inner_write(&self, src: &[u8]) -> io::Result<usize>; |
| pub fn metadata(&self) -> io::Result<Metadata>; |
| pub fn open(pb: PathBuf) -> io::Result<Self>; |
| pub fn set_len(&self, size: u64) -> io::Result<()>; |
| pub fn set_permissions(&self, _perm: Permissions) -> io::Result<()>; |
| pub fn sync_all(&self) -> io::Result<()>; |
| pub fn sync_data(&self) -> io::Result<()>; |
| pub fn try_clone(&self) -> io::Result<Self>; |
| } |
| #[cfg(windows)] |
| impl std::os::windows::io::AsRawHandle for File { |
| fn as_raw_handle(&self) -> std::os::windows::io::RawHandle; |
| } |
| #[cfg(windows)] |
| impl std::os::windows::io::FromRawHandle for File { |
| unsafe fn from_raw_handle(h: std::os::windows::io::RawHandle) -> Self; |
| } |
| #[cfg(unix)] |
| impl std::os::unix::io::AsRawFd for File { |
| fn as_raw_fd(&self) -> std::os::unix::io::RawFd; |
| } |
| |
| #[cfg(unix)] |
| impl std::os::unix::io::FromRawFd for File { |
| unsafe fn from_raw_fd(h: std::os::unix::io::RawFd) -> Self; |
| } |
| } |
| |
| impl Read for MockFile { |
| fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { |
| self.inner_read(dst) |
| } |
| } |
| |
| impl Read for &'_ MockFile { |
| fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> { |
| self.inner_read(dst) |
| } |
| } |
| |
| impl Seek for &'_ MockFile { |
| fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { |
| self.inner_seek(pos) |
| } |
| } |
| |
| impl Write for &'_ MockFile { |
| fn write(&mut self, src: &[u8]) -> io::Result<usize> { |
| self.inner_write(src) |
| } |
| |
| fn flush(&mut self) -> io::Result<()> { |
| self.inner_flush() |
| } |
| } |
| |
| tokio_thread_local! { |
| static QUEUE: RefCell<VecDeque<Box<dyn FnOnce() + Send>>> = RefCell::new(VecDeque::new()) |
| } |
| |
| #[derive(Debug)] |
| pub(super) struct JoinHandle<T> { |
| rx: oneshot::Receiver<T>, |
| } |
| |
| pub(super) fn spawn_blocking<F, R>(f: F) -> JoinHandle<R> |
| where |
| F: FnOnce() -> R + Send + 'static, |
| R: Send + 'static, |
| { |
| let (tx, rx) = oneshot::channel(); |
| let task = Box::new(move || { |
| let _ = tx.send(f()); |
| }); |
| |
| QUEUE.with(|cell| cell.borrow_mut().push_back(task)); |
| |
| JoinHandle { rx } |
| } |
| |
| pub(super) fn spawn_mandatory_blocking<F, R>(f: F) -> Option<JoinHandle<R>> |
| where |
| F: FnOnce() -> R + Send + 'static, |
| R: Send + 'static, |
| { |
| let (tx, rx) = oneshot::channel(); |
| let task = Box::new(move || { |
| let _ = tx.send(f()); |
| }); |
| |
| QUEUE.with(|cell| cell.borrow_mut().push_back(task)); |
| |
| Some(JoinHandle { rx }) |
| } |
| |
| impl<T> Future for JoinHandle<T> { |
| type Output = Result<T, io::Error>; |
| |
| fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| use std::task::Poll::*; |
| |
| match Pin::new(&mut self.rx).poll(cx) { |
| Ready(Ok(v)) => Ready(Ok(v)), |
| Ready(Err(e)) => panic!("error = {:?}", e), |
| Pending => Pending, |
| } |
| } |
| } |
| |
| pub(super) mod pool { |
| use super::*; |
| |
| pub(in super::super) fn len() -> usize { |
| QUEUE.with(|cell| cell.borrow().len()) |
| } |
| |
| pub(in super::super) fn run_one() { |
| let task = QUEUE |
| .with(|cell| cell.borrow_mut().pop_front()) |
| .expect("expected task to run, but none ready"); |
| |
| task(); |
| } |
| } |