dittolive_ditto/presence/
observer.rs

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
use_prelude!();

use std::hash::Hash;

use ffi_sdk::{FfiDynPresenceCallback, FfiPresenceObserver};
use uuid::Uuid;

use crate::error::Result;

trait_alias! {
    pub trait PresenceCallback = FnMut(&PresenceGraph) + Send + Sync + 'static
}

/// Use [`ditto.presence().register_observer(...)`] to create a new `PresenceObserver`.
///
/// # Example
///
/// ```
/// use dittolive_ditto::Ditto;
/// # fn example(ditto: &Ditto) -> anyhow::Result<()> {
///
/// // To register a new presence observer
/// let observer = ditto.presence().register_observer(|graph| {
///     println!("Graph updated: {:?}", graph);
/// })?;
///
/// // Later, to cancel the observer
/// observer.cancel();
/// # Ok(())
/// # }
/// ```
///
/// [`ditto.presence().register_observer(...)`]: crate::presence::Presence::register_observer
pub struct PresenceObserver {
    pub(crate) handle: repr_c::Box<FfiPresenceObserver>,
}

impl PresenceObserver {
    /// Create a new `PresenceObserver` with the given callback to receive presence updates.
    pub(crate) fn new<F>(ditto: &ffi_sdk::BoxedDitto, mut observer: F) -> Result<PresenceObserver>
    where
        F: PresenceCallback,
    {
        let ffi_callback: repr_c::Box<FfiDynPresenceCallback> = {
            fn make_callback<F>(f: F) -> repr_c::Box<FfiDynPresenceCallback>
            where
                F: 'static + Send + FnMut(c_slice::Box<u8>),
            {
                Box::new(f).into()
            }

            make_callback(move |graph: c_slice::Box<u8>| {
                let graph =
                    serde_json::from_slice(&graph).expect("should deserialize presence graph");
                observer(&graph);
            })
        };

        let handle = ffi_sdk::dittoffi_presence_register_observer_throws(ditto, ffi_callback)
            .into_rust_result()?;
        Ok(Self { handle })
    }

    /// Cancels this [`PresenceObserver`]. The registered callback will no longer be called.
    pub fn cancel(&self) {
        ffi_sdk::dittoffi_presence_observer_cancel(&self.handle);
    }

    /// Returns whether this [`PresenceObserver`] has been cancelled.
    pub fn is_cancelled(&self) -> bool {
        ffi_sdk::dittoffi_presence_observer_is_cancelled(&self.handle)
    }

    /// Returns the unique identifier for this [`PresenceObserver`].
    fn id(&self) -> Uuid {
        let buffer = ffi_sdk::dittoffi_presence_observer_id(&self.handle);
        Uuid::from_slice(buffer.as_slice()).expect("bug: expected valid UUID")
    }
}

impl Eq for PresenceObserver {}
impl PartialEq for PresenceObserver {
    fn eq(&self, other: &Self) -> bool {
        self.id() == other.id()
    }
}

impl Hash for PresenceObserver {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.id().hash(state);
    }
}