JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

So. Much. Work.

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨b05f964

⁨giterated-plugins/giterated-plugin/src/lib.rs⁩ - ⁨12137⁩ bytes
Raw
1 pub mod callback;
2 pub mod handle;
3 pub mod new_stack;
4 pub mod vtable;
5
6 #[macro_use]
7 extern crate tracing;
8
9 use std::{any::Any, fmt::Debug, mem::transmute, ptr::null_mut, sync::Arc};
10
11 use callback::{OperationHandlerCallback, SettingGetterCallback, ValueGetterCallback};
12 use dlopen2::wrapper::WrapperApi;
13 use giterated_models::{
14 object::GiteratedObject, operation::GiteratedOperation, settings::Setting,
15 value::GiteratedObjectValue,
16 };
17 use handle::PluginInitializationState;
18 use new_stack::{FFIPluginMeta, PluginState};
19
20 #[derive(WrapperApi)]
21 pub struct GiteratedPluginApi {
22 plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta,
23 load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable),
24 load_initialization_vtable: unsafe extern "C" fn(vtable: &InitializationVTable),
25 initialize: unsafe extern "C" fn() -> PluginState,
26 initialize_registration: unsafe extern "C" fn(
27 init_state: *mut PluginInitializationState,
28 ) -> *mut PluginInitializationState,
29 }
30
31 #[repr(C)]
32 pub struct FFIBox<T: ?Sized>(*mut T);
33
34 impl<T: ?Sized> FFIBox<T> {
35 pub fn from_box(src: Box<T>) -> Self {
36 Self(Box::into_raw(src))
37 }
38
39 pub fn untyped(self) -> FFIBox<()> {
40 FFIBox(self.0 as *mut ())
41 }
42 }
43
44 #[repr(C)]
45 pub struct FFIObject(&'static str);
46
47 #[repr(C)]
48 struct FFIOperationHandler(
49 for<'a> unsafe extern "C" fn(operation: FFIOperation<'a>) -> Result<FFIBox<[u8]>, FFIBox<[u8]>>,
50 );
51
52 #[repr(C)]
53 struct FFIOperation<'a> {
54 operation_name: &'a str,
55 object_name: &'a str,
56 object: FFIObject,
57 operation: &'a [u8],
58 }
59
60 #[derive(Clone, Copy)]
61 #[repr(C)]
62 pub struct OperationVTable {
63 pub serialize: unsafe extern "C" fn(AnyObject) -> Result<FFIBox<[u8]>, ()>,
64 pub deserialize: unsafe extern "C" fn(&[u8]) -> Result<AnyOperation, ()>,
65 pub is_same: unsafe extern "C" fn(AnyObject) -> bool,
66 pub serialize_success: unsafe extern "C" fn(()) -> Result<FFIBox<[u8]>, ()>,
67 pub serialize_failure: unsafe extern "C" fn(()) -> Result<FFIBox<[u8]>, ()>,
68 pub deserialize_success: unsafe extern "C" fn(&[u8]) -> Result<(), ()>,
69 pub deserialize_failure: unsafe extern "C" fn(&[u8]) -> Result<(), ()>,
70 }
71
72 impl OperationVTable {
73 pub fn new<O, T: IntoOperationVTable<O>>() -> Self {
74 Self {
75 serialize: T::serialize,
76 deserialize: T::deserialize,
77 is_same: T::is_same,
78 serialize_success: T::serialize_success,
79 serialize_failure: T::serialize_failure,
80 deserialize_success: T::deserialize_success,
81 deserialize_failure: T::deserialize_failure,
82 }
83 }
84 }
85
86 pub struct AnyOperation {
87 /// A pointer to the plugin-local object type. We are not capable of
88 /// knowing what this type is, we use the provided vtable.
89 inner: FFIBox<()>,
90 vtable: OperationVTable,
91 }
92
93 impl AnyOperation {
94 pub unsafe fn transmute_owned<T>(&mut self) -> Box<T> {
95 Box::from_raw(self.inner.0 as *mut T)
96 }
97
98 pub unsafe fn transmute_ref<T>(&self) -> &T {
99 let ptr: *const T = transmute(self.inner.0);
100
101 ptr.as_ref().unwrap()
102 }
103 }
104
105 #[repr(C)]
106 pub struct FFIValueChangeHandler();
107
108 #[derive(Clone, Copy)]
109 #[repr(C)]
110 pub struct ObjectVtable {
111 pub to_str: unsafe extern "C" fn(AnyObject) -> FFIBox<str>,
112 pub from_str: unsafe extern "C" fn(&str) -> Result<AnyObject, FFIBox<str>>,
113 pub home_uri: unsafe extern "C" fn(AnyObject) -> FFIBox<str>,
114 pub is_same: unsafe extern "C" fn(AnyObject) -> bool,
115 }
116
117 impl ObjectVtable {
118 pub const fn new<T: IntoObjectVTable>() -> Self {
119 Self {
120 to_str: T::to_str,
121 from_str: T::from_str,
122 home_uri: T::home_uri,
123 is_same: T::is_same,
124 }
125 }
126 }
127
128 #[repr(C)]
129 pub struct NewAnySetting {
130 /// A pointer to the plugin-local object type. We are not capable of
131 /// knowing what this type is, we use the provided vtable.
132 inner: FFIBox<()>,
133 vtable: SettingVtable,
134 }
135
136 impl NewAnySetting {
137 pub fn new<V: IntoSettingVTable>(value: V) -> Self {
138 Self {
139 inner: FFIBox::from_box(Box::new(value)).untyped(),
140 vtable: SettingVtable::new::<V>(),
141 }
142 }
143 }
144
145 #[derive(Clone, Copy)]
146 #[repr(C)]
147 pub struct SettingVtable {
148 pub deserialize: unsafe extern "C" fn(&[u8]) -> Result<(), ()>,
149 pub serialize: unsafe extern "C" fn(NewAnySetting) -> Result<FFIBox<[u8]>, ()>,
150 }
151
152 impl SettingVtable {
153 pub fn new<T: IntoSettingVTable>() -> Self {
154 Self {
155 deserialize: T::deserialize,
156 serialize: T::serialize,
157 }
158 }
159 }
160
161 #[repr(C)]
162 pub struct NewAnyValue {
163 /// A pointer to the plugin-local object type. We are not capable of
164 /// knowing what this type is, we use the provided vtable.
165 inner: FFIBox<()>,
166 vtable: ValueVTable,
167 }
168
169 impl NewAnyValue {
170 pub fn new<O, V: IntoValueVTable<O>>(value: V) -> Self {
171 NewAnyValue {
172 inner: FFIBox::from_box(Box::new(value)).untyped(),
173 vtable: ValueVTable::new::<O, V>(),
174 }
175 }
176 }
177
178 #[derive(Clone, Copy)]
179 #[repr(C)]
180 pub struct ValueVTable {
181 pub deserialize: unsafe extern "C" fn(&[u8]) -> Result<NewAnyValue, ()>,
182 pub serialize: unsafe extern "C" fn(NewAnyValue) -> Result<FFIBox<[u8]>, ()>,
183 }
184
185 impl ValueVTable {
186 pub fn new<O, T: IntoValueVTable<O>>() -> Self {
187 Self {
188 deserialize: T::deserialize,
189 serialize: T::serialize,
190 }
191 }
192 }
193
194 pub trait IntoObjectVTable {
195 unsafe extern "C" fn to_str(this: AnyObject) -> FFIBox<str>;
196 unsafe extern "C" fn from_str(src: &str) -> Result<AnyObject, FFIBox<str>>;
197 unsafe extern "C" fn home_uri(this: AnyObject) -> FFIBox<str>;
198 unsafe extern "C" fn is_same(other: AnyObject) -> bool;
199 }
200
201 impl<T: GiteratedObject + 'static> IntoObjectVTable for T {
202 unsafe extern "C" fn to_str(mut this: AnyObject) -> FFIBox<str> {
203 let this: &Box<T> = this.transmute_ref();
204
205 let result = this.to_string();
206
207 FFIBox::from_box(result.into_boxed_str())
208 }
209
210 unsafe extern "C" fn from_str(src: &str) -> Result<AnyObject, FFIBox<str>> {
211 let result = T::from_object_str(src).unwrap();
212
213 let any_object = AnyObject::new(result);
214
215 Ok(any_object)
216 }
217
218 unsafe extern "C" fn home_uri(this: AnyObject) -> FFIBox<str> {
219 todo!()
220 }
221
222 unsafe extern "C" fn is_same(other: AnyObject) -> bool {
223 todo!()
224 }
225 }
226
227 pub trait IntoOperationVTable<O> {
228 unsafe extern "C" fn serialize(this: AnyObject) -> Result<FFIBox<[u8]>, ()>;
229 unsafe extern "C" fn deserialize(src: &[u8]) -> Result<AnyOperation, ()>;
230 unsafe extern "C" fn is_same(this: AnyObject) -> bool;
231 unsafe extern "C" fn serialize_success(success: ()) -> Result<FFIBox<[u8]>, ()>;
232 unsafe extern "C" fn serialize_failure(failure: ()) -> Result<FFIBox<[u8]>, ()>;
233 unsafe extern "C" fn deserialize_success(src: &[u8]) -> Result<(), ()>;
234 unsafe extern "C" fn deserialize_failure(src: &[u8]) -> Result<(), ()>;
235 }
236
237 impl<O, D> IntoOperationVTable<O> for D
238 where
239 D: GiteratedOperation<O>,
240 O: GiteratedObject,
241 {
242 unsafe extern "C" fn serialize(this: AnyObject) -> Result<FFIBox<[u8]>, ()> {
243 todo!()
244 }
245
246 unsafe extern "C" fn deserialize(src: &[u8]) -> Result<AnyOperation, ()> {
247 let deserialized: D = serde_json::from_slice(src).unwrap();
248
249 Ok(AnyOperation {
250 inner: FFIBox::from_box(Box::new(deserialized)).untyped(),
251 vtable: OperationVTable::new::<O, D>(),
252 })
253 }
254
255 unsafe extern "C" fn is_same(this: AnyObject) -> bool {
256 todo!()
257 }
258
259 unsafe extern "C" fn serialize_success(success: ()) -> Result<FFIBox<[u8]>, ()> {
260 todo!()
261 }
262
263 unsafe extern "C" fn serialize_failure(failure: ()) -> Result<FFIBox<[u8]>, ()> {
264 todo!()
265 }
266
267 unsafe extern "C" fn deserialize_success(src: &[u8]) -> Result<(), ()> {
268 todo!()
269 }
270
271 unsafe extern "C" fn deserialize_failure(src: &[u8]) -> Result<(), ()> {
272 todo!()
273 }
274 }
275
276 pub trait IntoSettingVTable {
277 unsafe extern "C" fn deserialize(src: &[u8]) -> Result<(), ()>;
278 unsafe extern "C" fn serialize(this: NewAnySetting) -> Result<FFIBox<[u8]>, ()>;
279 }
280
281 impl<S> IntoSettingVTable for S
282 where
283 S: Setting,
284 {
285 unsafe extern "C" fn deserialize(src: &[u8]) -> Result<(), ()> {
286 todo!()
287 }
288
289 unsafe extern "C" fn serialize(this: NewAnySetting) -> Result<FFIBox<[u8]>, ()> {
290 todo!()
291 }
292 }
293
294 pub trait IntoValueVTable<O> {
295 unsafe extern "C" fn deserialize(src: &[u8]) -> Result<NewAnyValue, ()>;
296 unsafe extern "C" fn serialize(this: NewAnyValue) -> Result<FFIBox<[u8]>, ()>;
297 }
298
299 impl<O, V> IntoValueVTable<O> for V
300 where
301 O: GiteratedObject,
302 V: GiteratedObjectValue<Object = O>,
303 {
304 unsafe extern "C" fn deserialize(src: &[u8]) -> Result<NewAnyValue, ()> {
305 let _guard = trace_span!(
306 "deserialize value",
307 object = O::object_name(),
308 value = V::value_name()
309 );
310
311 trace!("Deserializing");
312 let deserialized: V = serde_json::from_slice(src).unwrap();
313
314 Ok(NewAnyValue {
315 inner: FFIBox::from_box(Box::new(deserialized)).untyped(),
316 vtable: ValueVTable::new::<O, V>(),
317 })
318 }
319
320 unsafe extern "C" fn serialize(this: NewAnyValue) -> Result<FFIBox<[u8]>, ()> {
321 todo!()
322 }
323 }
324
325 #[repr(C)]
326 pub struct AnyObject {
327 /// A pointer to the plugin-local object type. We are not capable of
328 /// knowing what this type is, we use the provided vtable.
329 inner: FFIBox<()>,
330 vtable: ObjectVtable,
331 }
332
333 impl AnyObject {
334 pub fn new<T: IntoObjectVTable>(inner: T) -> Self {
335 Self {
336 inner: FFIBox::from_box(Box::new(inner)).untyped(),
337 vtable: ObjectVtable::new::<T>(),
338 }
339 }
340 }
341
342 impl AnyObject {
343 pub unsafe fn transmute_owned<T>(&mut self) -> Box<T> {
344 Box::from_raw(self.inner.0 as *mut T)
345 }
346
347 pub unsafe fn transmute_ref<T>(&self) -> &T {
348 let ptr: *const T = transmute(self.inner.0);
349
350 ptr.as_ref().unwrap()
351 }
352 }
353
354 #[repr(C)]
355 pub struct FFISettingMeta();
356
357 #[repr(C)]
358 pub struct FFIValueMeta();
359
360 #[repr(C)]
361 pub struct HostVTable {
362 register_operation: unsafe extern "C" fn(&str, &str, FFIOperationHandler),
363 register_value_change: unsafe extern "C" fn(&str, &str, FFIValueChangeHandler),
364 register_object: unsafe extern "C" fn(&str, ObjectVtable),
365 register_setting: unsafe extern "C" fn(&str, &str, FFISettingMeta),
366 register_value: unsafe extern "C" fn(&str, &str, FFIValueMeta),
367 }
368
369 #[repr(C)]
370 #[derive(Clone, Copy)]
371 pub struct InitializationVTable {
372 pub register_value_change:
373 unsafe extern "C" fn(*mut PluginInitializationState, &str, &str, FFIValueChangeHandler),
374 pub register_object:
375 unsafe extern "C" fn(*mut PluginInitializationState, &'static str, ObjectVtable),
376 pub register_operation: unsafe extern "C" fn(
377 *mut PluginInitializationState,
378 &'static str,
379 &'static str,
380 OperationVTable,
381 ),
382 pub register_setting: unsafe extern "C" fn(
383 *mut PluginInitializationState,
384 &'static str,
385 &'static str,
386 SettingVtable,
387 ),
388 pub register_value: unsafe extern "C" fn(
389 *mut PluginInitializationState,
390 &'static str,
391 &'static str,
392 ValueVTable,
393 ),
394
395 pub operation_handler: unsafe extern "C" fn(
396 *mut PluginInitializationState,
397 &'static str,
398 &'static str,
399 OperationHandlerCallback,
400 ),
401
402 pub value_getter: unsafe extern "C" fn(
403 *mut PluginInitializationState,
404 &'static str,
405 &'static str,
406 ValueGetterCallback,
407 ),
408
409 pub setting_getter: unsafe extern "C" fn(
410 *mut PluginInitializationState,
411 &'static str,
412 &'static str,
413 SettingGetterCallback,
414 ),
415 }
416
417 impl Debug for InitializationVTable {
418 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419 f.debug_struct("InitializationVTable").finish()
420 }
421 }
422
423 unsafe impl Sync for InitializationVTable {}
424 unsafe impl Send for InitializationVTable {}
425