use core::future::poll_fn;
use core::pin::Pin;
use core::time::Duration;
use std::fs::{File, TryLockError};
use std::io;
use futures_io::AsyncWrite;
use crate::io::Handle;
const FIRST: Duration = Duration::from_micros(50);
const LAST: Duration = Duration::from_millis(20);
impl Handle<File> {
pub async fn lock_file(&self, shared: bool) -> io::Result<()> {
let mut pause = FIRST;
loop {
match self.try_lock_once(shared) {
Ok(()) => return Ok(()),
Err(TryLockError::Error(err)) => return Err(err),
Err(TryLockError::WouldBlock) => {
crate::time::sleep(pause).await;
pause = (pause * 2).min(LAST);
}
}
}
}
fn try_lock_once(&self, shared: bool) -> Result<(), TryLockError> {
let lease = self.source().lease().map_err(TryLockError::Error)?;
let file = lease.file();
if shared {
file.try_lock_shared()
} else {
file.try_lock()
}
}
pub async fn try_lock_file(&self, shared: bool) -> Result<(), TryLockError> {
self.try_lock_once(shared)
}
pub async fn unlock_file(&self) -> io::Result<()> {
let mut this = self;
let flushed = poll_fn(|cx| Pin::new(&mut this).poll_flush(cx)).await;
let unlocked = self
.source()
.lease()
.and_then(|lease| lease.file().unlock());
flushed.and(unlocked)
}
}