use crate::bindings::*;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::sync::{RwLock, RwLockWriteGuard};
use windows::Foundation::TypedEventHandler;
use windows::Win32::Foundation::ERROR_LOCK_VIOLATION;
use windows_core::{Event, IInspectable, Result, implement};
pub struct NotifyLock<T> {
lock: RwLock<T>,
}
pub use std::sync::RwLockReadGuard as NotifyLockReadGuard;
pub struct NotifyLockWriteGuard<'a, T, P = ()> {
guard: ManuallyDrop<RwLockWriteGuard<'a, T>>,
peeker: Box<dyn Fn(&T) -> P + 'a>,
notifier: Box<dyn Fn(P) + 'a>,
}
impl<'a, T, P> Deref for NotifyLockWriteGuard<'a, T, P> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.guard
}
}
impl<'a, T, P> DerefMut for NotifyLockWriteGuard<'a, T, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.guard
}
}
impl<'a, T, P> Drop for NotifyLockWriteGuard<'a, T, P> {
fn drop(&mut self) {
let peek_data = (self.peeker)(&self.guard);
unsafe {
ManuallyDrop::drop(&mut self.guard);
}
(self.notifier)(peek_data);
}
}
impl<T> NotifyLock<T> {
pub fn new(value: T) -> Self {
NotifyLock {
lock: RwLock::new(value),
}
}
pub fn read(&self) -> Result<NotifyLockReadGuard<'_, T>> {
self.lock.read().map_err(|_| ERROR_LOCK_VIOLATION.into())
}
pub fn write<'a, F>(&'a self, notifier: F) -> Result<NotifyLockWriteGuard<'a, T>>
where
F: Fn() + 'a,
{
self.lock
.write()
.map(|guard| NotifyLockWriteGuard {
guard: ManuallyDrop::new(guard),
peeker: Box::new(|_| ()),
notifier: Box::new(move |_| notifier()),
})
.map_err(|_| ERROR_LOCK_VIOLATION.into())
}
pub fn write_with_peek<'a, PF, NF, P>(
&'a self,
peeker: PF,
notifier: NF,
) -> Result<NotifyLockWriteGuard<'a, T, P>>
where
PF: Fn(&T) -> P + 'a,
NF: Fn(P) + 'a,
{
self.lock
.write()
.map(|guard| NotifyLockWriteGuard {
guard: ManuallyDrop::new(guard),
peeker: Box::new(peeker),
notifier: Box::new(notifier),
})
.map_err(|_| ERROR_LOCK_VIOLATION.into())
}
}
pub type PropChangedEventHandler = Event<TypedEventHandler<IInspectable, IPropChangedEventArgs>>;
#[implement(IPropChangedEventArgs)]
pub struct PropChangedEventArgs(pub windows_core::HSTRING);
impl IPropChangedEventArgs_Impl for PropChangedEventArgs_Impl {
fn PropertyName(&self) -> windows_core::Result<windows_core::HSTRING> {
Ok(self.0.clone())
}
}
impl From<windows_core::HSTRING> for PropChangedEventArgs {
fn from(value: windows_core::HSTRING) -> Self {
PropChangedEventArgs(value)
}
}
pub type ItemsChangedEventHandler = Event<TypedEventHandler<IInspectable, IItemsChangedEventArgs>>;
#[implement(IItemsChangedEventArgs)]
pub struct ItemsChangedEventArgs(pub i32);
impl IItemsChangedEventArgs_Impl for ItemsChangedEventArgs_Impl {
fn TotalItems(&self) -> windows_core::Result<i32> {
Ok(self.0)
}
}
impl From<i32> for ItemsChangedEventArgs {
fn from(value: i32) -> Self {
ItemsChangedEventArgs(value)
}
}