1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#![allow(non_snake_case)]

// lib that contains all common extensions for the raw fabric apis.

pub mod client;
pub mod conf;
pub mod debug;
mod iter;
pub mod runtime;
pub mod strings;
pub mod sync;

use std::sync::{Arc, Condvar, Mutex};

use log::info;
use mssf_com::FabricCommon::{
    IFabricAsyncOperationCallback, IFabricAsyncOperationCallback_Impl,
    IFabricAsyncOperationContext, IFabricAsyncOperationContext_Impl,
};
use windows::core::implement;

// re-export some windows types
pub use windows_core::{Error, Result, GUID, HSTRING, PCWSTR};

#[derive(Debug)]
#[implement(IFabricAsyncOperationCallback)]
pub struct WaitableCallback {
    pair_: Arc<(Mutex<bool>, Condvar)>,
}

pub struct WaitableToken {
    pair_: Arc<(Mutex<bool>, Condvar)>,
}

impl Default for WaitableCallback {
    fn default() -> Self {
        Self::new()
    }
}

impl WaitableCallback {
    pub fn channel() -> (WaitableToken, IFabricAsyncOperationCallback) {
        let callback = WaitableCallback::new();
        let token = WaitableToken {
            pair_: callback.pair_.clone(),
        };
        let i_callbaack = callback.into();
        (token, i_callbaack)
    }

    pub fn new() -> WaitableCallback {
        WaitableCallback {
            pair_: Arc::new((Mutex::new(false), Condvar::new())),
        }
    }
}

impl IFabricAsyncOperationCallback_Impl for WaitableCallback {
    // notify the function has been invoked.
    fn Invoke(&self, _context: ::core::option::Option<&IFabricAsyncOperationContext>) {
        //println!("WaitableCallback Invoke.");
        let (lock, cvar) = &*self.pair_;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    }
}

impl WaitableToken {
    pub fn wait(&self) {
        //println!("WaitableCallback wait.");
        // Wait for callback to be invoked
        let (lock, cvar) = &*self.pair_;
        let mut started = lock.lock().unwrap();
        while !*started {
            started = cvar.wait(started).unwrap();
        }
    }
}

// The basic implementation of async context
// which use needs to trigger callback synchronously
#[derive(Debug)]
#[implement(IFabricAsyncOperationContext)]
pub struct AsyncContext {
    callback_: IFabricAsyncOperationCallback,
}

impl AsyncContext {
    // construct ctx. Note: caller needs to invoke callback.
    // This is different from cpp impl.
    pub fn new(callback: core::option::Option<&IFabricAsyncOperationCallback>) -> AsyncContext {
        info!("AsyncContext::new");
        let callback_copy: IFabricAsyncOperationCallback = callback.expect("msg").clone();

        AsyncContext {
            callback_: callback_copy,
        }
    }
}

impl IFabricAsyncOperationContext_Impl for AsyncContext {
    fn IsCompleted(&self) -> windows::Win32::Foundation::BOOLEAN {
        windows::Win32::Foundation::BOOLEAN::from(true)
    }

    fn CompletedSynchronously(&self) -> windows::Win32::Foundation::BOOLEAN {
        windows::Win32::Foundation::BOOLEAN::from(true)
    }

    fn Callback(&self) -> windows::core::Result<IFabricAsyncOperationCallback> {
        info!("AsyncContext::Callback");
        // get a view of the callback
        let callback_copy: IFabricAsyncOperationCallback = self.callback_.clone();
        Ok(callback_copy)
    }

    fn Cancel(&self) -> windows::core::Result<()> {
        info!("AsyncContext::Cancel");
        Ok(())
    }
}