Skip to main content

slowshell_plugin_abi/
payload.rs

1use core::{ffi::c_void, fmt};
2
3use abi_stable::{
4  StableAbi, sabi_trait,
5  std_types::{RBox, ROption, RStr},
6};
7
8use crate::{Args, TypeKey};
9
10#[repr(C)]
11#[derive(StableAbi)]
12pub struct PayloadValue {
13  key: TypeKey,
14  ptr: *mut c_void,
15  clone_fn: extern "C" fn(*const c_void) -> *mut c_void,
16  drop_fn: extern "C" fn(*mut c_void),
17}
18
19unsafe impl Send for PayloadValue {}
20unsafe impl Sync for PayloadValue {}
21
22impl PayloadValue {
23  fn new<T: Clone + Send + Sync + 'static>(value: T) -> Self {
24    extern "C" fn clone_it<T: Clone + Send + Sync + 'static>(ptr: *const c_void) -> *mut c_void {
25      let value = unsafe { &*(ptr as *const T) };
26      Box::into_raw(Box::new(value.clone())) as *mut c_void
27    }
28
29    extern "C" fn drop_it<T>(ptr: *mut c_void) {
30      unsafe { drop(Box::from_raw(ptr as *mut T)) };
31    }
32
33    Self {
34      key: TypeKey::of::<T>(),
35      ptr: Box::into_raw(Box::new(value)) as *mut c_void,
36      clone_fn: clone_it::<T>,
37      drop_fn: drop_it::<T>,
38    }
39  }
40
41  fn clone_value(&self) -> Self {
42    Self {
43      key: self.key,
44      ptr: (self.clone_fn)(self.ptr as *const c_void),
45      clone_fn: self.clone_fn,
46      drop_fn: self.drop_fn,
47    }
48  }
49
50  fn is<T: 'static>(&self) -> bool {
51    self.key.matches::<T>()
52  }
53
54  fn as_ref<T: 'static>(&self) -> Option<&T> {
55    if self.is::<T>() {
56      Some(unsafe { &*(self.ptr as *const T) })
57    } else {
58      None
59    }
60  }
61
62  fn as_mut<T: 'static>(&mut self) -> Option<&mut T> {
63    if self.is::<T>() {
64      Some(unsafe { &mut *(self.ptr as *mut T) })
65    } else {
66      None
67    }
68  }
69}
70
71impl Clone for PayloadValue {
72  fn clone(&self) -> Self {
73    self.clone_value()
74  }
75}
76
77impl Drop for PayloadValue {
78  fn drop(&mut self) {
79    if !self.ptr.is_null() {
80      (self.drop_fn)(self.ptr);
81      self.ptr = core::ptr::null_mut();
82    }
83  }
84}
85
86#[repr(C)]
87#[derive(StableAbi)]
88pub struct PayloadBox {
89  value: PayloadValue,
90}
91
92impl PayloadBox {
93  pub fn new<T: Clone + Send + Sync + 'static>(value: T) -> Self {
94    Self {
95      value: PayloadValue::new(value),
96    }
97  }
98
99  pub fn is<T: 'static>(&self) -> bool {
100    self.value.is::<T>()
101  }
102
103  pub fn as_this<T: 'static>(&self) -> Option<&T> {
104    self.value.as_ref::<T>()
105  }
106
107  pub fn as_this_mut<T: 'static>(&mut self) -> Option<&mut T> {
108    self.value.as_mut::<T>()
109  }
110
111  pub fn type_key(&self) -> TypeKey {
112    self.value.key
113  }
114}
115
116impl Clone for PayloadBox {
117  fn clone(&self) -> Self {
118    Self {
119      value: self.value.clone_value(),
120    }
121  }
122}
123
124impl fmt::Debug for PayloadBox {
125  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126    write!(f, "PayloadBox<{}>", self.value.key.name)
127  }
128}
129
130#[sabi_trait]
131pub trait PayloadParser: Send + Sync + 'static {
132  fn parse(&self, command: RStr<'_>, args: &Args) -> ROption<PayloadBox>;
133}
134
135pub type PayloadParserBox = PayloadParser_TO<RBox<()>>;