mssf_core/sync/
wait.rs

1// ------------------------------------------------------------
2// Copyright (c) Microsoft Corporation.  All rights reserved.
3// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
4// ------------------------------------------------------------
5
6// Sync implementation for SF Callback and Contexts.
7use std::sync::{Arc, Condvar, Mutex};
8
9use mssf_com::FabricCommon::{
10    IFabricAsyncOperationCallback, IFabricAsyncOperationCallback_Impl,
11    IFabricAsyncOperationContext, IFabricAsyncOperationContext_Impl,
12};
13use windows_core::implement;
14
15#[derive(Debug)]
16#[implement(IFabricAsyncOperationCallback)]
17pub struct WaitableCallback {
18    pair_: Arc<(Mutex<bool>, Condvar)>,
19}
20
21pub struct WaitableToken {
22    pair_: Arc<(Mutex<bool>, Condvar)>,
23}
24
25impl Default for WaitableCallback {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31impl WaitableCallback {
32    pub fn channel() -> (WaitableToken, IFabricAsyncOperationCallback) {
33        let callback = WaitableCallback::new();
34        let token = WaitableToken {
35            pair_: callback.pair_.clone(),
36        };
37        let i_callbaack = callback.into();
38        (token, i_callbaack)
39    }
40
41    pub fn new() -> WaitableCallback {
42        WaitableCallback {
43            pair_: Arc::new((Mutex::new(false), Condvar::new())),
44        }
45    }
46}
47
48impl IFabricAsyncOperationCallback_Impl for WaitableCallback_Impl {
49    // notify the function has been invoked.
50    fn Invoke(&self, _context: windows_core::Ref<IFabricAsyncOperationContext>) {
51        //println!("WaitableCallback Invoke.");
52        let (lock, cvar) = &*self.pair_;
53        let mut started = lock.lock().unwrap();
54        *started = true;
55        // We notify the condvar that the value has changed.
56        cvar.notify_one();
57    }
58}
59
60impl WaitableToken {
61    pub fn wait(&self) {
62        //println!("WaitableCallback wait.");
63        // Wait for callback to be invoked
64        let (lock, cvar) = &*self.pair_;
65        let mut started = lock.lock().unwrap();
66        while !*started {
67            started = cvar.wait(started).unwrap();
68        }
69    }
70}
71
72// The basic implementation of async context
73// which use needs to trigger callback synchronously
74#[derive(Debug)]
75#[implement(IFabricAsyncOperationContext)]
76pub struct AsyncContext {
77    callback_: IFabricAsyncOperationCallback,
78}
79
80impl AsyncContext {
81    // construct ctx. Note: caller needs to invoke callback.
82    // This is different from cpp impl.
83    pub fn new(callback: core::option::Option<&IFabricAsyncOperationCallback>) -> AsyncContext {
84        let callback_copy: IFabricAsyncOperationCallback = callback.expect("msg").clone();
85
86        AsyncContext {
87            callback_: callback_copy,
88        }
89    }
90}
91
92impl IFabricAsyncOperationContext_Impl for AsyncContext_Impl {
93    fn IsCompleted(&self) -> bool {
94        true
95    }
96
97    fn CompletedSynchronously(&self) -> bool {
98        true
99    }
100
101    fn Callback(&self) -> crate::WinResult<IFabricAsyncOperationCallback> {
102        // get a view of the callback
103        let callback_copy: IFabricAsyncOperationCallback = self.callback_.clone();
104        Ok(callback_copy)
105    }
106
107    fn Cancel(&self) -> crate::WinResult<()> {
108        Ok(())
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use mssf_com::FabricCommon::IFabricAsyncOperationContext;
115
116    use super::{AsyncContext, WaitableCallback};
117
118    #[test]
119    fn test_waitable_callback() {
120        let (token, callback) = WaitableCallback::channel();
121        let ctx: IFabricAsyncOperationContext = AsyncContext::new(Some(&callback)).into();
122        unsafe { ctx.Callback().unwrap().Invoke(&ctx) };
123        token.wait();
124    }
125}