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*/