use super::*;
use bindings::*;
use std::sync::*;
pub struct Event<T: Interface + Clone> {
swap: Mutex<()>,
change: Mutex<()>,
delegates: Array<T>,
}
impl<T: Interface + Clone> Default for Event<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Interface + Clone> Event<T> {
pub fn new() -> Self {
Self { delegates: Array::new(), swap: Mutex::default(), change: Mutex::default() }
}
pub fn add(&mut self, delegate: &T) -> Result<i64> {
let mut _lock_free_drop = Array::new();
Ok({
let change_lock = self.change.lock().unwrap();
let mut new_delegates = Array::with_capacity(self.delegates.len() + 1)?;
for delegate in self.delegates.as_slice() {
new_delegates.push(delegate.clone());
}
let delegate = Delegate::new(delegate)?;
let token = delegate.to_token();
new_delegates.push(delegate);
let swap_lock = self.swap.lock().unwrap();
_lock_free_drop = self.delegates.swap(new_delegates);
token
})
}
pub fn remove(&mut self, token: i64) -> Result<()> {
let mut _lock_free_drop = Array::new();
{
let change_lock = self.change.lock().unwrap();
if self.delegates.is_empty() {
return Ok(());
}
let mut capacity = self.delegates.len() - 1;
let mut new_delegates = Array::new();
let mut removed = false;
if capacity == 0 {
removed = self.delegates.as_slice()[0].to_token() == token;
} else {
new_delegates = Array::with_capacity(capacity)?;
for delegate in self.delegates.as_slice() {
if !removed && delegate.to_token() == token {
removed = true;
continue;
}
if capacity == 0 {
break;
}
new_delegates.push(delegate.clone());
capacity -= 1;
}
}
if removed {
let swap_lock = self.swap.lock().unwrap();
_lock_free_drop = self.delegates.swap(new_delegates);
}
}
Ok(())
}
pub fn clear(&mut self) {
let mut _lock_free_drop = Array::new();
{
let change_lock = self.change.lock().unwrap();
if self.delegates.is_empty() {
return;
}
let swap_lock = self.swap.lock().unwrap();
_lock_free_drop = self.delegates.swap(Array::new());
}
}
pub fn call<F: FnMut(&T) -> Result<()>>(&mut self, mut callback: F) -> Result<()> {
let lock_free_calls = {
let swap_lock = self.swap.lock().unwrap();
self.delegates.clone()
};
for delegate in lock_free_calls.as_slice() {
if let Err(error) = delegate.call(&mut callback) {
const RPC_E_SERVER_UNAVAILABLE: HRESULT = HRESULT(-2147023174); if matches!(error.code(), RPC_E_DISCONNECTED | JSCRIPT_E_CANTEXECUTE | RPC_E_SERVER_UNAVAILABLE) {
self.remove(delegate.to_token())?;
}
}
}
Ok(())
}
}
struct Array<T: Interface + Clone> {
buffer: *mut Buffer<T>,
len: usize,
_phantom: std::marker::PhantomData<T>,
}
impl<T: Interface + Clone> Default for Array<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Interface + Clone> Array<T> {
fn new() -> Self {
Self { buffer: std::ptr::null_mut(), len: 0, _phantom: std::marker::PhantomData }
}
fn with_capacity(capacity: usize) -> Result<Self> {
Ok(Self { buffer: Buffer::new(capacity)?, len: 0, _phantom: std::marker::PhantomData })
}
fn swap(&mut self, mut other: Self) -> Self {
unsafe { std::ptr::swap(&mut self.buffer, &mut other.buffer) };
std::mem::swap(&mut self.len, &mut other.len);
other
}
fn is_empty(&self) -> bool {
self.len == 0
}
fn len(&self) -> usize {
self.len
}
fn push(&mut self, delegate: Delegate<T>) {
unsafe {
std::ptr::write((*self.buffer).as_mut_ptr().add(self.len), delegate);
self.len += 1;
}
}
fn as_slice(&self) -> &[Delegate<T>] {
if self.is_empty() {
&[]
} else {
unsafe { std::slice::from_raw_parts((*self.buffer).as_ptr(), self.len) }
}
}
fn as_mut_slice(&mut self) -> &mut [Delegate<T>] {
if self.is_empty() {
&mut []
} else {
unsafe { std::slice::from_raw_parts_mut((*self.buffer).as_mut_ptr(), self.len) }
}
}
}
impl<T: Interface + Clone> Clone for Array<T> {
fn clone(&self) -> Self {
if !self.is_empty() {
unsafe { (*self.buffer).0.add_ref() };
}
Self { buffer: self.buffer, len: self.len, _phantom: std::marker::PhantomData }
}
}
impl<T: Interface + Clone> Drop for Array<T> {
fn drop(&mut self) {
unsafe {
if !self.is_empty() && (*self.buffer).0.release() == 0 {
std::ptr::drop_in_place(self.as_mut_slice());
heap_free(self.buffer as _)
}
}
}
}
#[repr(C)]
struct Buffer<T>(RefCount, std::marker::PhantomData<T>);
impl<T: Interface + Clone> Buffer<T> {
fn new(len: usize) -> Result<*mut Self> {
if len == 0 {
Ok(std::ptr::null_mut())
} else {
let alloc_size = std::mem::size_of::<Self>() + len * std::mem::size_of::<Delegate<T>>();
let header = heap_alloc(alloc_size)? as *mut Self;
unsafe {
header.write(Self(RefCount::new(1), std::marker::PhantomData));
}
Ok(header)
}
}
fn as_ptr(&self) -> *const Delegate<T> {
unsafe { (self as *const Self).add(1) as *const _ }
}
fn as_mut_ptr(&mut self) -> *mut Delegate<T> {
unsafe { (self as *mut Self).add(1) as *mut _ }
}
}
#[derive(Clone)]
enum Delegate<T> {
Direct(T),
Indirect(AgileReference<T>),
}
impl<T: Interface + Clone> Delegate<T> {
fn new(delegate: &T) -> Result<Self> {
if delegate.cast::<IAgileObject>().is_ok() {
Ok(Self::Direct(delegate.clone()))
} else {
Ok(Self::Indirect(AgileReference::new(delegate)?))
}
}
fn to_token(&self) -> i64 {
unsafe {
match self {
Self::Direct(delegate) => EncodePointer(std::mem::transmute_copy(delegate)) as _,
Self::Indirect(delegate) => EncodePointer(std::mem::transmute_copy(delegate)) as _,
}
}
}
fn call<F: FnMut(&T) -> Result<()>>(&self, mut callback: F) -> Result<()> {
match self {
Self::Direct(delegate) => callback(delegate),
Self::Indirect(delegate) => callback(&delegate.resolve()?),
}
}
}