//! 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; // 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; pub fn inner_seek(&self, pos: SeekFrom) -> io::Result; pub fn inner_write(&self, src: &[u8]) -> io::Result; pub fn metadata(&self) -> io::Result; pub fn open(pb: PathBuf) -> io::Result; 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; } #[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 { self.inner_read(dst) } } impl Read for &'_ MockFile { fn read(&mut self, dst: &mut [u8]) -> io::Result { self.inner_read(dst) } } impl Seek for &'_ MockFile { fn seek(&mut self, pos: SeekFrom) -> io::Result { self.inner_seek(pos) } } impl Write for &'_ MockFile { fn write(&mut self, src: &[u8]) -> io::Result { self.inner_write(src) } fn flush(&mut self) -> io::Result<()> { self.inner_flush() } } thread_local! { static QUEUE: RefCell>> = RefCell::new(VecDeque::new()) } #[derive(Debug)] pub(super) struct JoinHandle { rx: oneshot::Receiver, } pub(super) fn spawn_blocking(f: F) -> JoinHandle 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: F) -> Option> 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 Future for JoinHandle { type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 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(); } }