#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(unix)]
mod unix;
#[cfg(unix)]
use crate::unix as sys;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
use crate::windows as sys;
pub use crate::sys::{Error, OsStr, OsString};
#[cfg(feature = "std")]
use std::{
ffi,
path::{Path, PathBuf},
};
use core::{fmt, ops::Deref};
impl Clone for OsString {
fn clone(&self) -> Self {
self.to_os_str()
.and_then(|str| str.into_os_string())
.expect("Allocation error")
}
}
impl fmt::Debug for OsString {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:?}", self.as_ref())
}
}
impl fmt::Display for OsString {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.as_ref())
}
}
impl Deref for OsString {
type Target = OsStr;
fn deref(&self) -> &OsStr {
self.as_ref()
}
}
#[derive(Debug)]
pub enum EitherOsStr<'str> {
Borrowed(&'str OsStr),
Owned(OsString),
}
impl<'str> AsRef<OsStr> for EitherOsStr<'str> {
fn as_ref(&self) -> &OsStr {
match self {
Self::Borrowed(str) => str,
Self::Owned(string) => string.as_ref(),
}
}
}
impl<'str> Deref for EitherOsStr<'str> {
type Target = OsStr;
fn deref(&self) -> &OsStr {
self.as_ref()
}
}
pub trait IntoOsString {
fn into_os_string(self) -> Result<OsString, Error>;
}
impl IntoOsString for OsString {
fn into_os_string(self) -> Result<OsString, Error> {
Ok(self)
}
}
impl<'str> IntoOsString for EitherOsStr<'str> {
fn into_os_string(self) -> Result<OsString, Error> {
match self {
Self::Borrowed(str) => str.into_os_string(),
Self::Owned(string) => Ok(string),
}
}
}
#[cfg(feature = "std")]
impl<'str> IntoOsString for &'str ffi::OsStr {
fn into_os_string(self) -> Result<OsString, Error> {
self.to_os_str()?.into_os_string()
}
}
#[cfg(feature = "std")]
impl IntoOsString for PathBuf {
fn into_os_string(self) -> Result<OsString, Error> {
(*self).into_os_string()
}
}
#[cfg(feature = "std")]
impl<'str> IntoOsString for &'str Path {
fn into_os_string(self) -> Result<OsString, Error> {
AsRef::<ffi::OsStr>::as_ref(self).to_os_str()?.into_os_string()
}
}
#[cfg(feature = "std")]
impl IntoOsString for ffi::OsString {
fn into_os_string(self) -> Result<OsString, Error> {
(*self).into_os_string()
}
}
impl<'str> IntoOsString for &'str str {
fn into_os_string(self) -> Result<OsString, Error> {
self.to_os_str()?.into_os_string()
}
}
#[cfg(feature = "std")]
impl IntoOsString for String {
fn into_os_string(self) -> Result<OsString, Error> {
self.to_os_str()?.into_os_string()
}
}
#[cfg(feature = "std")]
impl ToOsStr for String {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
(**self).to_os_str()
}
}
pub trait ToOsStr {
fn to_os_str(&self) -> Result<EitherOsStr, Error>;
}
impl<'str> ToOsStr for EitherOsStr<'str> {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
Ok(match self {
EitherOsStr::Owned(string) => {
EitherOsStr::Owned(string.to_os_str()?.into_os_string()?)
},
EitherOsStr::Borrowed(str) => EitherOsStr::Borrowed(str),
})
}
}
impl ToOsStr for OsStr {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
Ok(EitherOsStr::Borrowed(self))
}
}
impl ToOsStr for OsString {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
Ok(EitherOsStr::Borrowed(self.as_ref()))
}
}
#[cfg(feature = "std")]
impl ToOsStr for ffi::OsString {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
(**self).to_os_str()
}
}
#[cfg(feature = "std")]
impl ToOsStr for PathBuf {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
(**self).to_os_str()
}
}
#[cfg(feature = "std")]
impl ToOsStr for Path {
fn to_os_str(&self) -> Result<EitherOsStr, Error> {
AsRef::<ffi::OsStr>::as_ref(self).to_os_str()
}
}
#[derive(Debug)]
pub struct LockFile {
locked: bool,
desc: sys::FileDesc,
}
impl LockFile {
pub fn open<P>(path: &P) -> Result<Self, Error>
where
P: ToOsStr + ?Sized,
{
let path = path.to_os_str()?;
let desc = sys::open(path.as_ref())?;
Ok(Self { locked: false, desc })
}
pub fn lock(&mut self) -> Result<(), Error> {
if self.locked {
panic!("Cannot lock if already owning a lock");
}
sys::lock(self.desc)?;
self.locked = true;
Ok(())
}
pub fn try_lock(&mut self) -> Result<bool, Error> {
if self.locked {
panic!("Cannot lock if already owning a lock");
}
let locked = sys::try_lock(self.desc)?;
if locked {
self.locked = true;
}
Ok(locked)
}
pub fn owns_lock(&self) -> bool {
self.locked
}
pub fn unlock(&mut self) -> Result<(), Error> {
if !self.locked {
panic!("Attempted to unlock already locked lockfile");
}
sys::unlock(self.desc)?;
self.locked = false;
Ok(())
}
}
impl Drop for LockFile {
fn drop(&mut self) {
if self.locked {
let _ = sys::unlock(self.desc);
}
sys::close(self.desc);
}
}