use std::ffi::{OsStr, OsString};
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
#[cfg(windows)]
use std::os::windows::ffi::OsStrExt;
use std::path::{Path, PathBuf};
use std::ptr::NonNull;
use crate::Mutations;
use crate::general::{DebugHandler, GeneralHandler, GeneralObserver, SerializeHandler};
use crate::helper::macros::{delegate_methods, shallow_observer};
use crate::helper::{AsDeref, AsDerefMut, ObserverState, QuasiObserver, Unsigned};
use crate::impls::shallow::ShallowMut;
use crate::observe::{DefaultSpec, RefObserve};
shallow_observer! {
struct OsStrObserver(OsStr);
}
impl<'ob, S: ?Sized, D> OsStrObserver<'ob, S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = OsStr>,
{
fn nonempty_mut(&mut self) -> &mut OsStr {
if (*self).untracked_ref().is_empty() {
self.untracked_mut()
} else {
self.tracked_mut()
}
}
delegate_methods! { nonempty_mut() as OsStr =>
pub fn make_ascii_uppercase(&mut self);
pub fn make_ascii_lowercase(&mut self);
}
}
impl ShallowMut<'_, OsStr> {
fn nonempty_mut(&mut self) -> &mut OsStr {
if (*self).untracked_ref().is_empty() {
self.untracked_mut()
} else {
self.tracked_mut()
}
}
delegate_methods! { nonempty_mut() as OsStr =>
pub fn make_ascii_uppercase(&mut self);
pub fn make_ascii_lowercase(&mut self);
}
}
macro_rules! generic_impl_partial_eq {
($(impl $([$($gen:tt)*])? _ for $ty:ty);* $(;)?) => {
$(
impl<'ob, $($($gen)*,)? S: ?Sized, D> PartialEq<$ty> for OsStrObserver<'ob, S, D>
where
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialEq<$ty>,
{
fn eq(&self, other: &$ty) -> bool {
(***self).as_deref().eq(other)
}
}
)*
};
}
generic_impl_partial_eq! {
impl _ for str;
impl _ for String;
impl _ for OsStr;
impl _ for OsString;
impl _ for Path;
impl _ for PathBuf;
impl ['a, T] _ for &'a T;
impl ['a, T: ToOwned] _ for std::borrow::Cow<'a, T>;
}
#[cfg(unix)]
fn os_str_len(value: &OsStr) -> usize {
value.as_bytes().len()
}
#[cfg(windows)]
fn os_str_len(value: &OsStr) -> usize {
value.encode_wide().count()
}
pub struct OsStrHandler {
raw_parts: Option<(NonNull<()>, usize)>,
}
impl ObserverState for OsStrHandler {
type Target = OsStr;
fn invalidate(this: &mut Self, value: &OsStr) {
this.raw_parts
.get_or_insert_with(|| (NonNull::from(value).cast::<()>(), os_str_len(value)));
}
}
impl GeneralHandler for OsStrHandler {
fn observe(_: &OsStr) -> Self {
Self { raw_parts: None }
}
}
impl SerializeHandler for OsStrHandler {
unsafe fn flush(&mut self, value: &OsStr) -> Mutations {
let Some((old_addr, old_len)) = self.raw_parts.take() else {
return Mutations::new();
};
let new_addr = NonNull::from(value).cast::<()>();
let new_len = os_str_len(value);
if new_addr != old_addr {
return Mutations::replace(value);
}
if new_len < old_len {
#[cfg(not(feature = "truncate"))]
return Mutations::replace(value);
#[cfg(feature = "truncate")]
{
#[cfg(unix)]
return Mutations::truncate(old_len - new_len).with_prefix("Unix");
#[cfg(windows)]
return Mutations::truncate(old_len - new_len).with_prefix("Windows");
}
}
if new_len > old_len {
#[cfg(not(feature = "append"))]
return Mutations::replace(value);
#[cfg(feature = "append")]
{
#[cfg(unix)]
return Mutations::append(&value.as_bytes()[old_len..]).with_prefix("Unix");
#[cfg(windows)]
return Mutations::append_owned(value.encode_wide().skip(old_len).collect::<Vec<_>>())
.with_prefix("Windows");
}
}
Mutations::new()
}
}
impl DebugHandler for OsStrHandler {
const NAME: &'static str = "OsStrHandler";
}
impl RefObserve for OsStr {
type Observer<'ob, S, D>
= GeneralObserver<'ob, OsStrHandler, S, D>
where
Self: 'ob,
D: Unsigned,
S: AsDeref<D, Target = Self> + ?Sized + 'ob;
type Spec = DefaultSpec;
}