MOre pre vtable changes
parent: tbd commit: 9cfa135
Showing 17 changed files with 387 insertions and 176 deletions
.vscode/launch.json
@@ -44,6 +44,24 @@ | ||
44 | 44 | { |
45 | 45 | "type": "lldb", |
46 | 46 | "request": "launch", |
47 | "name": "Debug executable 'example-plugin'", | |
48 | "cargo": { | |
49 | "args": [ | |
50 | "build", | |
51 | "--bin=example-plugin", | |
52 | "--package=example-plugin" | |
53 | ], | |
54 | "filter": { | |
55 | "name": "example-plugin", | |
56 | "kind": "bin" | |
57 | } | |
58 | }, | |
59 | "args": [], | |
60 | "cwd": "${workspaceFolder}" | |
61 | }, | |
62 | { | |
63 | "type": "lldb", | |
64 | "request": "launch", | |
47 | 65 | "name": "Debug unit tests in executable 'giterated-daemon'", |
48 | 66 | "cargo": { |
49 | 67 | "args": [ |
Cargo.lock
@@ -686,6 +686,10 @@ dependencies = [ | ||
686 | 686 | ] |
687 | 687 | |
688 | 688 | [[package]] |
689 | name = "giterated-abi" | |
690 | version = "0.1.0" | |
691 | ||
692 | [[package]] | |
689 | 693 | name = "giterated-backend" |
690 | 694 | version = "0.1.0" |
691 | 695 | dependencies = [ |
@@ -789,6 +793,7 @@ dependencies = [ | ||
789 | 793 | "async-trait", |
790 | 794 | "dlopen2", |
791 | 795 | "futures-util", |
796 | "giterated-abi", | |
792 | 797 | "giterated-models", |
793 | 798 | "giterated-static-runtime", |
794 | 799 | "semver", |
Cargo.toml
@@ -1,5 +1,5 @@ | ||
1 | 1 | [workspace] |
2 | members = [ | |
2 | members = [ "giterated-abi", | |
3 | 3 | "giterated-daemon", |
4 | 4 | "giterated-models", |
5 | 5 | "giterated-plugin", |
@@ -9,4 +9,4 @@ members = [ | ||
9 | 9 | "plugins/giterated-backend", |
10 | 10 | "plugins/giterated-issues", |
11 | 11 | "plugins/giterated-protocol" |
12 | ] | |
12 | \ No newline at end of file | |
12 | ] |
giterated-models/src/instance/mod.rs
@@ -42,7 +42,7 @@ impl GiteratedObject for Instance { | ||
42 | 42 | } |
43 | 43 | |
44 | 44 | fn from_object_str(object_str: &str) -> Result<Self, anyhow::Error> { |
45 | Ok(Instance::from_str(object_str).unwrap()) | |
45 | Ok(Instance::from_str(object_str)?) | |
46 | 46 | } |
47 | 47 | |
48 | 48 | fn home_uri(&self) -> String { |
giterated-models/src/object/operations.rs
@@ -26,6 +26,8 @@ impl GiteratedOperation<Instance> for ObjectRequest { | ||
26 | 26 | pub enum ObjectRequestError { |
27 | 27 | #[error("error decoding the object")] |
28 | 28 | Deserialization(String), |
29 | #[error("invalid object type")] | |
30 | Invalid, | |
29 | 31 | } |
30 | 32 | |
31 | 33 | #[derive(Clone, Debug, Serialize, Deserialize)] |
giterated-plugin/Cargo.toml
@@ -12,6 +12,7 @@ thiserror = "1" | ||
12 | 12 | tracing = "0.1" |
13 | 13 | giterated-models = { path = "../giterated-models" } |
14 | 14 | giterated-static-runtime = { path = "giterated-static-runtime" } |
15 | giterated-abi = { path = "../giterated-abi" } | |
15 | 16 | semver = "*" |
16 | 17 | serde_json = "1.0" |
17 | 18 | async-trait = "0.1" |
giterated-plugin/giterated-static-runtime/src/lib.rs
@@ -14,3 +14,13 @@ pub unsafe fn initialize_runtime(runtime_pointer: *mut ()) { | ||
14 | 14 | pub unsafe fn get_runtime_reference() -> NonNull<()> { |
15 | 15 | GITERATED_RUNTIME.assume_init_read().0 |
16 | 16 | } |
17 | ||
18 | static mut GITERATED_TYPE_METADATA: MaybeUninit<RuntimePointer> = MaybeUninit::zeroed(); | |
19 | ||
20 | pub unsafe fn initialize_type_metadata(runtime_pointer: *mut ()) { | |
21 | GITERATED_TYPE_METADATA.write(RuntimePointer(NonNull::new(runtime_pointer).unwrap())); | |
22 | } | |
23 | ||
24 | pub unsafe fn get_type_metadata_reference() -> NonNull<()> { | |
25 | GITERATED_TYPE_METADATA.assume_init_read().0 | |
26 | } |
giterated-plugin/src/callback/mod.rs
@@ -14,7 +14,11 @@ pub use value::*; | ||
14 | 14 | mod setting; |
15 | 15 | pub use setting::*; |
16 | 16 | |
17 | use crate::{vtable::RuntimeVTable, AnyObject, AnyOperation}; | |
17 | use crate::{ | |
18 | new_stack::{PluginState, Runtime}, | |
19 | vtable::RuntimeVTable, | |
20 | AnyObject, AnyOperation, | |
21 | }; | |
18 | 22 | |
19 | 23 | /// A container for a callback pointer, used to provide an internal callback function or |
20 | 24 | /// state to a plugin when performing a callback. |
@@ -32,16 +36,21 @@ impl CallbackPtr { | ||
32 | 36 | #[repr(C)] |
33 | 37 | pub struct RuntimeState { |
34 | 38 | pub vtable: RuntimeVTable, |
35 | pub operation_state: OperationState, | |
36 | 39 | } |
37 | 40 | |
38 | 41 | impl RuntimeState { |
39 | 42 | pub unsafe fn from_static() -> Self { |
40 | 43 | let runtime = giterated_static_runtime::get_runtime_reference(); |
41 | 44 | |
42 | let runtime = runtime.cast::<Box<RuntimeState>>().as_ref(); | |
45 | let runtime = runtime.cast::<Box<Runtime>>().as_ref(); | |
46 | ||
47 | runtime.state() | |
48 | } | |
49 | ||
50 | pub unsafe fn runtime_state() -> PluginState { | |
51 | let runtime = giterated_static_runtime::get_runtime_reference(); | |
43 | 52 | |
44 | *runtime.clone() | |
53 | PluginState::from_raw_ptr(giterated_static_runtime::get_runtime_reference().as_ptr()) | |
45 | 54 | } |
46 | 55 | } |
47 | 56 | |
@@ -68,9 +77,21 @@ impl ObjectBackend for RuntimeState { | ||
68 | 77 | |
69 | 78 | async fn get_object<O: GiteratedObject + Debug + 'static>( |
70 | 79 | &self, |
71 | _object_str: &str, | |
72 | _operation_state: &OperationState, | |
80 | object_str: &str, | |
81 | operation_state: &OperationState, | |
73 | 82 | ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> { |
74 | todo!() | |
83 | let object = unsafe { | |
84 | (self.vtable.get_object)( | |
85 | Self::runtime_state(), | |
86 | object_str, | |
87 | &mut operation_state.clone(), | |
88 | ) | |
89 | }?; | |
90 | ||
91 | let object = unsafe { object.cast::<O>() }; | |
92 | ||
93 | panic!("object casted"); | |
94 | ||
95 | Ok(unsafe { Object::new_unchecked(object, self.clone()) }) | |
75 | 96 | } |
76 | 97 | } |
giterated-plugin/src/future.rs
@@ -1,67 +1,31 @@ | ||
1 | 1 | use futures_util::future::BoxFuture; |
2 | 2 | use futures_util::FutureExt; |
3 | use giterated_abi::{FfiFuture, FfiValue, FfiValueMut, RuntimeFuturePoll}; | |
3 | 4 | use std::{ |
4 | 5 | cell::UnsafeCell, |
5 | 6 | future::Future, |
6 | 7 | marker::PhantomData, |
8 | mem::transmute, | |
7 | 9 | task::{Context, RawWaker, RawWakerVTable, Waker}, |
8 | 10 | }; |
9 | 11 | |
10 | 12 | use crate::{callback::RuntimeState, new_stack::PluginState, FFIBox}; |
11 | 13 | |
12 | /// Future type for futures within the Runtime. | |
13 | /// | |
14 | /// Allows for plugins to spawn futures on the runtime. | |
15 | #[derive(Clone)] | |
16 | #[repr(C)] | |
17 | pub struct RuntimeFuture<Output> { | |
18 | /// The plugin's poll function, provided with the poll state for the future. | |
19 | poll_fn: unsafe extern "C" fn(*const RuntimeFuture<()>, PluginState) -> RuntimeFuturePoll, | |
20 | /// The function to wake the future, should only be called when the future is ready to be polled. | |
21 | wake_fn: Option<unsafe extern "C" fn(*const RuntimeFuture<()>, PluginState)>, | |
22 | ||
23 | /// The inner value that the owning plugin can use to poll the future | |
24 | poll_state: PluginState, | |
25 | /// The waker that the plugin uses for notification of the future's completion | |
26 | waker_state: Option<PluginState>, | |
27 | ||
28 | /// Whether its safe for the plugin to poll this future, panic if we think | |
29 | /// we're supposed to poll and this is not set to `true`. | |
30 | can_poll: bool, | |
31 | ||
32 | _output_marker: PhantomData<Output>, | |
33 | } | |
34 | ||
35 | unsafe impl<Output> Send for RuntimeFuture<Output> where Output: Send {} | |
36 | unsafe impl<Output> Sync for RuntimeFuture<Output> where Output: Sync {} | |
37 | ||
38 | 14 | #[repr(C)] |
39 | 15 | pub struct RuntimeWakerCallback { |
40 | 16 | callback: PluginState, |
41 | 17 | waker_func: unsafe extern "C" fn(PluginState), |
42 | 18 | } |
43 | 19 | |
44 | #[repr(C)] | |
45 | pub enum RuntimeFuturePoll { | |
46 | Ready(FFIBox<()>), | |
47 | Pending, | |
48 | } | |
49 | ||
50 | 20 | pub struct WakerState { |
51 | 21 | waker: Waker, |
52 | 22 | } |
53 | 23 | |
54 | impl<Output> RuntimeFuture<Output> { | |
55 | pub(crate) unsafe fn poll(&mut self) -> RuntimeFuturePoll { | |
56 | todo!() | |
57 | } | |
58 | } | |
59 | ||
60 | 24 | unsafe extern "C" fn wake(_waker: PluginState) {} |
61 | 25 | |
62 | 26 | pub struct LocalRuntimeFuture<Output> { |
63 | 27 | inner: BoxFuture<'static, Output>, |
64 | runtime_future: UnsafeCell<RuntimeFuture<Output>>, | |
28 | runtime_future: UnsafeCell<FfiFuture<Output>>, | |
65 | 29 | } |
66 | 30 | |
67 | 31 | unsafe impl<Output> Send for LocalRuntimeFuture<Output> where Output: Send {} |
@@ -70,7 +34,7 @@ unsafe impl<Output> Sync for LocalRuntimeFuture<Output> where Output: Sync {} | ||
70 | 34 | impl<Output> LocalRuntimeFuture<Output> { |
71 | 35 | pub fn finalize(self) {} |
72 | 36 | |
73 | pub fn into_runtime(&self) -> RuntimeFuture<Output> { | |
37 | pub fn into_runtime(&self) -> FfiFuture<Output> { | |
74 | 38 | todo!() |
75 | 39 | } |
76 | 40 | } |
@@ -93,25 +57,19 @@ impl RuntimeFuturesExt for RuntimeState { | ||
93 | 57 | FFIBox::from_box(Box::new(result)).untyped() |
94 | 58 | }; |
95 | 59 | |
96 | let runtime_future = RuntimeFuture { | |
97 | poll_fn: poll_local, | |
98 | wake_fn: None, | |
99 | poll_state: PluginState::from(type_eraser.boxed()), | |
100 | waker_state: None, | |
101 | can_poll: true, | |
102 | _output_marker: PhantomData, | |
103 | }; | |
60 | let runtime_future = unsafe { FfiFuture::from_raw(poll_local, type_eraser.boxed()) }; | |
104 | 61 | |
105 | runtime_future | |
62 | RuntimeFuture(runtime_future) | |
106 | 63 | } |
107 | 64 | } |
108 | 65 | |
109 | 66 | unsafe extern "C" fn poll_local( |
110 | _future: *const RuntimeFuture<()>, | |
111 | mut future_state: PluginState, | |
67 | _future: FfiValueMut<FfiFuture<()>>, | |
68 | mut future_state: FfiValueMut<()>, | |
112 | 69 | ) -> RuntimeFuturePoll { |
113 | let mut future: Box<BoxFuture<'static, FFIBox<()>>> = future_state.transmute_owned(); | |
114 | let runtime_future = future.as_ref(); | |
70 | let mut future_state: FfiValueMut<BoxFuture<'static, FfiValue<()>>> = transmute(future_state); | |
71 | ||
72 | let runtime_future = future_state.as_ref(); | |
115 | 73 | |
116 | 74 | let raw_waker = RawWaker::new( |
117 | 75 | Box::into_raw(Box::new(runtime_future)) as *const (), |
@@ -121,13 +79,7 @@ unsafe extern "C" fn poll_local( | ||
121 | 79 | let waker = unsafe { Waker::from_raw(raw_waker) }; |
122 | 80 | |
123 | 81 | // SAFETY: Pretty sure this has to be static lol |
124 | let poll_result = future.poll_unpin(&mut Context::from_waker(&waker)); | |
125 | ||
126 | #[allow(unused_assignments)] | |
127 | { | |
128 | // This is meant to communicate with the compiler the lifecycle of the object | |
129 | future_state = PluginState::from_raw(future); | |
130 | } | |
82 | let poll_result = future_state.poll_unpin(&mut Context::from_waker(&waker)); | |
131 | 83 | |
132 | 84 | match poll_result { |
133 | 85 | std::task::Poll::Ready(result) => RuntimeFuturePoll::Ready(result), |
@@ -162,6 +114,9 @@ mod runtime_waker_vtable { | ||
162 | 114 | } |
163 | 115 | } |
164 | 116 | |
117 | #[repr(transparent)] | |
118 | pub struct RuntimeFuture<Output>(FfiFuture<Output>); | |
119 | ||
165 | 120 | /// Allows for a remote future to be polled on the target. |
166 | 121 | /// |
167 | 122 | /// The target can be the host or a plugin, but the future should only be polled by one |
@@ -179,25 +134,19 @@ impl<Output: Unpin> Future for RuntimeFuture<Output> { | ||
179 | 134 | |
180 | 135 | let waker_state = PluginState::from(waker_state); |
181 | 136 | |
182 | self.waker_state = Some(waker_state); | |
183 | self.wake_fn = Some(wake_local); | |
137 | unsafe { self.0.write_waker(wake_local, waker_state) }; | |
184 | 138 | |
185 | match unsafe { | |
186 | (self.poll_fn)( | |
187 | &*self as *const RuntimeFuture<_> as *const RuntimeFuture<()>, | |
188 | self.poll_state, | |
189 | ) | |
190 | } { | |
139 | match unsafe { self.0.poll() } { | |
191 | 140 | RuntimeFuturePoll::Ready(result) => { |
192 | let result: Output = unsafe { *result.retype::<Output>().into_box() }; | |
141 | let result: FfiValue<Output> = unsafe { transmute(result) }; | |
193 | 142 | |
194 | std::task::Poll::Ready(result) | |
143 | std::task::Poll::Ready(result.take()) | |
195 | 144 | } |
196 | 145 | RuntimeFuturePoll::Pending => std::task::Poll::Pending, |
197 | 146 | } |
198 | 147 | } |
199 | 148 | } |
200 | 149 | |
201 | unsafe extern "C" fn wake_local(_future: *const RuntimeFuture<()>, _waker_state: PluginState) { | |
150 | unsafe extern "C" fn wake_local(future: FfiValueMut<FfiFuture<()>>, state: FfiValueMut<()>) { | |
202 | 151 | todo!() |
203 | 152 | } |
giterated-plugin/src/handle.rs
@@ -2,6 +2,7 @@ use std::{collections::HashMap, marker::PhantomData, sync::Arc}; | ||
2 | 2 | |
3 | 3 | use anyhow::Error; |
4 | 4 | use dlopen2::wrapper::Container; |
5 | use giterated_models::operation::OperationState; | |
5 | 6 | use semver::Version; |
6 | 7 | use tracing::{debug, trace}; |
7 | 8 | |
@@ -40,6 +41,10 @@ impl PluginHandle { | ||
40 | 41 | |
41 | 42 | let initalization = Self::initialize_registration(&mut handle)?; |
42 | 43 | |
44 | let type_metadata = Box::new(initalization.type_metadata.clone()); | |
45 | ||
46 | unsafe { handle.load_type_metadata(unsafe { Box::into_raw(type_metadata).cast() }) }; | |
47 | ||
43 | 48 | trace!( |
44 | 49 | "Loaded plugin {} (Version: {})", |
45 | 50 | metadata.name, |
giterated-plugin/src/lib.rs
@@ -9,6 +9,8 @@ pub mod vtable; | ||
9 | 9 | #[macro_use] |
10 | 10 | extern crate tracing; |
11 | 11 | |
12 | use std::{marker::PhantomData, mem::forget}; | |
13 | ||
12 | 14 | use callback::RuntimeState; |
13 | 15 | use dlopen2::wrapper::WrapperApi; |
14 | 16 | |
@@ -27,6 +29,7 @@ pub struct GiteratedPluginApi { | ||
27 | 29 | initialize_registration: unsafe extern "C" fn( |
28 | 30 | init_state: *mut PluginInitializationState, |
29 | 31 | ) -> *mut PluginInitializationState, |
32 | load_type_metadata: unsafe extern "C" fn(metadata: *mut ()), | |
30 | 33 | } |
31 | 34 | |
32 | 35 | #[repr(C)] |
@@ -56,7 +59,11 @@ impl<T: ?Sized> FFIBox<T> { | ||
56 | 59 | |
57 | 60 | impl ToString for FFIBox<str> { |
58 | 61 | fn to_string(&self) -> String { |
59 | todo!() | |
62 | let slice: Box<[u8]> = unsafe { Box::from_raw(self.0.clone() as *mut _) }; | |
63 | ||
64 | let string = unsafe { std::str::from_boxed_utf8_unchecked(slice) }; | |
65 | ||
66 | String::from(string) | |
60 | 67 | } |
61 | 68 | } |
62 | 69 | |
@@ -73,3 +80,100 @@ impl<T: ?Sized> std::ops::Deref for FFIBox<T> { | ||
73 | 80 | unsafe { self.0.as_ref() }.unwrap() |
74 | 81 | } |
75 | 82 | } |
83 | ||
84 | #[repr(transparent)] | |
85 | pub struct FFI<T, Ownership: FfiOwnershipDrop> { | |
86 | /// Can either be a pointer to `FFIData<T>` or to `T` | |
87 | /// depending on the ownership of the FFI reference. | |
88 | inner: *const (), | |
89 | _marker: PhantomData<(T, Ownership)>, | |
90 | } | |
91 | ||
92 | #[repr(C)] | |
93 | pub struct FFIData<T> { | |
94 | /// SAFETY: THIS VALUE COULD BE NULL. | |
95 | drop_fn: *const extern "C" fn(*const FFIData<T>), | |
96 | drop_state: *const (), | |
97 | ||
98 | allocation: T, | |
99 | } | |
100 | ||
101 | pub struct Owned; | |
102 | ||
103 | impl FfiOwnershipDrop for Owned {} | |
104 | ||
105 | pub struct StackOwned; | |
106 | ||
107 | impl FfiOwnershipDrop for StackOwned {} | |
108 | ||
109 | trait FfiOwnershipDrop {} | |
110 | ||
111 | pub struct PinnedRef; | |
112 | ||
113 | impl FfiOwnershipDrop for PinnedRef {} | |
114 | ||
115 | pub struct PinnedMut; | |
116 | ||
117 | impl FfiOwnershipDrop for PinnedMut {} | |
118 | ||
119 | impl<T> FFI<T, Owned> { | |
120 | pub fn place_heap(value: T) -> FFI<T, Owned> { | |
121 | todo!() | |
122 | } | |
123 | ||
124 | pub fn ref_guard<'a>(&'a self) -> StackPinnedGuard<'a, T> { | |
125 | todo!() | |
126 | } | |
127 | } | |
128 | ||
129 | impl<T> FFI<T, StackOwned> { | |
130 | pub fn place_stack<'a>(value: T) -> StackPinned<'a, T> { | |
131 | todo!() | |
132 | } | |
133 | } | |
134 | ||
135 | pub struct StackPinned<'a, T> { | |
136 | descriptor: FFIData<T>, | |
137 | _lifetime: PhantomData<&'a ()>, | |
138 | } | |
139 | ||
140 | impl<'a, T> StackPinned<'a, T> { | |
141 | pub unsafe fn grant_ref(&self) -> FFI<T, PinnedRef> { | |
142 | todo!() | |
143 | } | |
144 | } | |
145 | ||
146 | pub struct StackPinnedGuard<'a, T> { | |
147 | pinned_owned: &'a FFI<T, Owned>, | |
148 | } | |
149 | ||
150 | impl<'a, T> StackPinnedGuard<'a, T> { | |
151 | pub unsafe fn grant_ref(&self) -> FFI<T, PinnedRef> { | |
152 | todo!() | |
153 | } | |
154 | } | |
155 | ||
156 | impl<T, O: FfiOwnershipDrop> Drop for FFI<T, O> { | |
157 | fn drop(&mut self) { | |
158 | todo!() | |
159 | } | |
160 | } | |
161 | ||
162 | pub struct FFISlice<T: ?Sized> { | |
163 | len: usize, | |
164 | slice: T, | |
165 | } | |
166 | ||
167 | fn example() { | |
168 | let stack_ffi_value = FFI::place_stack(()); | |
169 | ||
170 | let stack_ffi_ref = unsafe { stack_ffi_value.grant_ref() }; | |
171 | ||
172 | let foo = stack_ffi_ref; | |
173 | ||
174 | let heap_ffi_value = FFI::place_heap(()); | |
175 | ||
176 | let heap_ffi_ref_guard = heap_ffi_value.ref_guard(); | |
177 | ||
178 | let heap_ffi_ref = unsafe { heap_ffi_ref_guard.grant_ref() }; | |
179 | } |
giterated-plugin/src/new_stack/mod.rs
@@ -6,7 +6,7 @@ use std::{collections::HashMap, fmt::Debug, mem::transmute, ptr::null_mut, sync: | ||
6 | 6 | |
7 | 7 | use giterated_models::{ |
8 | 8 | error::OperationError, |
9 | object::GiteratedObject, | |
9 | object::{GiteratedObject, ObjectRequestError}, | |
10 | 10 | operation::{GiteratedOperation, OperationState}, |
11 | 11 | }; |
12 | 12 | use semver::Version; |
@@ -38,7 +38,7 @@ impl<S> std::ops::Deref for State<S> { | ||
38 | 38 | } |
39 | 39 | } |
40 | 40 | |
41 | #[derive(Default)] | |
41 | #[derive(Default, Clone)] | |
42 | 42 | pub struct TypeMetadata { |
43 | 43 | pub objects: HashMap<&'static str, ObjectVtable>, |
44 | 44 | pub operations: HashMap<ObjectOperationPair<'static>, OperationVTable>, |
@@ -47,6 +47,12 @@ pub struct TypeMetadata { | ||
47 | 47 | } |
48 | 48 | |
49 | 49 | impl TypeMetadata { |
50 | pub unsafe fn from_static() -> &'static Self { | |
51 | giterated_static_runtime::get_type_metadata_reference() | |
52 | .cast::<TypeMetadata>() | |
53 | .as_ref() | |
54 | } | |
55 | ||
50 | 56 | pub fn register_object(&mut self, object_kind: &'static str, vtable: ObjectVtable) { |
51 | 57 | trace!("Registering type metadata for {}", object_kind); |
52 | 58 | |
@@ -182,22 +188,32 @@ impl PluginState { | ||
182 | 188 | } |
183 | 189 | } |
184 | 190 | |
185 | pub unsafe fn from_raw<S>(raw: Box<S>) -> Self { | |
191 | pub unsafe fn from_box<S>(raw: Box<S>) -> Self { | |
186 | 192 | Self { |
187 | 193 | inner: Box::into_raw(raw) as *mut _, |
188 | 194 | } |
189 | 195 | } |
190 | 196 | |
197 | pub unsafe fn from_raw_ptr(raw: *const ()) -> Self { | |
198 | Self { | |
199 | inner: raw as *mut (), | |
200 | } | |
201 | } | |
202 | ||
191 | 203 | pub fn null() -> Self { |
192 | 204 | Self { inner: null_mut() } |
193 | 205 | } |
194 | 206 | } |
195 | 207 | |
196 | 208 | pub struct Runtime { |
197 | plugins: Vec<(PluginMeta, PluginHandle)>, | |
209 | plugins: Vec<PluginHandle>, | |
198 | 210 | handlers: RuntimeHandlers, |
199 | 211 | } |
200 | 212 | |
213 | pub struct FfiRuntimeMetadata { | |
214 | runtime: PluginState, | |
215 | } | |
216 | ||
201 | 217 | impl IntoRuntimeVtable for Runtime { |
202 | 218 | unsafe extern "C" fn handle( |
203 | 219 | _this: PluginState, |
@@ -209,6 +225,38 @@ impl IntoRuntimeVtable for Runtime { | ||
209 | 225 | ) -> RuntimeFuture<Result<AnySuccess, OperationError<AnyFailure>>> { |
210 | 226 | todo!() |
211 | 227 | } |
228 | ||
229 | unsafe extern "C" fn get_object( | |
230 | this: PluginState, | |
231 | object_str: &str, | |
232 | operation_state: *mut OperationState, | |
233 | ) -> Result<crate::AnyObject, OperationError<giterated_models::object::ObjectRequestError>> | |
234 | { | |
235 | let runtime_state = unsafe { RuntimeState::from_static() }; | |
236 | ||
237 | let type_metada = runtime_state | |
238 | .vtable | |
239 | .type_metadata | |
240 | .as_ref() | |
241 | .unwrap_or_else(|| { | |
242 | let runtime = this.transmute_ref::<Runtime>(); | |
243 | ||
244 | &runtime | |
245 | .plugins | |
246 | .first() | |
247 | .unwrap() | |
248 | .initialization | |
249 | .type_metadata | |
250 | }); | |
251 | ||
252 | for (object_type, object_vtable) in &type_metada.objects { | |
253 | if let Ok(object) = (object_vtable.from_str)(object_str) { | |
254 | return Ok(object); | |
255 | } | |
256 | } | |
257 | ||
258 | Err(OperationError::Operation(ObjectRequestError::Invalid)) | |
259 | } | |
212 | 260 | } |
213 | 261 | |
214 | 262 | impl Runtime { |
@@ -219,13 +267,14 @@ impl Runtime { | ||
219 | 267 | }) |
220 | 268 | } |
221 | 269 | |
222 | pub fn state(self: &Box<Self>, operation_state: &OperationState) -> RuntimeState { | |
270 | pub fn state(self: &Box<Self>) -> RuntimeState { | |
223 | 271 | RuntimeState { |
224 | 272 | vtable: RuntimeVTable { |
225 | 273 | runtime: PluginState::from(self), |
226 | 274 | handle_fn: <Runtime as IntoRuntimeVtable>::handle, |
275 | get_object: <Runtime as IntoRuntimeVtable>::get_object, | |
276 | type_metadata: unsafe { TypeMetadata::from_static() }, | |
227 | 277 | }, |
228 | operation_state: operation_state.clone(), | |
229 | 278 | } |
230 | 279 | } |
231 | 280 | |
@@ -279,6 +328,8 @@ impl Runtime { | ||
279 | 328 | |
280 | 329 | trace!("Insertion of setting handler successful") |
281 | 330 | } |
331 | ||
332 | self.plugins.push(plugin); | |
282 | 333 | } |
283 | 334 | |
284 | 335 | pub fn init(self: Box<Self>) { |
giterated-plugin/src/vtable/object.rs
@@ -1,61 +1,63 @@ | ||
1 | 1 | use std::{mem::transmute, str::FromStr}; |
2 | 2 | |
3 | use giterated_abi::vtable::IntoObjectVTable; | |
3 | 4 | use giterated_models::object::GiteratedObject; |
4 | 5 | |
5 | 6 | use crate::FFIBox; |
6 | 7 | |
7 | #[derive(Clone, Copy)] | |
8 | #[repr(C)] | |
9 | pub struct ObjectVtable { | |
10 | object_kind: *const u8, | |
11 | object_kind_len: usize, | |
12 | pub to_str: unsafe extern "C" fn(&AnyObject) -> FFIBox<str>, | |
13 | pub from_str: unsafe extern "C" fn(&str) -> Result<AnyObject, FFIBox<str>>, | |
14 | pub home_uri: unsafe extern "C" fn(&AnyObject) -> FFIBox<str>, | |
15 | pub is_same: unsafe extern "C" fn(&AnyObject) -> bool, | |
16 | } | |
17 | ||
18 | impl ObjectVtable { | |
19 | pub fn new<T: IntoObjectVTable>() -> Self { | |
20 | let object_kind = T::object_kind().as_ptr(); | |
21 | let object_kind_len = T::object_kind().len(); | |
22 | ||
23 | Self { | |
24 | to_str: T::to_str, | |
25 | from_str: T::from_str, | |
26 | home_uri: T::home_uri, | |
27 | is_same: T::is_same, | |
28 | object_kind, | |
29 | object_kind_len, | |
30 | } | |
31 | } | |
32 | ||
33 | pub fn kind(&self) -> &'static str { | |
34 | let slice = unsafe { std::slice::from_raw_parts(self.object_kind, self.object_kind_len) }; | |
35 | ||
36 | std::str::from_utf8(slice).unwrap() | |
37 | } | |
38 | } | |
39 | ||
40 | pub trait IntoObjectVTable { | |
41 | fn object_kind() -> &'static str; | |
42 | unsafe extern "C" fn to_str(this: &AnyObject) -> FFIBox<str>; | |
43 | unsafe extern "C" fn from_str(src: &str) -> Result<AnyObject, FFIBox<str>>; | |
44 | unsafe extern "C" fn home_uri(this: &AnyObject) -> FFIBox<str>; | |
45 | unsafe extern "C" fn is_same(other: &AnyObject) -> bool; | |
46 | } | |
8 | // #[derive(Clone, Copy)] | |
9 | // #[repr(C)] | |
10 | // pub struct ObjectVtable { | |
11 | // object_kind: *const u8, | |
12 | // object_kind_len: usize, | |
13 | // pub to_str: unsafe extern "C" fn(&AnyObject) -> FFIBox<[u8]>, | |
14 | // pub from_str: unsafe extern "C" fn(&str) -> Result<AnyObject, FFIBox<str>>, | |
15 | // pub home_uri: unsafe extern "C" fn(&AnyObject) -> FFIBox<str>, | |
16 | // pub is_same: unsafe extern "C" fn(&AnyObject) -> bool, | |
17 | // } | |
18 | ||
19 | // impl ObjectVtable { | |
20 | // pub fn new<T: IntoObjectVTable>() -> Self { | |
21 | // let object_kind = T::object_kind().as_ptr(); | |
22 | // let object_kind_len = T::object_kind().len(); | |
23 | ||
24 | // Self { | |
25 | // to_str: T::to_str, | |
26 | // from_str: T::from_str, | |
27 | // home_uri: T::home_uri, | |
28 | // is_same: T::is_same, | |
29 | // object_kind, | |
30 | // object_kind_len, | |
31 | // } | |
32 | // } | |
33 | ||
34 | // pub fn kind(&self) -> &'static str { | |
35 | // let slice = unsafe { std::slice::from_raw_parts(self.object_kind, self.object_kind_len) }; | |
36 | ||
37 | // std::str::from_utf8(slice).unwrap() | |
38 | // } | |
39 | // } | |
40 | ||
41 | // pub trait IntoObjectVTable { | |
42 | // fn object_kind() -> &'static str; | |
43 | // unsafe extern "C" fn to_str(this: &AnyObject) -> FFIBox<[u8]>; | |
44 | // unsafe extern "C" fn from_str(src: &str) -> Result<AnyObject, FFIBox<str>>; | |
45 | // unsafe extern "C" fn home_uri(this: &AnyObject) -> FFIBox<str>; | |
46 | // unsafe extern "C" fn is_same(other: &AnyObject) -> bool; | |
47 | // } | |
47 | 48 | |
48 | 49 | impl<T: GiteratedObject + 'static> IntoObjectVTable for T { |
49 | unsafe extern "C" fn to_str(this: &AnyObject) -> FFIBox<str> { | |
50 | unsafe extern "C" fn to_str(this: &AnyObject) -> FFIBox<[u8]> { | |
50 | 51 | let this: &Box<T> = this.transmute_ref(); |
51 | 52 | |
52 | 53 | let result = this.to_string(); |
53 | 54 | |
54 | FFIBox::from_box(result.into_boxed_str()) | |
55 | FFIBox::from_box(result.into_bytes().into_boxed_slice()) | |
55 | 56 | } |
56 | 57 | |
57 | 58 | unsafe extern "C" fn from_str(src: &str) -> Result<AnyObject, FFIBox<str>> { |
58 | let result = T::from_object_str(src).unwrap(); | |
59 | let result = T::from_object_str(src) | |
60 | .map_err(|err| FFIBox::from_box(err.to_string().into_boxed_str()))?; | |
59 | 61 | |
60 | 62 | let any_object = AnyObject::new(result); |
61 | 63 | |
@@ -66,58 +68,63 @@ impl<T: GiteratedObject + 'static> IntoObjectVTable for T { | ||
66 | 68 | todo!() |
67 | 69 | } |
68 | 70 | |
69 | unsafe extern "C" fn is_same(_other: &AnyObject) -> bool { | |
70 | todo!() | |
71 | } | |
72 | ||
73 | fn object_kind() -> &'static str { | |
71 | fn object_kind() -> &'static std::ffi::CStr { | |
74 | 72 | <T as GiteratedObject>::object_name() |
75 | 73 | } |
74 | ||
75 | // unsafe extern "C" fn is_same(_other: &AnyObject) -> bool { | |
76 | // todo!() | |
77 | // } | |
76 | 78 | } |
77 | 79 | |
78 | #[repr(C)] | |
79 | pub struct AnyObject { | |
80 | /// A pointer to the plugin-local object type. We are not capable of | |
81 | /// knowing what this type is, we use the provided vtable. | |
82 | inner: FFIBox<()>, | |
83 | vtable: ObjectVtable, | |
84 | } | |
85 | 80 | |
86 | impl AnyObject { | |
87 | pub fn new<T: IntoObjectVTable>(inner: T) -> Self { | |
88 | Self { | |
89 | inner: FFIBox::from_box(Box::new(inner)).untyped(), | |
90 | vtable: ObjectVtable::new::<T>(), | |
91 | } | |
92 | } | |
81 | // impl AnyObject { | |
82 | // pub fn new<T: IntoObjectVTable>(inner: T) -> Self { | |
83 | // Self { | |
84 | // inner: FFIBox::from_box(Box::new(inner)).untyped(), | |
85 | // vtable: ObjectVtable::new::<T>(), | |
86 | // } | |
87 | // } | |
93 | 88 | |
94 | pub fn vtable(&self) -> ObjectVtable { | |
95 | self.vtable | |
96 | } | |
89 | // pub fn vtable(&self) -> ObjectVtable { | |
90 | // self.vtable | |
91 | // } | |
97 | 92 | |
98 | pub fn object_kind(&self) -> &str { | |
99 | unsafe { | |
100 | std::str::from_utf8_unchecked(std::slice::from_raw_parts( | |
101 | self.vtable.object_kind, | |
102 | self.vtable.object_kind_len, | |
103 | )) | |
104 | } | |
105 | } | |
93 | // pub fn object_kind(&self) -> &str { | |
94 | // unsafe { | |
95 | // std::str::from_utf8_unchecked(std::slice::from_raw_parts( | |
96 | // self.vtable.object_kind, | |
97 | // self.vtable.object_kind_len, | |
98 | // )) | |
99 | // } | |
100 | // } | |
106 | 101 | |
107 | pub fn home_uri(&self) -> String { | |
108 | unsafe { (self.vtable.home_uri)(self).to_string() } | |
109 | } | |
102 | // pub fn home_uri(&self) -> String { | |
103 | // unsafe { (self.vtable.home_uri)(self).to_string() } | |
104 | // } | |
110 | 105 | |
111 | pub fn is_same(&self, other: &AnyObject) -> bool { | |
112 | unsafe { (self.vtable.is_same)(other) } | |
113 | } | |
114 | } | |
106 | // pub fn is_same(&self, other: &AnyObject) -> bool { | |
107 | // unsafe { (self.vtable.is_same)(other) } | |
108 | // } | |
115 | 109 | |
116 | impl ToString for AnyObject { | |
117 | fn to_string(&self) -> String { | |
118 | unsafe { (self.vtable.to_str)(self).to_string() } | |
119 | } | |
120 | } | |
110 | // pub unsafe fn cast<T: IntoObjectVTable + GiteratedObject>(self) -> T { | |
111 | // assert_eq!(self.object_kind(), T::object_kind()); | |
112 | ||
113 | // info!("{}", self.to_string()); | |
114 | ||
115 | // T::from_object_str(&self.to_string()).unwrap() | |
116 | // } | |
117 | // } | |
118 | ||
119 | // impl ToString for AnyObject { | |
120 | // fn to_string(&self) -> String { | |
121 | // let slice: Box<[u8]> = unsafe { Box::from_raw((self.vtable.to_str)(&self).0 as *mut _) }; | |
122 | ||
123 | // let string = unsafe { std::str::from_boxed_utf8_unchecked(slice) }; | |
124 | ||
125 | // String::from(string) | |
126 | // } | |
127 | // } | |
121 | 128 | |
122 | 129 | impl AnyObject { |
123 | 130 | pub unsafe fn transmute_owned<T>(&mut self) -> Box<T> { |
giterated-plugin/src/vtable/runtime.rs
@@ -1,10 +1,17 @@ | ||
1 | use giterated_models::error::OperationError; | |
1 | use giterated_models::{ | |
2 | error::OperationError, object::ObjectRequestError, operation::OperationState, | |
3 | }; | |
2 | 4 | |
3 | use crate::{future::RuntimeFuture, new_stack::PluginState, AnyFailure, AnySuccess, FFIBox}; | |
5 | use crate::{ | |
6 | future::RuntimeFuture, | |
7 | new_stack::{PluginState, TypeMetadata}, | |
8 | AnyFailure, AnyObject, AnySuccess, FFIBox, | |
9 | }; | |
4 | 10 | |
5 | 11 | #[derive(Clone, Copy)] |
6 | 12 | pub struct RuntimeVTable { |
7 | 13 | pub(crate) runtime: PluginState, |
14 | pub(crate) type_metadata: *const TypeMetadata, | |
8 | 15 | pub(crate) handle_fn: unsafe extern "C" fn( |
9 | 16 | PluginState, |
10 | 17 | FFIBox<str>, |
@@ -15,8 +22,17 @@ pub struct RuntimeVTable { | ||
15 | 22 | ) -> RuntimeFuture< |
16 | 23 | Result<AnySuccess, OperationError<AnyFailure>>, |
17 | 24 | >, |
25 | pub(crate) get_object: | |
26 | unsafe extern "C" fn( | |
27 | PluginState, | |
28 | &str, | |
29 | *mut OperationState, | |
30 | ) -> Result<AnyObject, OperationError<ObjectRequestError>>, | |
18 | 31 | } |
19 | 32 | |
33 | unsafe impl Send for RuntimeVTable {} | |
34 | unsafe impl Sync for RuntimeVTable {} | |
35 | ||
20 | 36 | pub trait IntoRuntimeVtable { |
21 | 37 | unsafe extern "C" fn handle( |
22 | 38 | this: PluginState, |
@@ -26,4 +42,10 @@ pub trait IntoRuntimeVtable { | ||
26 | 42 | operation_payload: FFIBox<[u8]>, |
27 | 43 | operation_state: FFIBox<[u8]>, |
28 | 44 | ) -> RuntimeFuture<Result<AnySuccess, OperationError<AnyFailure>>>; |
45 | ||
46 | unsafe extern "C" fn get_object( | |
47 | this: PluginState, | |
48 | object_str: &str, | |
49 | operation_state: *mut OperationState, | |
50 | ) -> Result<AnyObject, OperationError<ObjectRequestError>>; | |
29 | 51 | } |
plugins/example-plugin/src/lib.rs
@@ -41,6 +41,12 @@ pub extern "C" fn load_initialization_vtable(init_vtable: &InitializationVTable) | ||
41 | 41 | } |
42 | 42 | |
43 | 43 | #[no_mangle] |
44 | pub extern "C" fn load_type_metadata(metadata: *mut ()) { | |
45 | unsafe { giterated_static_runtime::initialize_type_metadata(metadata) } | |
46 | println!("Initialized type metadata for plugin"); | |
47 | } | |
48 | ||
49 | #[no_mangle] | |
44 | 50 | pub extern "C" fn initialize() -> PluginState { |
45 | 51 | tracing_subscriber::fmt() |
46 | 52 | .pretty() |
plugins/example-plugin/src/main.rs
@@ -18,12 +18,20 @@ async fn main() -> Result<(), anyhow::Error> { | ||
18 | 18 | |
19 | 19 | let handle = PluginHandle::from_dylib("example_plugin_dylib.dll").unwrap(); |
20 | 20 | |
21 | info!("1"); | |
22 | ||
21 | 23 | let mut runtime = Runtime::new(); |
22 | 24 | |
25 | info!("2"); | |
26 | ||
23 | 27 | runtime.insert_plugin(handle); |
24 | 28 | |
29 | info!("3"); | |
30 | ||
25 | 31 | runtime.init(); |
26 | 32 | |
33 | info!("4"); | |
34 | ||
27 | 35 | let runtime = unsafe { RuntimeState::from_static() }; |
28 | 36 | |
29 | 37 | let _object_request = ObjectRequest(String::from("foobar")); |
plugins/giterated-protocol/src/handlers.rs
@@ -131,7 +131,9 @@ pub async fn try_handle_with_remote( | ||
131 | 131 | // operation.kind().operation_name |
132 | 132 | // ); |
133 | 133 | |
134 | let object = NetworkedObject(unsafe { (object_meta.to_str)(&object).as_ref().to_string() }); | |
134 | // let object = NetworkedObject(unsafe { (object_meta.to_str)(object).as_ref().to_string() }); | |
135 | ||
136 | let object = todo!(); | |
135 | 137 | |
136 | 138 | let payload = unsafe { (operation_meta.serialize)(&operation) }.unwrap(); |
137 | 139 | let payload = Vec::from(payload.as_ref()); |