janus_plugin/
session.rs

1/// Utilities to make it easier to maintain Janus session state between plugin callbacks.
2use crate::PluginSession;
3use std::error::Error;
4use std::hash::{Hash, Hasher};
5use std::fmt;
6use std::ops::Deref;
7use std::sync::Arc;
8
9/// An error indicating that someone handed us a null plugin session handle.
10#[derive(Debug, Clone, Copy)]
11pub struct NullHandleError;
12
13impl Error for NullHandleError {}
14
15impl fmt::Display for NullHandleError {
16    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17        f.write_str("A null session handle was provided.")
18    }
19}
20
21/// A wrapper for a Janus session. Contains a pointer to the Janus `PluginSession` (which is used to identify
22/// this session in the Janus FFI) and any Rust state associated with the session.
23#[derive(Debug, Clone)]
24pub struct SessionWrapper<T> {
25    pub handle: *mut PluginSession,
26    state: T,
27}
28
29impl<T> Hash for SessionWrapper<T> {
30    fn hash<H: Hasher>(&self, state: &mut H) {
31        self.handle.hash(state);
32    }
33}
34
35impl<T> PartialEq for SessionWrapper<T> {
36    fn eq(&self, other: &Self) -> bool {
37        self.handle == other.handle
38    }
39}
40
41impl<T> Eq for SessionWrapper<T> {}
42
43impl<T> SessionWrapper<T> {
44    /// Allocates a boxed, reference-counted state wrapper associated with a Janus PluginSession
45    /// (whose plugin_handle will then point to the contents of the box).
46    pub unsafe fn associate(handle: *mut PluginSession, state: T) -> Result<Box<Arc<Self>>, NullHandleError> {
47        match handle.as_mut() {
48            Some(x) => {
49                let mut result = Box::new(Arc::new(Self { handle, state }));
50                x.plugin_handle = result.as_mut() as *mut Arc<Self> as *mut _;
51                Ok(result)
52            }
53            None => Err(NullHandleError),
54        }
55    }
56
57    /// Retrieves and clones the reference-counted state wrapper associated with a Janus PluginSession.
58    pub unsafe fn from_ptr(handle: *mut PluginSession) -> Result<Arc<Self>, NullHandleError> {
59        match handle.as_ref() {
60            Some(x) => Ok(Arc::clone(
61                (x.plugin_handle as *mut Arc<Self>).as_ref().unwrap()
62            )),
63            None => Err(NullHandleError),
64        }
65    }
66
67    /// Returns the opaque pointer for this session.
68    pub fn as_ptr(&self) -> *mut PluginSession {
69        self.handle
70    }
71}
72
73impl<T> Deref for SessionWrapper<T> {
74    type Target = T;
75    fn deref(&self) -> &T {
76        &self.state
77    }
78}
79
80impl<T> Drop for SessionWrapper<T> {
81    fn drop(&mut self) {
82        unsafe {
83            // the Janus core assumes that we will store the handle reference, and increments it on our behalf.
84            // we're only responsible for decrementing it when we are done with it.
85            let refcount = &(*self.handle).ref_;
86            super::refcount::decrease(refcount);
87        }
88    }
89}
90
91// the pointer is opaque to Janus code, so this handle is threadsafe to the extent that the state is
92
93unsafe impl<T: Sync> Sync for SessionWrapper<T> {}
94unsafe impl<T: Send> Send for SessionWrapper<T> {}
95
96// todo: port to refcount branch
97/*
98#[cfg(test)]
99mod tests {
100
101    use super::*;
102    use std::ptr;
103
104    #[test]
105    fn handle_round_trip() {
106        struct State(i32);
107        let mut handle = PluginSession {
108            gateway_handle: ptr::null_mut(),
109            plugin_handle: ptr::null_mut(),
110            stopped_bitfield: 0,
111            __padding: Default::default(),
112        };
113
114        let ptr = &mut handle as *mut _;
115        let session = unsafe { SessionWrapper::associate(ptr, State(42)).unwrap() };
116        assert_eq!(session.as_ref() as *const _ as *mut _, handle.plugin_handle);
117        assert_eq!(unsafe { SessionWrapper::<State>::from_ptr(ptr).unwrap().state.0 }, 42);
118    }
119}
120*/