use super::*; use std::sync::Mutex; struct State { result: Option>, completed: Option, completed_assigned: bool, } impl State { fn status(&self) -> AsyncStatus { match &self.result { None => AsyncStatus::Started, Some(Ok(_)) => AsyncStatus::Completed, Some(Err(_)) => AsyncStatus::Error, } } fn error_code(&self) -> HRESULT { match &self.result { Some(Err(error)) => error.code(), _ => HRESULT(0), } } fn get_results(&self) -> Result { match &self.result { Some(result) => result.clone(), None => Err(Error::from_hresult(HRESULT(0x8000000Eu32 as i32))), // E_ILLEGAL_METHOD_CALL } } } struct SyncState(Mutex>); impl SyncState { fn new() -> Self { Self(Mutex::new(State { result: None, completed: None, completed_assigned: false, })) } fn status(&self) -> AsyncStatus { self.0.lock().unwrap().status() } fn error_code(&self) -> HRESULT { self.0.lock().unwrap().error_code() } fn get_results(&self) -> Result { self.0.lock().unwrap().get_results() } fn set_completed(&self, sender: &T, handler: Ref) -> Result<()> { let mut guard = self.0.lock().unwrap(); if guard.completed_assigned { Err(Error::from_hresult(HRESULT(0x80000018u32 as i32))) // E_ILLEGAL_DELEGATE_ASSIGNMENT } else { guard.completed_assigned = true; let status = guard.status(); let handler = handler.ok()?; if status == AsyncStatus::Started { guard.completed = Some(handler.clone()); } else { drop(guard); sender.invoke_completed(handler, status); } Ok(()) } } fn spawn(&self, sender: &T, f: F) where F: FnOnce() -> Result + Send + 'static, { let result = f(); let mut guard = self.0.lock().unwrap(); debug_assert!(guard.result.is_none()); guard.result = Some(result); let status = guard.status(); let completed = guard.completed.take(); drop(guard); if let Some(completed) = completed { sender.invoke_completed(&completed, status); } } } unsafe impl Send for SyncState {} #[implement(IAsyncAction, IAsyncInfo)] struct Action(SyncState); #[implement(IAsyncOperation, IAsyncInfo)] struct Operation(SyncState>) where T: RuntimeType + 'static; #[implement(IAsyncActionWithProgress

, IAsyncInfo)] struct ActionWithProgress

(SyncState>) where P: RuntimeType + 'static; #[implement(IAsyncOperationWithProgress, IAsyncInfo)] struct OperationWithProgress(SyncState>) where T: RuntimeType + 'static, P: RuntimeType + 'static; impl IAsyncInfo_Impl for Action_Impl { fn Id(&self) -> Result { Ok(1) } fn Status(&self) -> Result { Ok(self.0.status()) } fn ErrorCode(&self) -> Result { Ok(self.0.error_code()) } fn Cancel(&self) -> Result<()> { Ok(()) } fn Close(&self) -> Result<()> { Ok(()) } } impl IAsyncInfo_Impl for Operation_Impl { fn Id(&self) -> Result { Ok(1) } fn Status(&self) -> Result { Ok(self.0.status()) } fn ErrorCode(&self) -> Result { Ok(self.0.error_code()) } fn Cancel(&self) -> Result<()> { Ok(()) } fn Close(&self) -> Result<()> { Ok(()) } } impl IAsyncInfo_Impl for ActionWithProgress_Impl

{ fn Id(&self) -> Result { Ok(1) } fn Status(&self) -> Result { Ok(self.0.status()) } fn ErrorCode(&self) -> Result { Ok(self.0.error_code()) } fn Cancel(&self) -> Result<()> { Ok(()) } fn Close(&self) -> Result<()> { Ok(()) } } impl IAsyncInfo_Impl for OperationWithProgress_Impl { fn Id(&self) -> Result { Ok(1) } fn Status(&self) -> Result { Ok(self.0.status()) } fn ErrorCode(&self) -> Result { Ok(self.0.error_code()) } fn Cancel(&self) -> Result<()> { Ok(()) } fn Close(&self) -> Result<()> { Ok(()) } } impl IAsyncAction_Impl for Action_Impl { fn SetCompleted(&self, handler: Ref) -> Result<()> { self.0.set_completed(&self.as_interface(), handler) } fn Completed(&self) -> Result { Err(Error::empty()) } fn GetResults(&self) -> Result<()> { self.0.get_results() } } impl IAsyncOperation_Impl for Operation_Impl { fn SetCompleted(&self, handler: Ref>) -> Result<()> { self.0.set_completed(&self.as_interface(), handler) } fn Completed(&self) -> Result> { Err(Error::empty()) } fn GetResults(&self) -> Result { self.0.get_results() } } impl IAsyncActionWithProgress_Impl

for ActionWithProgress_Impl

{ fn SetCompleted(&self, handler: Ref>) -> Result<()> { self.0.set_completed(&self.as_interface(), handler) } fn Completed(&self) -> Result> { Err(Error::empty()) } fn GetResults(&self) -> Result<()> { self.0.get_results() } fn SetProgress(&self, _: Ref>) -> Result<()> { Ok(()) } fn Progress(&self) -> Result> { Err(Error::empty()) } } impl IAsyncOperationWithProgress_Impl for OperationWithProgress_Impl { fn SetCompleted( &self, handler: Ref>, ) -> Result<()> { self.0.set_completed(&self.as_interface(), handler) } fn Completed(&self) -> Result> { Err(Error::empty()) } fn GetResults(&self) -> Result { self.0.get_results() } fn SetProgress(&self, _: Ref>) -> Result<()> { Ok(()) } fn Progress(&self) -> Result> { Err(Error::empty()) } } impl IAsyncAction { /// Creates an `IAsyncAction` that waits for the closure to execute on the Windows thread pool. pub fn spawn(f: F) -> Self where F: FnOnce() -> Result<()> + Send + 'static, { let object = ComObject::new(Action(SyncState::new())); let interface = object.to_interface(); windows_threading::submit(move || { object.0.spawn(&object.as_interface(), f); }); interface } } impl IAsyncOperation { /// Creates an `IAsyncOperation` that waits for the closure to execute on the Windows thread pool. pub fn spawn(f: F) -> Self where F: FnOnce() -> Result + Send + 'static, { let object = ComObject::new(Operation(SyncState::new())); let interface = object.to_interface(); windows_threading::submit(move || { object.0.spawn(&object.as_interface(), f); }); interface } } impl IAsyncActionWithProgress

{ /// Creates an `IAsyncActionWithProgress

` that waits for the closure to execute on the Windows thread pool. pub fn spawn(f: F) -> Self where F: FnOnce() -> Result<()> + Send + 'static, { let object = ComObject::new(ActionWithProgress(SyncState::new())); let interface = object.to_interface(); windows_threading::submit(move || { object.0.spawn(&object.as_interface(), f); }); interface } } impl IAsyncOperationWithProgress { /// Creates an `IAsyncOperationWithProgress` that waits for the closure to execute on the Windows thread pool. pub fn spawn(f: F) -> Self where F: FnOnce() -> Result + Send + 'static, { let object = ComObject::new(OperationWithProgress(SyncState::new())); let interface = object.to_interface(); windows_threading::submit(move || { object.0.spawn(&object.as_interface(), f); }); interface } }