mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-25 00:00:18 +02:00
137 lines
3.7 KiB
Rust
137 lines
3.7 KiB
Rust
//! 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()
|
|
}
|
|
}
|
|
|
|
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 }
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|