Structure refactoring
parent: tbd commit: a8f41ac
Showing 53 changed files with 1958 insertions and 2500 deletions
Cargo.lock
@@ -488,7 +488,6 @@ dependencies = [ | ||
488 | 488 | "dlopen2", |
489 | 489 | "giterated-models", |
490 | 490 | "giterated-plugin", |
491 | "giterated-plugin-sys", | |
492 | 491 | "giterated-static-runtime", |
493 | 492 | "serde_json", |
494 | 493 | "tokio", |
@@ -699,7 +698,6 @@ dependencies = [ | ||
699 | 698 | "anyhow", |
700 | 699 | "giterated-models", |
701 | 700 | "giterated-plugin", |
702 | "giterated-plugin-sys", | |
703 | 701 | "serde", |
704 | 702 | "serde_json", |
705 | 703 | "sqlx", |
@@ -757,7 +755,6 @@ dependencies = [ | ||
757 | 755 | "anyhow", |
758 | 756 | "giterated-models", |
759 | 757 | "giterated-plugin", |
760 | "giterated-plugin-sys", | |
761 | 758 | "serde", |
762 | 759 | "serde_json", |
763 | 760 | "sqlx", |
@@ -773,6 +770,7 @@ name = "giterated-macros" | ||
773 | 770 | version = "0.1.0" |
774 | 771 | dependencies = [ |
775 | 772 | "quote", |
773 | "syn 2.0.39", | |
776 | 774 | ] |
777 | 775 | |
778 | 776 | [[package]] |
@@ -820,16 +818,6 @@ dependencies = [ | ||
820 | 818 | ] |
821 | 819 | |
822 | 820 | [[package]] |
823 | name = "giterated-plugin-sys" | |
824 | version = "0.1.0" | |
825 | dependencies = [ | |
826 | "giterated-abi", | |
827 | "giterated-models", | |
828 | "giterated-plugin", | |
829 | "tracing", | |
830 | ] | |
831 | ||
832 | [[package]] | |
833 | 821 | name = "giterated-protocol" |
834 | 822 | version = "0.1.0" |
835 | 823 | dependencies = [ |
@@ -839,7 +827,6 @@ dependencies = [ | ||
839 | 827 | "futures-util", |
840 | 828 | "giterated-models", |
841 | 829 | "giterated-plugin", |
842 | "giterated-plugin-sys", | |
843 | 830 | "rand", |
844 | 831 | "rsa", |
845 | 832 | "serde", |
Cargo.toml
@@ -3,9 +3,9 @@ members = [ "giterated-abi", "giterated-core", | ||
3 | 3 | "giterated-daemon", |
4 | 4 | "giterated-models", |
5 | 5 | "giterated-plugin", |
6 | "giterated-plugin/giterated-macros", | |
7 | "giterated-plugin/giterated-plugin-sys", | |
8 | "giterated-plugin/giterated-static-runtime", "giterated-runtime", | |
6 | "giterated-macros", | |
7 | "giterated-runtime/giterated-static-runtime", | |
8 | "giterated-runtime", | |
9 | 9 | "plugins/example-plugin", |
10 | 10 | "plugins/giterated-backend", |
11 | 11 | "plugins/giterated-issues", |
giterated-abi/src/vtable/mod.rs
@@ -4,6 +4,8 @@ mod object; | ||
4 | 4 | pub mod operation; |
5 | 5 | mod setting; |
6 | 6 | mod value; |
7 | mod runtime; | |
8 | mod plugin_initialization; | |
7 | 9 | |
8 | 10 | pub use object::*; |
9 | 11 | pub use setting::*; |
giterated-abi/src/vtable/plugin_initialization.rs
@@ -0,0 +1,61 @@ | ||
1 | #[repr(C)] | |
2 | pub struct HostVTable {} | |
3 | ||
4 | #[repr(C)] | |
5 | #[derive(Clone, Copy)] | |
6 | pub struct Initialization { | |
7 | pub register_object: | |
8 | unsafe extern "C" fn(*mut PluginInitializationState, &'static str, &'static VTable<Object>), | |
9 | pub register_operation: unsafe extern "C" fn( | |
10 | *mut PluginInitializationState, | |
11 | &'static str, | |
12 | &'static str, | |
13 | &'static VTable<Operation>, | |
14 | ), | |
15 | pub register_setting: unsafe extern "C" fn( | |
16 | *mut PluginInitializationState, | |
17 | &'static str, | |
18 | &'static str, | |
19 | &'static VTable<Setting>, | |
20 | ), | |
21 | pub register_value: unsafe extern "C" fn( | |
22 | *mut PluginInitializationState, | |
23 | &'static str, | |
24 | &'static str, | |
25 | &'static VTable<Value>, | |
26 | ), | |
27 | ||
28 | pub operation_handler: unsafe extern "C" fn( | |
29 | *mut PluginInitializationState, | |
30 | &'static str, | |
31 | &'static str, | |
32 | CallbackPtr<OperationHandlerCallback>, | |
33 | ), | |
34 | ||
35 | pub value_getter: unsafe extern "C" fn( | |
36 | *mut PluginInitializationState, | |
37 | &'static str, | |
38 | &'static str, | |
39 | CallbackPtr<ValueGetterCallback>, | |
40 | ), | |
41 | ||
42 | pub setting_getter: unsafe extern "C" fn( | |
43 | *mut PluginInitializationState, | |
44 | &'static str, | |
45 | &'static str, | |
46 | CallbackPtr<SettingGetterCallback>, | |
47 | ), | |
48 | } | |
49 | ||
50 | impl ObjectABI for Initialization { | |
51 | type VTable = Initialization; | |
52 | } | |
53 | ||
54 | impl Debug for Initialization { | |
55 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
56 | f.debug_struct("InitializationVTable").finish() | |
57 | } | |
58 | } | |
59 | ||
60 | unsafe impl Sync for Initialization {} | |
61 | unsafe impl Send for Initialization {} |
giterated-abi/src/vtable/runtime.rs
@@ -0,0 +1,56 @@ | ||
1 | use giterated_abi::{ | |
2 | result::{FfiError, FfiResult}, | |
3 | value_ex::FfiValueUntyped, | |
4 | vtable::Object, | |
5 | FfiSliceRef, | |
6 | }; | |
7 | use giterated_models::{ | |
8 | error::OperationError, object::ObjectRequestError, operation::OperationState, | |
9 | }; | |
10 | ||
11 | use crate::{ | |
12 | future::RuntimeFuture, | |
13 | new_stack::{PluginState, TypeMetadata}, | |
14 | }; | |
15 | ||
16 | #[derive(Clone, Copy)] | |
17 | pub struct RuntimeVTable { | |
18 | pub(crate) runtime: PluginState, | |
19 | pub(crate) type_metadata: *const TypeMetadata, | |
20 | pub(crate) handle_fn: unsafe extern "C" fn( | |
21 | PluginState, | |
22 | FfiSliceRef<str>, | |
23 | FfiSliceRef<str>, | |
24 | FfiSliceRef<str>, | |
25 | FfiSliceRef<[u8]>, | |
26 | FfiSliceRef<[u8]>, | |
27 | ) -> RuntimeFuture< | |
28 | FfiResult<FfiValueUntyped, OperationError<FfiError>>, | |
29 | >, | |
30 | pub(crate) get_object: | |
31 | unsafe extern "C" fn( | |
32 | PluginState, | |
33 | &str, | |
34 | *mut OperationState, | |
35 | ) -> FfiResult<Object, OperationError<ObjectRequestError>>, | |
36 | } | |
37 | ||
38 | unsafe impl Send for RuntimeVTable {} | |
39 | unsafe impl Sync for RuntimeVTable {} | |
40 | ||
41 | pub trait IntoRuntimeVtable { | |
42 | unsafe extern "C" fn handle( | |
43 | this: PluginState, | |
44 | object_kind: FfiSliceRef<str>, | |
45 | operation_name: FfiSliceRef<str>, | |
46 | object: FfiSliceRef<str>, | |
47 | operation_payload: FfiSliceRef<[u8]>, | |
48 | operation_state: FfiSliceRef<[u8]>, | |
49 | ) -> RuntimeFuture<FfiResult<FfiValueUntyped, OperationError<FfiError>>>; | |
50 | ||
51 | unsafe extern "C" fn get_object( | |
52 | this: PluginState, | |
53 | object_str: &str, | |
54 | operation_state: *mut OperationState, | |
55 | ) -> FfiResult<Object, OperationError<ObjectRequestError>>; | |
56 | } |
giterated-abi/src/vtable/setting.rs
@@ -32,7 +32,7 @@ impl SettingVTable { | ||
32 | 32 | pub const fn new<S: IntoSettingVTable>() -> Self { |
33 | 33 | Self { |
34 | 34 | serialize: S::serialize, |
35 | deserialize: S::deserialize | |
35 | deserialize: S::deserialize, | |
36 | 36 | } |
37 | 37 | } |
38 | 38 |
giterated-core/src/callback/mod.rs
@@ -1 +1,3 @@ | ||
1 | 1 | mod operation; |
2 | mod setting; | |
3 | mod value; |
giterated-core/src/callback/setting.rs
@@ -0,0 +1,150 @@ | ||
1 | pub struct SettingGetterCallback(FfiValueUntyped); | |
2 | ||
3 | impl Callback for SettingGetterCallback { | |
4 | type CallbackFunc = unsafe extern "C" fn( | |
5 | CallbackPtr<SettingGetterCallback>, | |
6 | state: FfiValueMut<State>, | |
7 | object: FfiValueRef<Object>, | |
8 | ) -> RuntimeFuture<Result<Setting, ()>>; | |
9 | } | |
10 | ||
11 | pub trait IntoPluginSettingGetter<S, O, OS> { | |
12 | unsafe extern "C" fn get_setting( | |
13 | callback_ptr: CallbackPtr<SettingGetterCallback>, | |
14 | state: FfiValueMut<State>, | |
15 | object: FfiValueRef<Object>, | |
16 | ) -> RuntimeFuture<Result<Setting, ()>>; | |
17 | ||
18 | fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback> { | |
19 | // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) } | |
20 | todo!() | |
21 | } | |
22 | } | |
23 | ||
24 | impl<F, S, O, OS, Fut> IntoPluginSettingGetter<S, O, OS> for F | |
25 | where | |
26 | Fut: Future<Output = Result<OS, OperationError<anyhow::Error>>> + Send + Sync + 'static, | |
27 | S: Clone + Send + Sync + 'static, | |
28 | O: GiteratedObject + Send + Sync + 'static, | |
29 | OS: giterated_models::settings::Setting + Send + Sync + 'static, | |
30 | F: Fn(S, O) -> Fut + Send + Sync + 'static, | |
31 | { | |
32 | unsafe extern "C" fn get_setting( | |
33 | callback: CallbackPtr<SettingGetterCallback>, | |
34 | state: FfiValueMut<State>, | |
35 | mut object: FfiValueRef<Object>, | |
36 | ) -> RuntimeFuture<Result<Setting, ()>> { | |
37 | // let _guard = trace_span!( | |
38 | // "get_setting handler", | |
39 | // object = O::object_name(), | |
40 | // setting = OS::name() | |
41 | // ) | |
42 | // .entered(); | |
43 | // let state = unsafe { state.transmute_ref::<S>() }; | |
44 | ||
45 | // let object = unsafe { object.transmute_owned::<O>() }; | |
46 | ||
47 | // // Cast the callback ptr to ourselves | |
48 | // let callback: *const F = std::mem::transmute(callback.0); | |
49 | // let callback = callback.as_ref().unwrap(); | |
50 | ||
51 | // let state = state.clone(); | |
52 | // runtime_state.spawn_future(async move { | |
53 | // let result = callback(state, *object).await; | |
54 | ||
55 | // match result { | |
56 | // Ok(success) => unsafe { Ok(NewAnySetting::new(success)) }, | |
57 | // Err(err) => match err { | |
58 | // OperationError::Operation(_) => todo!(), | |
59 | // OperationError::Internal(_) => todo!(), | |
60 | // OperationError::Unhandled => todo!(), | |
61 | // }, | |
62 | // } | |
63 | ||
64 | todo!() | |
65 | // }) | |
66 | } | |
67 | } | |
68 | ||
69 | pub trait IntoPluginSettingSetter<S, O, OS> { | |
70 | unsafe extern "C" fn set_setting( | |
71 | callback_ptr: CallbackPtr<SettingGetterCallback>, | |
72 | state: &PluginState, | |
73 | object: FfiValueRef<Object>, | |
74 | setting: Setting, | |
75 | ) -> RuntimeFuture<Result<(), ()>>; | |
76 | ||
77 | fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback> { | |
78 | // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) } | |
79 | todo!() | |
80 | } | |
81 | } | |
82 | ||
83 | impl<F, S, O, OS, Fut> IntoPluginSettingSetter<S, O, OS> for F | |
84 | where | |
85 | Fut: Future<Output = Result<(), OperationError<anyhow::Error>>>, | |
86 | S: Clone, | |
87 | O: GiteratedObject, | |
88 | OS: giterated_models::settings::Setting, | |
89 | F: Fn(S, O, OS) -> Fut, | |
90 | { | |
91 | unsafe extern "C" fn set_setting( | |
92 | callback: CallbackPtr<SettingGetterCallback>, | |
93 | state: &PluginState, | |
94 | mut object: FfiValueRef<Object>, | |
95 | _setting: Setting, | |
96 | ) -> RuntimeFuture<Result<(), ()>> { | |
97 | // let _guard = trace_span!( | |
98 | // "get_setting handler", | |
99 | // object = O::object_name(), | |
100 | // setting = OS::name() | |
101 | // ) | |
102 | // .entered(); | |
103 | // let _state = unsafe { state.transmute_ref::<S>() }; | |
104 | ||
105 | // let _object = unsafe { object.transmute_owned::<O>() }; | |
106 | ||
107 | // // Cast the callback ptr to ourselves | |
108 | // let callback: *const F = std::mem::transmute(callback.0); | |
109 | // let _callback = callback.as_ref().unwrap(); | |
110 | ||
111 | // let result = callback(state.clone(), *object); | |
112 | ||
113 | // match result { | |
114 | // Ok(setting) => Ok(NewAnySetting::new(setting)), | |
115 | // Err(_) => todo!(), | |
116 | // } | |
117 | todo!() | |
118 | } | |
119 | } | |
120 | ||
121 | pub struct SettingChangeCallback(FfiValueUntyped); | |
122 | ||
123 | impl Callback for SettingChangeCallback { | |
124 | type CallbackFunc = unsafe extern "C" fn( | |
125 | &PluginState, | |
126 | object: FfiValueRef<Object>, | |
127 | setting_name: &str, | |
128 | new_setting: Setting, | |
129 | ); | |
130 | } | |
131 | ||
132 | pub trait IntoSettingChangeCallback<S, O> { | |
133 | unsafe extern "C" fn setting_changed( | |
134 | state: &PluginState, | |
135 | object: FfiValueRef<Object>, | |
136 | setting_name: &str, | |
137 | new_setting: Setting, | |
138 | ); | |
139 | } | |
140 | ||
141 | impl<F, S, O> IntoSettingChangeCallback<S, O> for F { | |
142 | unsafe extern "C" fn setting_changed( | |
143 | _state: &PluginState, | |
144 | _object: FfiValueRef<Object>, | |
145 | _setting_name: &str, | |
146 | _new_setting: Setting, | |
147 | ) { | |
148 | todo!() | |
149 | } | |
150 | } |
giterated-core/src/callback/value.rs
@@ -0,0 +1,103 @@ | ||
1 | #[derive(Copy, Clone)] | |
2 | pub struct ValueGetterCallback(CallbackPtr<ValueGetterCallback>); | |
3 | ||
4 | impl Callback for ValueGetterCallback { | |
5 | type CallbackFunc = unsafe extern "C" fn( | |
6 | CallbackPtr<ValueGetterCallback>, | |
7 | state: FfiValueMut<State>, | |
8 | object: FfiValueRef<Object>, | |
9 | ) -> RuntimeFuture<FfiResult<Value, FfiError>>; | |
10 | } | |
11 | ||
12 | pub trait IntoPluginValueGetter<S, O, V> { | |
13 | unsafe extern "C" fn get_value( | |
14 | callback: CallbackPtr<SettingGetterCallback>, | |
15 | state: FfiValueMut<State>, | |
16 | object: FfiValueRef<Object>, | |
17 | ) -> RuntimeFuture<FfiResult<Value, FfiError>>; | |
18 | ||
19 | fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback>; | |
20 | } | |
21 | ||
22 | impl<F, S, O, V, Fut> IntoPluginValueGetter<S, O, V> for F | |
23 | where | |
24 | Fut: Future<Output = Result<V, OperationError<anyhow::Error>>> + Send + Sync, | |
25 | S: Clone + Send + Sync + 'static, | |
26 | O: GiteratedObject + 'static, | |
27 | V: GiteratedObjectValue<Object = O> + Send + Sync + 'static, | |
28 | F: Fn(S, O) -> Fut + Send + Sync + 'static, | |
29 | { | |
30 | unsafe extern "C" fn get_value( | |
31 | callback: CallbackPtr<SettingGetterCallback>, | |
32 | state: FfiValueMut<State>, | |
33 | mut object: FfiValueRef<Object>, | |
34 | ) -> RuntimeFuture<FfiResult<Value, FfiError>> { | |
35 | // let _guard = trace_span!( | |
36 | // "get_value handler", | |
37 | // object = O::object_name(), | |
38 | // value = V::value_name() | |
39 | // ) | |
40 | // .entered(); | |
41 | // let state = unsafe { state.transmute_ref::<S>() }; | |
42 | ||
43 | // let object = unsafe { object.transmute_owned::<O>() }; | |
44 | ||
45 | // // Cast the callback ptr to ourselves | |
46 | // let callback: *const F = std::mem::transmute(callback.0); | |
47 | // let callback = callback.as_ref().unwrap(); | |
48 | ||
49 | // let state = state.clone(); | |
50 | // runtime_state.spawn_future(async move { | |
51 | // let result = callback(state, *object).await; | |
52 | ||
53 | // match result { | |
54 | // Ok(success) => unsafe { Ok(NewAnyValue::new(success)) }, | |
55 | // Err(err) => match err { | |
56 | // OperationError::Operation(_) => todo!(), | |
57 | // OperationError::Internal(_) => todo!(), | |
58 | // OperationError::Unhandled => todo!(), | |
59 | // }, | |
60 | // } | |
61 | // }) | |
62 | ||
63 | todo!() | |
64 | } | |
65 | ||
66 | fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback> { | |
67 | todo!() | |
68 | // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) } | |
69 | } | |
70 | } | |
71 | ||
72 | pub struct ValueChangeCallback(CallbackPtr<ValueChangeCallback>); | |
73 | ||
74 | impl Callback for ValueChangeCallback { | |
75 | type CallbackFunc = unsafe extern "C" fn( | |
76 | &PluginState, | |
77 | object: FfiValueRef<Object>, | |
78 | value_name: FfiSliceRef<str>, | |
79 | new_value: Value, | |
80 | ) -> RuntimeFuture<()>; | |
81 | } | |
82 | ||
83 | pub trait IntoValueChangeCallback<S, O> { | |
84 | unsafe extern "C" fn value_changed( | |
85 | callback: CallbackPtr<ValueChangeCallback>, | |
86 | state: FfiValueMut<State>, | |
87 | object: FfiValueRef<Object>, | |
88 | value_name: FfiSliceRef<str>, | |
89 | new_value: Value, | |
90 | ) -> RuntimeFuture<()>; | |
91 | } | |
92 | ||
93 | impl<F, S, O> IntoValueChangeCallback<S, O> for F { | |
94 | unsafe extern "C" fn value_changed( | |
95 | callback: CallbackPtr<ValueChangeCallback>, | |
96 | state: FfiValueMut<State>, | |
97 | _object: FfiValueRef<Object>, | |
98 | _value_name: FfiSliceRef<str>, | |
99 | _new_value: Value, | |
100 | ) -> RuntimeFuture<()> { | |
101 | todo!() | |
102 | } | |
103 | } |
giterated-core/src/lib.rs
@@ -1,5 +1,6 @@ | ||
1 | 1 | mod callback; |
2 | 2 | mod state; |
3 | mod types; | |
3 | 4 | |
4 | 5 | #[derive(Clone)] |
5 | 6 | #[repr(C)] |
giterated-core/src/operation_walker.rs
@@ -0,0 +1,273 @@ | ||
1 | use crate::callback::RuntimeState; | |
2 | use giterated_abi::{result::FfiError, value_ex::FfiValueUntyped}; | |
3 | use giterated_models::{ | |
4 | error::OperationError, operation::GiteratedOperation, settings::GetSetting, value::GetValue, | |
5 | }; | |
6 | ||
7 | use serde_json::Value; | |
8 | use tracing::{debug_span, trace, trace_span}; | |
9 | ||
10 | use crate::new_stack::ObjectOperationPair; | |
11 | ||
12 | use super::{ObjectSettingPair, ObjectValuePair, RuntimeHandlers}; | |
13 | ||
14 | /// A wrapper for operation handling that enforces handling rules. | |
15 | /// | |
16 | /// # Handler Resolution | |
17 | /// In order, handler resolution will be attempted as follows: | |
18 | /// | |
19 | /// | Index | object_kind | operation_kind | Special Case? | | |
20 | /// |-------|-------------|-----------------|---------------| | |
21 | /// | 1 | `any` | `typed` | No | | |
22 | /// | 2 | `typed` | `any` | No | | |
23 | /// | 3 | `any` | `any` | No | | |
24 | /// | 4 | `any` | `GetValue` | ⚠️ Yes ⚠️ | | |
25 | /// | 5 | `any` | `GetSetting` | ⚠️ Yes ⚠️ | | |
26 | /// | 6 | `any` | `SetSetting` | ⚠️ Yes ⚠️ | | |
27 | /// | 7 | `any` | `ObjectRequest` | ⚠️ Yes ⚠️ | | |
28 | /// | 8 | `typed` | `typed` | No | | |
29 | pub struct OperationHandlerRules<'a> { | |
30 | object_kind: &'a str, | |
31 | operation_name: &'a str, | |
32 | handlers: &'a RuntimeHandlers, | |
33 | } | |
34 | ||
35 | impl<'o> OperationHandlerRules<'o> { | |
36 | pub fn new( | |
37 | object_kind: &'o str, | |
38 | operation_name: &'o str, | |
39 | handlers: &'o RuntimeHandlers, | |
40 | ) -> Self { | |
41 | Self { | |
42 | object_kind, | |
43 | operation_name, | |
44 | handlers, | |
45 | } | |
46 | } | |
47 | ||
48 | pub async fn handle( | |
49 | &self, | |
50 | runtime_state: &RuntimeState, | |
51 | object: &str, | |
52 | operation_payload: &[u8], | |
53 | ) -> Result<FfiValueUntyped, OperationError<FfiError>> { | |
54 | // object_kind: `any` | |
55 | // operation_kind: `typed` | |
56 | if let Some(_handler) = self | |
57 | .handlers | |
58 | .operation_handlers | |
59 | .get(&ObjectOperationPair::new("any", self.operation_name)) | |
60 | { | |
61 | todo!() | |
62 | } | |
63 | ||
64 | // object_kind: `typed` | |
65 | // operation_kind: `any` | |
66 | if let Some(_handler) = self | |
67 | .handlers | |
68 | .operation_handlers | |
69 | .get(&ObjectOperationPair::new(self.object_kind, "any")) | |
70 | {} | |
71 | ||
72 | // object_kind: `any` | |
73 | // operation_kind: `any` | |
74 | if let Some(_handler) = self | |
75 | .handlers | |
76 | .operation_handlers | |
77 | .get(&ObjectOperationPair::new("any", "any")) | |
78 | {} | |
79 | ||
80 | // ⚠️ Special Case ⚠️ | |
81 | // object_kind: `any` | |
82 | // operation_kind: `GetValue` | |
83 | if self.operation_name == "get_value" { | |
84 | let operation: GetValue = serde_json::from_slice(operation_payload).unwrap(); | |
85 | let _guard = trace_span!( | |
86 | "get_value handler resolving", | |
87 | object = self.object_kind, | |
88 | value = operation.value_name | |
89 | ) | |
90 | .entered(); | |
91 | ||
92 | if let Some((domain, callback)) = self.handlers.value_getters.get( | |
93 | &ObjectValuePair::new(self.object_kind, &operation.value_name), | |
94 | ) { | |
95 | trace_span!( | |
96 | "get_value handler.", | |
97 | object = self.object_kind, | |
98 | value_name = operation.value_name | |
99 | ); | |
100 | ||
101 | let object_vtable = domain | |
102 | .object_vtable(self.object_kind) | |
103 | .ok_or_else(|| OperationError::Unhandled)?; | |
104 | trace!("Resolved object vtable for {}", self.object_kind); | |
105 | ||
106 | let _value_vtable = domain | |
107 | .value_vtable(self.object_kind, &operation.value_name) | |
108 | .ok_or_else(|| OperationError::Unhandled)?; | |
109 | trace!( | |
110 | "Resolved value vtable for {}::{}", | |
111 | self.object_kind, | |
112 | operation.value_name | |
113 | ); | |
114 | ||
115 | // let object = unsafe { (object_vtable.from_str)(object) } | |
116 | // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; | |
117 | ||
118 | // let _guard = debug_span!("get_value handler"); | |
119 | ||
120 | // let result = unsafe { | |
121 | // (callback.func)( | |
122 | // callback.callback_ptr, | |
123 | // runtime_state, | |
124 | // &domain.plugin.state, | |
125 | // object, | |
126 | // ) | |
127 | // } | |
128 | // .await; | |
129 | ||
130 | // match result { | |
131 | // Ok(value) => return Ok(value.into()), | |
132 | // Err(_err) => todo!(), | |
133 | // } | |
134 | ||
135 | todo!() | |
136 | } else { | |
137 | trace!("Failed to resolve handler."); | |
138 | } | |
139 | } | |
140 | ||
141 | // ⚠️ Special Case ⚠️ | |
142 | // object_kind: `any` | |
143 | // operation_kind: `GetSetting` | |
144 | if self.operation_name == "get_setting" { | |
145 | let operation: GetSetting = serde_json::from_slice(operation_payload).unwrap(); | |
146 | let _guard = trace_span!( | |
147 | "get_setting handler resolving", | |
148 | object = self.object_kind, | |
149 | setting = operation.setting_name | |
150 | ) | |
151 | .entered(); | |
152 | ||
153 | if let Some((domain, callback)) = self.handlers.setting_getters.get( | |
154 | &ObjectSettingPair::new(self.object_kind, &operation.setting_name), | |
155 | ) { | |
156 | trace_span!( | |
157 | "get_setting handler.", | |
158 | object = self.object_kind, | |
159 | setting_name = operation.setting_name | |
160 | ); | |
161 | ||
162 | let object_vtable = domain | |
163 | .object_vtable(self.object_kind) | |
164 | .ok_or_else(|| OperationError::Unhandled)?; | |
165 | trace!("Resolved object vtable for {}", self.object_kind); | |
166 | ||
167 | let _setting_vtable = domain | |
168 | .setting_vtable(self.object_kind, &operation.setting_name) | |
169 | .ok_or_else(|| OperationError::Unhandled)?; | |
170 | trace!("Resolved setting vtable for {}", operation.setting_name); | |
171 | ||
172 | todo!() | |
173 | ||
174 | // let object = unsafe { (object_vtable.from_str)(object) } | |
175 | // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; | |
176 | ||
177 | // let _guard = debug_span!("get_value handler"); | |
178 | ||
179 | // let result = unsafe { | |
180 | // (callback.func())( | |
181 | // callback.callback_ptr, | |
182 | // runtime_state, | |
183 | // &domain.plugin.state, | |
184 | // object, | |
185 | // ) | |
186 | // } | |
187 | // .await; | |
188 | ||
189 | // match result { | |
190 | // Ok(value) => { | |
191 | // let vtable = unsafe { (value.vtable.get_setting_vtable)() }; | |
192 | // let return_value: Value = serde_json::from_slice(unsafe { | |
193 | // (value.vtable.serialize)(value).unwrap().as_ref() | |
194 | // }) | |
195 | // .unwrap(); | |
196 | ||
197 | // todo!() | |
198 | ||
199 | // // return Ok(unsafe { | |
200 | // // AnySuccess::from_raw( | |
201 | // // FFIBox::from_box(Box::new(return_value)).untyped(), | |
202 | // // vtable, | |
203 | // // ) | |
204 | // // }); | |
205 | // } | |
206 | // Err(_err) => todo!(), | |
207 | // } | |
208 | } else { | |
209 | trace!("Failed to resolve handler."); | |
210 | } | |
211 | } | |
212 | ||
213 | // ⚠️ Special Case ⚠️ | |
214 | // object_kind: `any` | |
215 | // operation_kind: `SetSetting` | |
216 | self.operation_name == "set_setting"; | |
217 | ||
218 | // ⚠️ Special Case ⚠️ | |
219 | // object_kind: `any` | |
220 | // operation_kind: `ObjectRequest` | |
221 | self.operation_name == "object_request"; | |
222 | ||
223 | // object_kind: `typed` | |
224 | // operation_kind: `typed` | |
225 | if let Some((domain, handler)) = | |
226 | self.handlers | |
227 | .operation_handlers | |
228 | .get(&ObjectOperationPair::new( | |
229 | self.object_kind, | |
230 | self.operation_name, | |
231 | )) | |
232 | { | |
233 | let _guard = trace_span!("typed_typed handler resolved").entered(); | |
234 | ||
235 | let object_vtable = domain | |
236 | .object_vtable(self.object_kind) | |
237 | .ok_or_else(|| OperationError::Unhandled)?; | |
238 | trace!("Resolved object vtable for {}", self.object_kind); | |
239 | ||
240 | let operation_vtable = domain | |
241 | .operation_vtable(self.object_kind, self.operation_name) | |
242 | .ok_or_else(|| OperationError::Unhandled)?; | |
243 | trace!( | |
244 | "Resolved operation vtable for {}::{}", | |
245 | self.object_kind, | |
246 | self.operation_name | |
247 | ); | |
248 | ||
249 | todo!() | |
250 | ||
251 | // let object = unsafe { (object_vtable.from_str)(object) } | |
252 | // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; | |
253 | // let operation = unsafe { (operation_vtable.deserialize)(operation_payload) } | |
254 | // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?; | |
255 | // trace!("Parsed operation data"); | |
256 | ||
257 | // let _guard = debug_span!("calling handler").entered(); | |
258 | // let result = unsafe { | |
259 | // (handler.func)( | |
260 | // handler.callback_ptr, | |
261 | // runtime_state, | |
262 | // &domain.plugin.state, | |
263 | // object, | |
264 | // operation, | |
265 | // ) | |
266 | // }; | |
267 | ||
268 | // return result.await; | |
269 | } | |
270 | ||
271 | Err(OperationError::Unhandled) | |
272 | } | |
273 | } |
giterated-core/src/state.rs
@@ -13,3 +13,120 @@ impl<T: FromState> FromState for StateExtractor<T> { | ||
13 | 13 | todo!() |
14 | 14 | } |
15 | 15 | } |
16 | ||
17 | use giterated_abi::prelude::*; | |
18 | use giterated_abi::value_ex::FfiValueUntyped; | |
19 | use giterated_abi::vtable::ObjectABI; | |
20 | use giterated_abi::vtable::VTable; | |
21 | ||
22 | #[repr(transparent)] | |
23 | pub struct State { | |
24 | inner: StateHandle, | |
25 | } | |
26 | ||
27 | #[repr(transparent)] | |
28 | struct StateHandle { | |
29 | state: FfiValue<()>, | |
30 | } | |
31 | ||
32 | #[repr(C)] | |
33 | struct StateItem<T: ?Sized> { | |
34 | /// The pointer to the next item. | |
35 | /// | |
36 | /// `next_item` is most likely always an `FfiValue<StateItem<()>>` and that's how we free them. | |
37 | next_item: *const StateItem<()>, | |
38 | pub state_uuid: u128, | |
39 | pub state: T, | |
40 | } | |
41 | ||
42 | impl Drop for State { | |
43 | fn drop(&mut self) { | |
44 | let state_manager = unsafe { StateManager::new(self) }; | |
45 | ||
46 | for state in state_manager {} | |
47 | } | |
48 | } | |
49 | ||
50 | struct StateManager<'s> { | |
51 | state: &'s mut State, | |
52 | last: Option<StateHandle>, | |
53 | } | |
54 | ||
55 | impl<'s> StateManager<'s> { | |
56 | pub unsafe fn new(handle: &'s mut State) -> Self { | |
57 | todo!() | |
58 | } | |
59 | ||
60 | pub unsafe fn write_state<S: StateUUID>(&mut self, state: S) -> Self { | |
61 | todo!() | |
62 | } | |
63 | ||
64 | pub unsafe fn get_state<S: StateUUID>(&mut self) -> Option<&S> { | |
65 | todo!() | |
66 | } | |
67 | } | |
68 | ||
69 | impl<'s> Iterator for StateManager<'s> { | |
70 | type Item = StateItem<()>; | |
71 | ||
72 | fn next(&mut self) -> Option<StateItem<()>> { | |
73 | todo!() | |
74 | } | |
75 | } | |
76 | ||
77 | pub trait StateUUID { | |
78 | fn uuid() -> u128; | |
79 | ||
80 | fn unsafe_hint_copy() -> Option<bool> { | |
81 | None | |
82 | } | |
83 | } | |
84 | ||
85 | /// State values for the current execution domain. 99.99% of the time this means "plugin-specific" | |
86 | /// | |
87 | /// The remainder 0.01% of the time it refers to the daemon's runtime domain. | |
88 | pub struct DomainState(StateItem<()>); | |
89 | ||
90 | impl StateUUID for DomainState { | |
91 | fn uuid() -> u128 { | |
92 | todo!() | |
93 | } | |
94 | } | |
95 | ||
96 | pub struct RuntimeState(StateItem<&'static VTable<Runtime>>); | |
97 | ||
98 | impl StateUUID for RuntimeState { | |
99 | fn uuid() -> u128 { | |
100 | todo!() | |
101 | } | |
102 | } | |
103 | ||
104 | impl RuntimeState { | |
105 | pub fn queue_insert_state<S: StateUUID>(&mut self, state: S) { | |
106 | todo!() | |
107 | } | |
108 | } | |
109 | ||
110 | pub struct Runtime { | |
111 | pub queue_insert_state: unsafe extern "C" fn(state_uuid: u128, state: FfiValueUntyped), | |
112 | } | |
113 | ||
114 | impl ObjectABI for Runtime { | |
115 | type VTable = Runtime; | |
116 | } | |
117 | ||
118 | pub trait FromState: Sized { | |
119 | fn from_state(state: &mut State) -> Result<Self, anyhow::Error>; | |
120 | } | |
121 | ||
122 | impl<T: StateUUID> FromState for T { | |
123 | fn from_state(state: &mut State) -> Result<Self, anyhow::Error> { | |
124 | todo!() | |
125 | } | |
126 | } | |
127 | ||
128 | impl<T: FromState> FromState for Option<T> { | |
129 | fn from_state(state: &mut State) -> Result<Self, anyhow::Error> { | |
130 | todo!() | |
131 | } | |
132 | } |
giterated-core/src/types/mod.rs
@@ -0,0 +1,77 @@ | ||
1 | #[derive(Default, Clone)] | |
2 | pub struct TypeMetadata { | |
3 | pub objects: HashMap<&'static str, &'static VTable<Object>>, | |
4 | pub operations: HashMap<ObjectOperationPair<'static>, &'static VTable<Operation>>, | |
5 | pub settings: HashMap<ObjectSettingPair<'static>, &'static VTable<Setting>>, | |
6 | pub values: HashMap<ObjectValuePair<'static>, &'static VTable<Value>>, | |
7 | } | |
8 | ||
9 | impl TypeMetadata { | |
10 | pub unsafe fn from_static() -> &'static Self { | |
11 | giterated_static_runtime::get_type_metadata_reference() | |
12 | .cast::<TypeMetadata>() | |
13 | .as_ref() | |
14 | } | |
15 | ||
16 | pub fn register_object(&mut self, object_kind: &'static str, vtable: &'static VTable<Object>) { | |
17 | trace!("Registering type metadata for {}", object_kind); | |
18 | ||
19 | self.objects.insert(object_kind, vtable); | |
20 | } | |
21 | ||
22 | pub fn register_operation( | |
23 | &mut self, | |
24 | object_kind: &'static str, | |
25 | operation_name: &'static str, | |
26 | vtable: &'static VTable<Operation>, | |
27 | ) { | |
28 | trace!( | |
29 | "Registering operation metadata for {}::{}", | |
30 | object_kind, | |
31 | operation_name | |
32 | ); | |
33 | ||
34 | self.operations.insert( | |
35 | ObjectOperationPair { | |
36 | object_kind, | |
37 | operation_name, | |
38 | }, | |
39 | vtable, | |
40 | ); | |
41 | } | |
42 | ||
43 | pub fn register_setting( | |
44 | &mut self, | |
45 | object_kind: &'static str, | |
46 | setting_name: &'static str, | |
47 | vtable: &'static VTable<Setting>, | |
48 | ) { | |
49 | trace!("Registering setting {}::{}", object_kind, setting_name); | |
50 | ||
51 | self.settings.insert( | |
52 | ObjectSettingPair { | |
53 | object_kind, | |
54 | setting_name, | |
55 | }, | |
56 | vtable, | |
57 | ); | |
58 | } | |
59 | ||
60 | pub fn register_value( | |
61 | &mut self, | |
62 | object_kind: &'static str, | |
63 | value_name: &'static str, | |
64 | vtable: &'static VTable<Value>, | |
65 | ) { | |
66 | trace!("Registering value {}::{}", object_kind, value_name); | |
67 | ||
68 | self.values.insert( | |
69 | ObjectValuePair { | |
70 | object_kind, | |
71 | value_name, | |
72 | }, | |
73 | vtable, | |
74 | ); | |
75 | } | |
76 | } | |
77 |
giterated-macros/Cargo.toml
@@ -0,0 +1,11 @@ | ||
1 | [package] | |
2 | name = "giterated-macros" | |
3 | version = "0.1.0" | |
4 | edition = "2021" | |
5 | ||
6 | [lib] | |
7 | proc-macro = true | |
8 | ||
9 | [dependencies] | |
10 | quote = "1" | |
11 | syn = "2" | |
11 | \ No newline at end of file |
giterated-macros/src/lib.rs
@@ -0,0 +1,40 @@ | ||
1 | use proc_macro::TokenStream; | |
2 | use quote::quote; | |
3 | use syn::{parse_macro_input, Abi, Attribute, ItemFn}; | |
4 | ||
5 | extern crate proc_macro; | |
6 | ||
7 | #[proc_macro] | |
8 | pub fn plugin(metadata: TokenStream) -> TokenStream { | |
9 | emit_plugin_api().into() | |
10 | } | |
11 | ||
12 | #[proc_macro_attribute] | |
13 | pub fn plugin_init(attribute: TokenStream, item: TokenStream) -> TokenStream { | |
14 | let mut input = parse_macro_input!(item as ItemFn); | |
15 | ||
16 | quote! { | |
17 | #[doc(hidden)] | |
18 | #[no_mangle] | |
19 | unsafe extern "C" fn __plugin_init() { | |
20 | #input.sig.ident() | |
21 | } | |
22 | } | |
23 | .into() | |
24 | } | |
25 | ||
26 | fn emit_plugin_api() -> impl Into<TokenStream> { | |
27 | quote! { | |
28 | #[doc(hidden)] | |
29 | #[no_mangle] | |
30 | unsafe extern "C" fn __load_runtime_vtable(vtable: &'static ::giterated_abi::VTable<Runtime>) { | |
31 | todo!() | |
32 | } | |
33 | ||
34 | #[doc(hidden)] | |
35 | #[no_mangle] | |
36 | unsafe extern "C" fn __get_plugin_vtable() -> &'static ::giterated_abi::VTable<Plugin> { | |
37 | todo!() | |
38 | } | |
39 | } | |
40 | } |
giterated-models/src/object.rs
@@ -115,3 +115,18 @@ impl<O: GiteratedObject + Clone + Debug + 'static, B: ObjectBackend> Object<O, B | ||
115 | 115 | .await |
116 | 116 | } |
117 | 117 | } |
118 | ||
119 | #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] | |
120 | pub struct ObjectOperationPair<'s> { | |
121 | pub object_kind: &'s str, | |
122 | pub operation_name: &'s str, | |
123 | } | |
124 | ||
125 | impl<'s> ObjectOperationPair<'s> { | |
126 | pub fn new(object_kind: &'s str, operation_name: &'s str) -> Self { | |
127 | Self { | |
128 | object_kind, | |
129 | operation_name, | |
130 | } | |
131 | } | |
132 | } |
giterated-models/src/settings/mod.rs
@@ -9,5 +9,17 @@ pub trait Setting: Serialize + DeserializeOwned + Send + Sync { | ||
9 | 9 | fn name() -> &'static str; |
10 | 10 | } |
11 | 11 | |
12 | #[derive(Debug, Clone)] | |
13 | pub struct AnySetting(pub Arc<dyn Any + Send + Sync>); | |
12 | #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] | |
13 | pub struct ObjectSettingPair<'s> { | |
14 | pub object_kind: &'s str, | |
15 | pub setting_name: &'s str, | |
16 | } | |
17 | ||
18 | impl<'s> ObjectSettingPair<'s> { | |
19 | pub fn new(object_kind: &'s str, setting_name: &'s str) -> Self { | |
20 | Self { | |
21 | object_kind, | |
22 | setting_name, | |
23 | } | |
24 | } | |
25 | } |
giterated-models/src/update/mod.rs
@@ -1,22 +1,7 @@ | ||
1 | use crate::value::AnyValue; | |
2 | ||
3 | 1 | mod instance; |
4 | 2 | mod repository; |
5 | 3 | mod user; |
6 | 4 | |
7 | pub struct ValueUpdate { | |
8 | pub object: String, | |
9 | pub value_name: String, | |
10 | pub value: AnyValue<()>, | |
11 | } | |
12 | ||
13 | #[allow(unused)] | |
14 | pub struct SettingUpdate { | |
15 | object: String, | |
16 | value_name: String, | |
17 | value: AnyValue<()>, | |
18 | } | |
19 | ||
20 | 5 | pub enum GiteratedUpdateKind { |
21 | 6 | Instance, |
22 | 7 | Repository, |
giterated-models/src/value.rs
@@ -39,31 +39,17 @@ impl<O: GiteratedObject + Send, V: GiteratedObjectValue<Object = O>> GiteratedOp | ||
39 | 39 | type Failure = GetValueError; |
40 | 40 | } |
41 | 41 | |
42 | #[derive(Debug, Clone, Deserialize, Serialize)] | |
43 | #[serde(transparent)] | |
44 | pub struct AnyValue<O> { | |
45 | value: Value, | |
46 | #[serde(skip)] | |
47 | _marker: PhantomData<O>, | |
42 | #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] | |
43 | pub struct ObjectValuePair<'s> { | |
44 | pub object_kind: &'s str, | |
45 | pub value_name: &'s str, | |
48 | 46 | } |
49 | 47 | |
50 | impl<O> AnyValue<O> { | |
51 | pub unsafe fn from_raw(value: Value) -> Self { | |
48 | impl<'s> ObjectValuePair<'s> { | |
49 | pub fn new(object_kind: &'s str, value_name: &'s str) -> Self { | |
52 | 50 | Self { |
53 | value, | |
54 | _marker: Default::default(), | |
51 | object_kind, | |
52 | value_name, | |
55 | 53 | } |
56 | 54 | } |
57 | ||
58 | pub fn into_inner(self) -> Value { | |
59 | self.value | |
60 | } | |
61 | } | |
62 | ||
63 | impl<O: GiteratedObject> GiteratedObjectValue for AnyValue<O> { | |
64 | type Object = O; | |
65 | ||
66 | fn value_name() -> &'static str { | |
67 | todo!() | |
68 | } | |
69 | 55 | } |
giterated-plugin/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1" | ||
11 | 11 | thiserror = "1" |
12 | 12 | tracing = "0.1" |
13 | 13 | giterated-models = { path = "../giterated-models" } |
14 | giterated-static-runtime = { path = "giterated-static-runtime" } | |
14 | giterated-static-runtime = { path = "../giterated-runtime/giterated-static-runtime" } | |
15 | 15 | giterated-abi = { path = "../giterated-abi" } |
16 | 16 | semver = "*" |
17 | 17 | serde_json = "1.0" |
@@ -19,4 +19,4 @@ async-trait = "0.1" | ||
19 | 19 | serde = "*" |
20 | 20 | futures-util = "0.3.30" |
21 | 21 | tokio = { version = "1.32", features = [ "full" ] } |
22 | giterated-macros = { path = "giterated-macros" } | |
22 | \ No newline at end of file | |
22 | giterated-macros = { path = "../giterated-macros" } | |
22 | \ No newline at end of file |
giterated-plugin/src/future.rs
@@ -9,8 +9,6 @@ use std::{ | ||
9 | 9 | task::{Context, RawWaker, RawWakerVTable, Waker}, |
10 | 10 | }; |
11 | 11 | |
12 | use crate::{callback::RuntimeState, new_stack::PluginState}; | |
13 | ||
14 | 12 | #[repr(C)] |
15 | 13 | pub struct RuntimeWakerCallback { |
16 | 14 | callback: PluginState, |
giterated-plugin/src/lib.rs
@@ -1,38 +1,10 @@ | ||
1 | 1 | #![allow(improper_ctypes_definitions)] |
2 | 2 | |
3 | pub mod callback; | |
4 | 3 | pub mod future; |
5 | pub mod handle; | |
6 | pub mod new_stack; | |
7 | pub mod state; | |
8 | pub mod vtable; | |
9 | 4 | |
10 | 5 | #[macro_use] |
11 | 6 | extern crate tracing; |
12 | 7 | |
13 | use std::{marker::PhantomData, mem::forget}; | |
14 | ||
15 | use callback::RuntimeState; | |
16 | use dlopen2::wrapper::WrapperApi; | |
17 | ||
18 | use giterated_abi::vtable::VTable; | |
19 | use handle::PluginInitializationState; | |
20 | use new_stack::{FFIPluginMeta, PluginState}; | |
21 | ||
22 | use vtable::{HostVTable, Initialization}; | |
23 | ||
24 | #[derive(WrapperApi)] | |
25 | pub struct GiteratedPluginApi { | |
26 | plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta, | |
27 | load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable), | |
28 | load_initialization_vtable: unsafe extern "C" fn(vtable: &'static VTable<Initialization>), | |
29 | initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState, | |
30 | initialize_registration: unsafe extern "C" fn( | |
31 | init_state: *mut PluginInitializationState, | |
32 | ) -> *mut PluginInitializationState, | |
33 | load_type_metadata: unsafe extern "C" fn(metadata: *mut ()), | |
34 | } | |
35 | ||
36 | 8 | pub mod plugin { |
37 | 9 | pub use giterated_macros::plugin_init as init; |
38 | 10 | } |
giterated-plugin/src/local.rs
@@ -0,0 +1,302 @@ | ||
1 | mod local_runtime; | |
2 | ||
3 | use giterated_abi::{ | |
4 | callback::{Callback, CallbackPtr}, | |
5 | result::FfiError, | |
6 | value_ex::FfiValueUntyped, | |
7 | vtable::{ | |
8 | operation::{IntoOperationVTable, OperationVTable}, | |
9 | IntoObjectVTable, IntoSettingVTable, IntoValueVTable, Object, ObjectVTable, SettingVTable, | |
10 | VTable, ValueVTable, | |
11 | }, | |
12 | FfiValueRef, | |
13 | }; | |
14 | use giterated_models::{ | |
15 | object::GiteratedObject, operation::GiteratedOperation, settings::Setting, | |
16 | value::GiteratedObjectValue, | |
17 | }; | |
18 | use giterated_plugin::{ | |
19 | callback::{ | |
20 | IntoPluginOperationHandler, IntoPluginSettingGetter, IntoPluginSettingSetter, | |
21 | IntoPluginValueGetter, OperationHandlerCallback, SettingGetterCallback, | |
22 | ValueGetterCallback, | |
23 | }, | |
24 | handle::PluginInitializationState, | |
25 | new_stack::PluginState, | |
26 | vtable::Initialization, | |
27 | }; | |
28 | use tracing::trace_span; | |
29 | ||
30 | pub struct PluginStackBuilder<S> { | |
31 | init_state: *mut PluginInitializationState, | |
32 | vtable: &'static VTable<Initialization>, | |
33 | state: S, | |
34 | } | |
35 | ||
36 | impl<S> PluginStackBuilder<S> { | |
37 | pub fn new( | |
38 | plugin_state: S, | |
39 | state: *mut PluginInitializationState, | |
40 | vtable: &'static VTable<Initialization>, | |
41 | ) -> PluginStackBuilder<S> { | |
42 | PluginStackBuilder { | |
43 | init_state: state, | |
44 | vtable, | |
45 | state: plugin_state, | |
46 | } | |
47 | } | |
48 | ||
49 | pub fn object<O: IntoObjectVTable + GiteratedObject>(&mut self) -> &mut Self { | |
50 | let _guard = trace_span!("register object").entered(); | |
51 | ||
52 | let func = self.vtable.register_object; | |
53 | ||
54 | unsafe { | |
55 | func( | |
56 | self.init_state, | |
57 | O::object_name(), | |
58 | O::VTABLE | |
59 | ) | |
60 | }; | |
61 | ||
62 | self | |
63 | } | |
64 | ||
65 | pub fn register_operation<O, D>(&mut self) -> &mut Self | |
66 | where | |
67 | D: IntoOperationVTable<O> + GiteratedOperation<O>, | |
68 | O: GiteratedObject, | |
69 | { | |
70 | let _guard = trace_span!("register operation").entered(); | |
71 | ||
72 | unsafe { | |
73 | (self.vtable.register_operation)( | |
74 | self.init_state, | |
75 | O::object_name(), | |
76 | D::operation_name(), | |
77 | <D as IntoOperationVTable<O>>::VTABLE, | |
78 | ) | |
79 | } | |
80 | ||
81 | self | |
82 | } | |
83 | ||
84 | pub fn object_setting<O, OS, HG, HS>(&mut self, _get: HG, _set: HS) -> &mut Self | |
85 | where | |
86 | O: GiteratedObject, | |
87 | OS: IntoSettingVTable + Setting, | |
88 | HG: IntoPluginSettingGetter<S, O, OS>, | |
89 | HS: IntoPluginSettingSetter<S, O, OS>, | |
90 | { | |
91 | let _guard = trace_span!("register setting").entered(); | |
92 | ||
93 | unsafe { | |
94 | (self.vtable.register_setting)( | |
95 | self.init_state, | |
96 | O::object_name(), | |
97 | OS::name(), | |
98 | OS::VTABLE, | |
99 | ) | |
100 | } | |
101 | ||
102 | self | |
103 | } | |
104 | ||
105 | pub fn object_user_setting<O, OS>(&mut self) -> &mut Self | |
106 | where | |
107 | O: GiteratedObject, | |
108 | OS: IntoSettingVTable + Setting, | |
109 | { | |
110 | let _guard = trace_span!("register setting").entered(); | |
111 | ||
112 | unsafe { | |
113 | (self.vtable.register_setting)( | |
114 | self.init_state, | |
115 | O::object_name(), | |
116 | OS::name(), | |
117 | OS::VTABLE, | |
118 | ) | |
119 | } | |
120 | ||
121 | self | |
122 | } | |
123 | ||
124 | pub fn value<O, V, T>(&mut self, handler: T) -> &mut Self | |
125 | where | |
126 | O: GiteratedObject, | |
127 | V: IntoValueVTable + GiteratedObjectValue<Object = O>, | |
128 | T: IntoPluginValueGetter<S, O, V>, | |
129 | { | |
130 | let _guard = trace_span!("register value").entered(); | |
131 | ||
132 | unsafe { | |
133 | (self.vtable.register_value)( | |
134 | self.init_state, | |
135 | O::object_name(), | |
136 | V::value_name(), | |
137 | V::VTABLE, | |
138 | ) | |
139 | } | |
140 | ||
141 | // unsafe { | |
142 | // (self.vtable.value_getter)( | |
143 | // self.init_state, | |
144 | // O::object_name(), | |
145 | // V::value_name(), | |
146 | // ValueGetterCallback::new::<S, O, V, T>(handler), | |
147 | // ) | |
148 | // } | |
149 | ||
150 | self | |
151 | } | |
152 | ||
153 | pub fn operation< | |
154 | A, | |
155 | O: GiteratedObject + IntoObjectVTable, | |
156 | D: IntoOperationVTable<O> + GiteratedOperation<O>, | |
157 | T: IntoPluginOperationHandler<S, O, D, A>, | |
158 | >( | |
159 | &mut self, | |
160 | handler: T, | |
161 | ) -> &mut Self { | |
162 | let _guard = trace_span!("register operation handler").entered(); | |
163 | ||
164 | // unsafe { | |
165 | // (self.vtable.operation_handler)( | |
166 | // self.init_state, | |
167 | // O::object_name(), | |
168 | // D::operation_name(), | |
169 | // OperationHandlerCallback::new::<S, O, D, A, T>(handler), | |
170 | // ) | |
171 | // } | |
172 | ||
173 | // TODO: Yikes? | |
174 | self.object::<O>(); | |
175 | ||
176 | self.register_operation::<O, D>(); | |
177 | ||
178 | self | |
179 | } | |
180 | ||
181 | // pub fn value_getter<O, V, T>(&mut self, handler: T) -> &mut Self | |
182 | // where | |
183 | // O: GiteratedObject + IntoObjectVTable, | |
184 | // V: GiteratedObjectValue<Object = O> + IntoValueVTable<O>, | |
185 | // T: IntoPluginValueGetter<S, O, V>, | |
186 | // { | |
187 | // let _guard = trace_span!("register value_getter handler").entered(); | |
188 | ||
189 | // unsafe { | |
190 | // (self.vtable.value_getter)( | |
191 | // self.init_state, | |
192 | // O::object_name(), | |
193 | // V::value_name(), | |
194 | // ValueGetterCallback::new::<S, O, V, T>(handler), | |
195 | // ) | |
196 | // } | |
197 | ||
198 | // // TODO: Yikes? | |
199 | // self.object::<O>(); | |
200 | // self.value::<O, V>(); | |
201 | ||
202 | // self | |
203 | // } | |
204 | ||
205 | pub fn setting_getter<O, OS, T>(&mut self, handler: T) -> &mut Self | |
206 | where | |
207 | O: GiteratedObject + IntoObjectVTable, | |
208 | OS: Setting + IntoSettingVTable, | |
209 | T: IntoPluginSettingGetter<S, O, OS>, | |
210 | { | |
211 | let _guard = trace_span!("register setting_getter handler").entered(); | |
212 | ||
213 | // unsafe { | |
214 | // (self.vtable.setting_getter)( | |
215 | // self.init_state, | |
216 | // O::object_name(), | |
217 | // OS::name(), | |
218 | // SettingGetterCallback::new::<S, O, OS, T>(handler), | |
219 | // ) | |
220 | // } | |
221 | ||
222 | self.object::<O>(); | |
223 | ||
224 | unsafe { | |
225 | (self.vtable.register_setting)( | |
226 | self.init_state, | |
227 | O::object_name(), | |
228 | OS::name(), | |
229 | OS::VTABLE, | |
230 | ) | |
231 | }; | |
232 | ||
233 | self | |
234 | } | |
235 | } | |
236 | ||
237 | pub trait ValueSettingExt<PS> { | |
238 | fn value_setting<O, VS, HG, HS>(&mut self, get: HG, set: HS) -> &mut Self | |
239 | where | |
240 | O: GiteratedObject + IntoObjectVTable + 'static, | |
241 | VS: GiteratedObjectValue<Object = O> + IntoValueVTable + Setting + IntoSettingVTable, | |
242 | HG: IntoPluginSettingGetter<PS, O, VS>, | |
243 | HS: IntoPluginSettingSetter<PS, O, VS>; | |
244 | } | |
245 | ||
246 | impl<PS> ValueSettingExt<PS> for PluginStackBuilder<PS> { | |
247 | fn value_setting<O, VS, HG, HS>(&mut self, _get: HG, _set: HS) -> &mut Self | |
248 | where | |
249 | O: GiteratedObject + IntoObjectVTable + 'static, | |
250 | VS: GiteratedObjectValue<Object = O> + IntoValueVTable + Setting + IntoSettingVTable, | |
251 | HG: IntoPluginSettingGetter<PS, O, VS>, | |
252 | HS: IntoPluginSettingSetter<PS, O, VS>, | |
253 | { | |
254 | self | |
255 | } | |
256 | } | |
257 | ||
258 | #[derive(Clone, Copy)] | |
259 | pub struct ValueSettingGetterCallback; | |
260 | ||
261 | impl Callback for ValueSettingGetterCallback { | |
262 | type CallbackFunc = unsafe extern "C" fn( | |
263 | callback: CallbackPtr<ValueSettingGetterCallback>, | |
264 | state: &PluginState, | |
265 | object: FfiValueRef<Object>, | |
266 | ) -> Result<FfiValueUntyped, FfiError>; | |
267 | } | |
268 | ||
269 | pub trait ValueSettingGetter<S, O, V> { | |
270 | unsafe extern "C" fn get_value( | |
271 | callback: CallbackPtr<ValueSettingGetterCallback>, | |
272 | state: &PluginState, | |
273 | object: FfiValueRef<Object>, | |
274 | ) -> Result<FfiValueUntyped, FfiError>; | |
275 | ||
276 | fn callback_ptr(&self) -> CallbackPtr<ValueSettingGetterCallback>; | |
277 | } | |
278 | ||
279 | impl<S, O, VS, HG> ValueSettingGetter<S, O, VS> for HG | |
280 | where | |
281 | O: GiteratedObject, | |
282 | VS: GiteratedObjectValue<Object = O>, | |
283 | HG: IntoPluginSettingGetter<S, O, VS>, | |
284 | { | |
285 | unsafe extern "C" fn get_value( | |
286 | _callback: CallbackPtr<ValueSettingGetterCallback>, | |
287 | _state: &PluginState, | |
288 | _object: FfiValueRef<Object>, | |
289 | ) -> Result<FfiValueUntyped, FfiError> { | |
290 | // let result = HG::get_setting(callback, state, object)?; | |
291 | ||
292 | // let setting = *result.transmute_owned::<VS>(); | |
293 | ||
294 | todo!(); | |
295 | ||
296 | // Ok(NewAnyValue::new(setting)) | |
297 | } | |
298 | ||
299 | fn callback_ptr(&self) -> CallbackPtr<ValueSettingGetterCallback> { | |
300 | todo!() | |
301 | } | |
302 | } |
giterated-runtime/giterated-static-runtime/Cargo.toml
@@ -0,0 +1,8 @@ | ||
1 | [package] | |
2 | name = "giterated-static-runtime" | |
3 | version = "0.1.0" | |
4 | edition = "2021" | |
5 | ||
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | |
7 | ||
8 | [dependencies] |
giterated-runtime/giterated-static-runtime/src/lib.rs
@@ -0,0 +1,26 @@ | ||
1 | use std::{mem::MaybeUninit, ptr::NonNull}; | |
2 | ||
3 | struct RuntimePointer(NonNull<()>); | |
4 | ||
5 | unsafe impl Send for RuntimePointer {} | |
6 | unsafe impl Sync for RuntimePointer {} | |
7 | ||
8 | static mut GITERATED_RUNTIME: MaybeUninit<RuntimePointer> = MaybeUninit::zeroed(); | |
9 | ||
10 | pub unsafe fn initialize_runtime(runtime_pointer: *mut ()) { | |
11 | GITERATED_RUNTIME.write(RuntimePointer(NonNull::new(runtime_pointer).unwrap())); | |
12 | } | |
13 | ||
14 | pub unsafe fn get_runtime_reference() -> NonNull<()> { | |
15 | GITERATED_RUNTIME.assume_init_read().0 | |
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-runtime/src/api.rs
@@ -0,0 +1,11 @@ | ||
1 | #[derive(WrapperApi)] | |
2 | pub struct GiteratedPluginApi { | |
3 | plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta, | |
4 | load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable), | |
5 | load_initialization_vtable: unsafe extern "C" fn(vtable: &'static VTable<Initialization>), | |
6 | initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState, | |
7 | initialize_registration: unsafe extern "C" fn( | |
8 | init_state: *mut PluginInitializationState, | |
9 | ) -> *mut PluginInitializationState, | |
10 | load_type_metadata: unsafe extern "C" fn(metadata: *mut ()), | |
11 | } | |
11 | \ No newline at end of file |
giterated-runtime/src/handle.rs
@@ -0,0 +1,270 @@ | ||
1 | use std::{collections::HashMap, marker::PhantomData, sync::Arc}; | |
2 | ||
3 | use anyhow::Error; | |
4 | use dlopen2::wrapper::Container; | |
5 | use giterated_abi::{ | |
6 | callback::CallbackPtr, | |
7 | vtable::{operation::Operation, Object, Setting, VTable, Value}, | |
8 | }; | |
9 | use giterated_models::operation::OperationState; | |
10 | use semver::Version; | |
11 | use tracing::{debug, trace}; | |
12 | ||
13 | use crate::{ | |
14 | callback::{ | |
15 | OperationHandlerCallback, RuntimeState, SettingGetterCallback, ValueGetterCallback, | |
16 | }, | |
17 | new_stack::{ | |
18 | ObjectOperationPair, ObjectSettingPair, ObjectValuePair, PluginMeta, PluginState, | |
19 | TypeMetadata, | |
20 | }, | |
21 | vtable::Initialization, | |
22 | GiteratedPluginApi, | |
23 | }; | |
24 | ||
25 | #[derive(Clone)] | |
26 | pub struct PluginHandle { | |
27 | pub meta: PluginMeta, | |
28 | pub raw: Arc<Container<GiteratedPluginApi>>, | |
29 | pub domain_metadata: Arc<TypeMetadata>, | |
30 | pub state: PluginState, | |
31 | } | |
32 | ||
33 | unsafe impl Send for PluginHandle {} | |
34 | unsafe impl Sync for PluginHandle {} | |
35 | ||
36 | impl PluginHandle { | |
37 | pub fn from_dylib(path: &str) -> Result<Self, CreationError> { | |
38 | let mut handle = unsafe { Container::load(path) }?; | |
39 | ||
40 | // Initialize the raw handle | |
41 | let init_state = | |
42 | Self::initialize_raw_handle(&mut handle, &unsafe { RuntimeState::from_static() })?; | |
43 | ||
44 | let metadata = Self::get_meta(&mut handle)?; | |
45 | ||
46 | let initalization = Self::initialize_registration(&mut handle)?; | |
47 | ||
48 | let type_metadata = Box::new(initalization.type_metadata.clone()); | |
49 | ||
50 | unsafe { handle.load_type_metadata(unsafe { Box::into_raw(type_metadata).cast() }) }; | |
51 | ||
52 | trace!( | |
53 | "Loaded plugin {} (Version: {})", | |
54 | metadata.name, | |
55 | metadata.version | |
56 | ); | |
57 | ||
58 | Ok(Self { | |
59 | raw: Arc::new(handle), | |
60 | meta: metadata, | |
61 | state: init_state, | |
62 | domain_metadata: todo!(), | |
63 | }) | |
64 | } | |
65 | ||
66 | /// Builds the Plugin's Substack. | |
67 | /// | |
68 | /// Builds the Plugin into a substack, which can then be provided to the Giterated Runtime. | |
69 | pub fn build_substack(&mut self) -> Result<(), Error> { | |
70 | todo!() | |
71 | } | |
72 | ||
73 | fn get_meta(handle: &mut Container<GiteratedPluginApi>) -> Result<PluginMeta, CreationError> { | |
74 | let meta = unsafe { handle.plugin_meta() }; | |
75 | ||
76 | let name = unsafe { std::slice::from_raw_parts(meta.name, meta.name_len) }; | |
77 | let version = unsafe { std::slice::from_raw_parts(meta.version, meta.version_len) }; | |
78 | ||
79 | let name = std::str::from_utf8(name).unwrap(); | |
80 | let version = std::str::from_utf8(version).unwrap(); | |
81 | ||
82 | Ok(PluginMeta { | |
83 | name: String::from(name), | |
84 | version: Version::parse(version).unwrap(), | |
85 | }) | |
86 | } | |
87 | ||
88 | pub fn initialize_registration( | |
89 | handle: &mut Container<GiteratedPluginApi>, | |
90 | ) -> Result<PluginInitializationState, CreationError> { | |
91 | debug!("Initializing plugin registration..."); | |
92 | let mut builder = PluginInitializationTable::default(); | |
93 | ||
94 | // SAFETY: The lifetime of the returned type is only valid as long | |
95 | // as the builder that returned it lives | |
96 | let func_table = unsafe { builder.func_table() }; | |
97 | ||
98 | let state = Box::new(PluginInitializationState::new()); | |
99 | ||
100 | unsafe { handle.load_initialization_vtable(&func_table) }; | |
101 | let state = unsafe { handle.initialize_registration(Box::into_raw(state)) }; | |
102 | ||
103 | debug!("Plugin handle initialized!"); | |
104 | Ok(unsafe { *Box::from_raw(state) }) | |
105 | } | |
106 | ||
107 | fn initialize_raw_handle( | |
108 | handle: &mut Container<GiteratedPluginApi>, | |
109 | runtime_state: &RuntimeState, | |
110 | ) -> Result<PluginState, CreationError> { | |
111 | debug!("Initializing plugin handle..."); | |
112 | ||
113 | let state = unsafe { handle.initialize(runtime_state) }; | |
114 | ||
115 | debug!("Plugin handle initialized!"); | |
116 | ||
117 | Ok(state) | |
118 | } | |
119 | } | |
120 | ||
121 | #[derive(Debug, thiserror::Error)] | |
122 | pub enum CreationError { | |
123 | #[error("an error occured opening the library {0}")] | |
124 | LoadingLibrary(#[from] dlopen2::Error), | |
125 | } | |
126 | ||
127 | pub struct PluginSubstackBuilder {} | |
128 | ||
129 | #[derive(Default)] | |
130 | pub struct PluginInitializationState { | |
131 | pub type_metadata: TypeMetadata, | |
132 | pub operation_handlers: | |
133 | HashMap<ObjectOperationPair<'static>, CallbackPtr<OperationHandlerCallback>>, | |
134 | pub value_getters: HashMap<ObjectValuePair<'static>, CallbackPtr<ValueGetterCallback>>, | |
135 | pub setting_getters: HashMap<ObjectSettingPair<'static>, CallbackPtr<SettingGetterCallback>>, | |
136 | } | |
137 | ||
138 | impl PluginInitializationState { | |
139 | pub fn new() -> Self { | |
140 | Self::default() | |
141 | } | |
142 | } | |
143 | ||
144 | #[derive(Default)] | |
145 | pub struct PluginInitializationTable<'a> { | |
146 | _marker: PhantomData<&'a ()>, | |
147 | } | |
148 | ||
149 | impl<'a> PluginInitializationTable<'a> { | |
150 | pub unsafe fn func_table(&mut self) -> &'static VTable<Initialization> { | |
151 | VTable::new(&Initialization { | |
152 | register_object, | |
153 | register_operation, | |
154 | register_setting, | |
155 | register_value, | |
156 | operation_handler, | |
157 | value_getter, | |
158 | setting_getter, | |
159 | }) | |
160 | } | |
161 | } | |
162 | ||
163 | unsafe extern "C" fn register_object( | |
164 | state: *mut PluginInitializationState, | |
165 | object_kind: &'static str, | |
166 | vtable: &'static VTable<Object>, | |
167 | ) { | |
168 | let mut state = Box::from_raw(state); | |
169 | ||
170 | state.type_metadata.register_object(object_kind, vtable); | |
171 | ||
172 | Box::into_raw(state); | |
173 | } | |
174 | ||
175 | unsafe extern "C" fn register_operation( | |
176 | state: *mut PluginInitializationState, | |
177 | object_kind: &'static str, | |
178 | operation_name: &'static str, | |
179 | vtable: &'static VTable<Operation>, | |
180 | ) { | |
181 | let mut state = Box::from_raw(state); | |
182 | ||
183 | state | |
184 | .type_metadata | |
185 | .register_operation(object_kind, operation_name, vtable); | |
186 | ||
187 | Box::into_raw(state); | |
188 | } | |
189 | ||
190 | unsafe extern "C" fn register_setting( | |
191 | state: *mut PluginInitializationState, | |
192 | object_kind: &'static str, | |
193 | setting_name: &'static str, | |
194 | vtable: &'static VTable<Setting>, | |
195 | ) { | |
196 | let mut state = Box::from_raw(state); | |
197 | ||
198 | state | |
199 | .type_metadata | |
200 | .register_setting(object_kind, setting_name, vtable); | |
201 | ||
202 | Box::into_raw(state); | |
203 | } | |
204 | ||
205 | unsafe extern "C" fn register_value( | |
206 | state: *mut PluginInitializationState, | |
207 | object_kind: &'static str, | |
208 | value_name: &'static str, | |
209 | vtable: &'static VTable<Value>, | |
210 | ) { | |
211 | let mut state = Box::from_raw(state); | |
212 | ||
213 | state | |
214 | .type_metadata | |
215 | .register_value(object_kind, value_name, vtable); | |
216 | ||
217 | Box::into_raw(state); | |
218 | } | |
219 | ||
220 | unsafe extern "C" fn operation_handler( | |
221 | state: *mut PluginInitializationState, | |
222 | object_kind: &'static str, | |
223 | operation_name: &'static str, | |
224 | handler: CallbackPtr<OperationHandlerCallback>, | |
225 | ) { | |
226 | let mut state = Box::from_raw(state); | |
227 | ||
228 | trace!("Operation handler for {}::{}", object_kind, operation_name); | |
229 | ||
230 | state.operation_handlers.insert( | |
231 | ObjectOperationPair::new(object_kind, operation_name), | |
232 | handler, | |
233 | ); | |
234 | ||
235 | Box::into_raw(state); | |
236 | } | |
237 | ||
238 | unsafe extern "C" fn value_getter( | |
239 | state: *mut PluginInitializationState, | |
240 | object_kind: &'static str, | |
241 | value_name: &'static str, | |
242 | handler: CallbackPtr<ValueGetterCallback>, | |
243 | ) { | |
244 | let mut state = Box::from_raw(state); | |
245 | ||
246 | trace!("Value getter for {}::{}", object_kind, value_name); | |
247 | ||
248 | state | |
249 | .value_getters | |
250 | .insert(ObjectValuePair::new(object_kind, value_name), handler); | |
251 | ||
252 | Box::into_raw(state); | |
253 | } | |
254 | ||
255 | unsafe extern "C" fn setting_getter( | |
256 | state: *mut PluginInitializationState, | |
257 | object_kind: &'static str, | |
258 | setting_name: &'static str, | |
259 | handler: CallbackPtr<SettingGetterCallback>, | |
260 | ) { | |
261 | let mut state = Box::from_raw(state); | |
262 | ||
263 | trace!("Setting getter for {}::{}", object_kind, setting_name); | |
264 | ||
265 | state | |
266 | .setting_getters | |
267 | .insert(ObjectSettingPair::new(object_kind, setting_name), handler); | |
268 | ||
269 | Box::into_raw(state); | |
270 | } |
giterated-runtime/src/lib.rs
@@ -0,0 +1,394 @@ | ||
1 | pub struct Runtime { | |
2 | plugins: Vec<PluginHandle>, | |
3 | handlers: RuntimeHandlers, | |
4 | } | |
5 | ||
6 | pub struct FfiRuntimeMetadata { | |
7 | runtime: PluginState, | |
8 | } | |
9 | ||
10 | impl IntoRuntimeVtable for Runtime { | |
11 | unsafe extern "C" fn handle( | |
12 | _this: PluginState, | |
13 | _object_kind: FfiSliceRef<str>, | |
14 | _operation_name: FfiSliceRef<str>, | |
15 | _object: FfiSliceRef<str>, | |
16 | _operation_payload: FfiSliceRef<[u8]>, | |
17 | _operation_state: FfiSliceRef<[u8]>, | |
18 | ) -> RuntimeFuture<FfiResult<FfiValueUntyped, OperationError<giterated_abi::result::FfiError>>> | |
19 | { | |
20 | todo!() | |
21 | } | |
22 | ||
23 | unsafe extern "C" fn get_object( | |
24 | this: PluginState, | |
25 | object_str: &str, | |
26 | operation_state: *mut OperationState, | |
27 | ) -> FfiResult<Object, OperationError<giterated_models::object::ObjectRequestError>> { | |
28 | let runtime_state = unsafe { RuntimeState::from_static() }; | |
29 | ||
30 | let type_metada = runtime_state | |
31 | .vtable | |
32 | .type_metadata | |
33 | .as_ref() | |
34 | .unwrap_or_else(|| { | |
35 | let runtime = this.transmute_ref::<Runtime>(); | |
36 | ||
37 | &runtime.plugins.first().unwrap().domain_metadata | |
38 | }); | |
39 | ||
40 | // for (object_type, object_vtable) in &type_metada.objects { | |
41 | // if let Ok(object) = (object_vtable.from_str)(object_str) { | |
42 | // return Ok(object); | |
43 | // } | |
44 | // } | |
45 | ||
46 | // Err(OperationError::Operation(ObjectRequestError::Invalid)) | |
47 | ||
48 | todo!() | |
49 | } | |
50 | } | |
51 | ||
52 | impl Runtime { | |
53 | pub fn new() -> Box<Self> { | |
54 | Box::new(Self { | |
55 | plugins: vec![], | |
56 | handlers: RuntimeHandlers::default(), | |
57 | }) | |
58 | } | |
59 | ||
60 | pub fn state(self: &Box<Self>) -> RuntimeState { | |
61 | RuntimeState { | |
62 | vtable: RuntimeVTable { | |
63 | runtime: PluginState::from(self), | |
64 | handle_fn: <Runtime as IntoRuntimeVtable>::handle, | |
65 | get_object: <Runtime as IntoRuntimeVtable>::get_object, | |
66 | type_metadata: unsafe { TypeMetadata::from_static() }, | |
67 | }, | |
68 | } | |
69 | } | |
70 | ||
71 | pub fn insert_plugin( | |
72 | &mut self, | |
73 | mut plugin: PluginHandle, | |
74 | mut initialization: PluginInitializationState, | |
75 | ) { | |
76 | let _guard = debug_span!("inserting plugin", meta = debug(&plugin.meta)).entered(); | |
77 | ||
78 | for (pair, callback) in initialization.operation_handlers.drain() { | |
79 | let _guard = | |
80 | trace_span!("processing operation handler callbacks", pair = debug(pair)).entered(); | |
81 | ||
82 | if self | |
83 | .handlers | |
84 | .operation_handlers | |
85 | .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback)) | |
86 | .is_some() | |
87 | { | |
88 | warn!("Warning! Insertion of handler for overwrote a previous handler.") | |
89 | } | |
90 | ||
91 | trace!("Insertion of operation handler successful") | |
92 | } | |
93 | ||
94 | for (pair, callback) in initialization.value_getters.drain() { | |
95 | let _guard = | |
96 | trace_span!("processing value getter callbacks", pair = debug(pair)).entered(); | |
97 | ||
98 | if self | |
99 | .handlers | |
100 | .value_getters | |
101 | .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback)) | |
102 | .is_some() | |
103 | { | |
104 | warn!("Warning! Insertion of handler for overwrote a previous handler.") | |
105 | } | |
106 | ||
107 | trace!("Insertion of operation handler successful") | |
108 | } | |
109 | ||
110 | for (pair, callback) in initialization.setting_getters { | |
111 | let _guard = | |
112 | trace_span!("processing setting getter callbacks", pair = debug(pair)).entered(); | |
113 | ||
114 | if self | |
115 | .handlers | |
116 | .setting_getters | |
117 | .insert(pair, (RuntimeDomain::from_plugin(&plugin), callback)) | |
118 | .is_some() | |
119 | { | |
120 | warn!("Warning! Insertion of setting handler for overwrote a previous handler.") | |
121 | } | |
122 | ||
123 | trace!("Insertion of setting handler successful") | |
124 | } | |
125 | ||
126 | self.plugins.push(plugin); | |
127 | } | |
128 | ||
129 | pub fn init(self: Box<Self>) { | |
130 | unsafe { giterated_static_runtime::initialize_runtime(Box::into_raw(self).cast::<()>()) } | |
131 | } | |
132 | ||
133 | // pub async fn handle( | |
134 | // &self, | |
135 | // object_kind: &str, | |
136 | // operation_name: &str, | |
137 | // object: &str, | |
138 | // operation_payload: &[u8], | |
139 | // operation_state: &OperationState, | |
140 | // ) -> Result<AnySuccess, OperationError<AnyFailure>> { | |
141 | // let rules = self.handlers.handle_operation(object_kind, operation_name); | |
142 | ||
143 | // let state = self.state(operation_state); | |
144 | ||
145 | // rules.handle(&state, object, operation_payload).await | |
146 | // } | |
147 | ||
148 | pub fn handle_typed<O: GiteratedObject, D: GiteratedOperation<O>>( | |
149 | &self, | |
150 | _object: O, | |
151 | _operation: D, | |
152 | ) -> Result<D::Success, OperationError<D::Failure>> { | |
153 | todo!() | |
154 | } | |
155 | } | |
156 | ||
157 | #[derive(Default)] | |
158 | pub struct RuntimeHandlers { | |
159 | operation_handlers: HashMap< | |
160 | ObjectOperationPair<'static>, | |
161 | (RuntimeDomain, CallbackPtr<OperationHandlerCallback>), | |
162 | >, | |
163 | value_getters: | |
164 | HashMap<ObjectValuePair<'static>, (RuntimeDomain, CallbackPtr<ValueGetterCallback>)>, | |
165 | setting_getters: | |
166 | HashMap<ObjectSettingPair<'static>, (RuntimeDomain, CallbackPtr<SettingGetterCallback>)>, | |
167 | value_change: | |
168 | HashMap<ObjectValuePair<'static>, (RuntimeDomain, CallbackPtr<ValueChangeCallback>)>, | |
169 | setting_change: | |
170 | HashMap<ObjectSettingPair<'static>, (RuntimeDomain, CallbackPtr<SettingChangeCallback>)>, | |
171 | } | |
172 | ||
173 | unsafe impl Send for RuntimeHandlers {} | |
174 | unsafe impl Sync for RuntimeHandlers {} | |
175 | ||
176 | impl RuntimeHandlers { | |
177 | pub fn operation_handler( | |
178 | &mut self, | |
179 | pair: ObjectOperationPair<'static>, | |
180 | handler: CallbackPtr<OperationHandlerCallback>, | |
181 | domain: RuntimeDomain, | |
182 | ) { | |
183 | trace!( | |
184 | "Inserting operation handler for {}::{}", | |
185 | pair.object_kind, | |
186 | pair.operation_name | |
187 | ); | |
188 | ||
189 | // There can only be one handler per operation (at least for now?), send a warning if | |
190 | // a newly registered handler overwrites the previous handler. | |
191 | if self | |
192 | .operation_handlers | |
193 | .insert(pair, (domain, handler)) | |
194 | .is_some() | |
195 | { | |
196 | debug!("Warning! A newly inserted operation handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.operation_name); | |
197 | } | |
198 | } | |
199 | ||
200 | pub fn value_getter( | |
201 | &mut self, | |
202 | pair: ObjectValuePair<'static>, | |
203 | handler: CallbackPtr<ValueGetterCallback>, | |
204 | domain: RuntimeDomain, | |
205 | ) { | |
206 | trace!( | |
207 | "Inserting value getter for {}::{}", | |
208 | pair.object_kind, | |
209 | pair.value_name | |
210 | ); | |
211 | ||
212 | if self.value_getters.insert(pair, (domain, handler)).is_some() { | |
213 | debug!( | |
214 | "Warning! A newly inserted value getter for {}::{} overwrites a previous handler.", | |
215 | pair.object_kind, pair.value_name | |
216 | ); | |
217 | } | |
218 | } | |
219 | ||
220 | pub fn setting_getter( | |
221 | &mut self, | |
222 | pair: ObjectSettingPair<'static>, | |
223 | handler: CallbackPtr<SettingGetterCallback>, | |
224 | domain: RuntimeDomain, | |
225 | ) { | |
226 | trace!( | |
227 | "Inserting setting getter for {}::{}", | |
228 | pair.object_kind, | |
229 | pair.setting_name | |
230 | ); | |
231 | ||
232 | if self | |
233 | .setting_getters | |
234 | .insert(pair, (domain, handler)) | |
235 | .is_some() | |
236 | { | |
237 | debug!("Warning! A newly inserted setting getter for {}::{} overwrites a previous handler.", pair.object_kind, pair.setting_name); | |
238 | } | |
239 | } | |
240 | ||
241 | pub fn value_change( | |
242 | &mut self, | |
243 | pair: ObjectValuePair<'static>, | |
244 | handler: CallbackPtr<ValueChangeCallback>, | |
245 | domain: RuntimeDomain, | |
246 | ) { | |
247 | trace!( | |
248 | "Inserting value change handler for {}::{}", | |
249 | pair.object_kind, | |
250 | pair.value_name | |
251 | ); | |
252 | ||
253 | if self.value_change.insert(pair, (domain, handler)).is_some() { | |
254 | debug!("Warning! A newly inserted value change handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.value_name); | |
255 | panic!("Not intended"); | |
256 | } | |
257 | } | |
258 | ||
259 | pub fn setting_change( | |
260 | &mut self, | |
261 | pair: ObjectSettingPair<'static>, | |
262 | handler: CallbackPtr<SettingChangeCallback>, | |
263 | domain: RuntimeDomain, | |
264 | ) { | |
265 | trace!( | |
266 | "Inserting setting change handler for {}::{}", | |
267 | pair.object_kind, | |
268 | pair.setting_name | |
269 | ); | |
270 | ||
271 | if self | |
272 | .setting_change | |
273 | .insert(pair, (domain, handler)) | |
274 | .is_some() | |
275 | { | |
276 | debug!("Warning! A newly inserted setting change handler for {}::{} overwrites a previous handler.", pair.object_kind, pair.setting_name); | |
277 | panic!("Not intended"); | |
278 | } | |
279 | } | |
280 | } | |
281 | ||
282 | impl RuntimeHandlers { | |
283 | pub fn handle_operation<'o>( | |
284 | &'o self, | |
285 | object_kind: &'o str, | |
286 | operation_name: &'o str, | |
287 | ) -> OperationHandlerRules<'o> { | |
288 | OperationHandlerRules::new(object_kind, operation_name, self) | |
289 | } | |
290 | } | |
291 | ||
292 | pub struct RuntimeDomain { | |
293 | plugin: PluginHandle, | |
294 | } | |
295 | ||
296 | impl RuntimeDomain { | |
297 | pub fn from_plugin(plugin: &PluginHandle) -> Self { | |
298 | Self { | |
299 | plugin: plugin.clone(), | |
300 | } | |
301 | } | |
302 | ||
303 | pub fn object_vtable(&self, object_kind: &str) -> Option<&'static VTable<Object>> { | |
304 | self.plugin | |
305 | .domain_metadata | |
306 | .objects | |
307 | .get(object_kind) | |
308 | .copied() | |
309 | } | |
310 | ||
311 | pub fn operation_vtable( | |
312 | &self, | |
313 | object_kind: &str, | |
314 | operation_name: &str, | |
315 | ) -> Option<&'static VTable<Operation>> { | |
316 | self.plugin | |
317 | .domain_metadata | |
318 | .operations | |
319 | .get(&ObjectOperationPair::new(object_kind, operation_name)) | |
320 | .copied() | |
321 | } | |
322 | ||
323 | pub fn setting_vtable( | |
324 | &self, | |
325 | object_kind: &str, | |
326 | setting_name: &str, | |
327 | ) -> Option<&'static VTable<Setting>> { | |
328 | self.plugin | |
329 | .domain_metadata | |
330 | .settings | |
331 | .get(&ObjectSettingPair::new(object_kind, setting_name)) | |
332 | .copied() | |
333 | } | |
334 | ||
335 | pub fn value_vtable( | |
336 | &self, | |
337 | object_kind: &str, | |
338 | value_name: &str, | |
339 | ) -> Option<&'static VTable<Value>> { | |
340 | self.plugin | |
341 | .domain_metadata | |
342 | .values | |
343 | .get(&ObjectValuePair::new(object_kind, value_name)) | |
344 | .copied() | |
345 | } | |
346 | } | |
347 | ||
348 | #[derive(Clone, Debug)] | |
349 | pub struct PluginMeta { | |
350 | pub name: String, | |
351 | pub version: Version, | |
352 | } | |
353 | ||
354 | #[repr(C)] | |
355 | pub struct FFIPluginMeta { | |
356 | pub name: *const u8, | |
357 | pub name_len: usize, | |
358 | pub version: *const u8, | |
359 | pub version_len: usize, | |
360 | } | |
361 | ||
362 | pub struct RuntimePlugin { | |
363 | handle: PluginHandle, | |
364 | type_metadata: Arc<TypeMetadata>, | |
365 | } | |
366 | ||
367 | impl RuntimePlugin { | |
368 | pub fn plugin_meta(&self) -> PluginMeta { | |
369 | let meta = unsafe { self.handle.raw.plugin_meta() }; | |
370 | ||
371 | let name = unsafe { std::slice::from_raw_parts(meta.name, meta.name_len) }; | |
372 | let version = unsafe { std::slice::from_raw_parts(meta.version, meta.version_len) }; | |
373 | ||
374 | let name = std::str::from_utf8(name).unwrap(); | |
375 | let version = std::str::from_utf8(version).unwrap(); | |
376 | ||
377 | PluginMeta { | |
378 | name: String::from(name), | |
379 | version: Version::parse(version).unwrap(), | |
380 | } | |
381 | } | |
382 | } | |
383 | ||
384 | #[derive(WrapperApi)] | |
385 | pub struct GiteratedPluginApi { | |
386 | plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta, | |
387 | load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable), | |
388 | load_initialization_vtable: unsafe extern "C" fn(vtable: &'static VTable<Initialization>), | |
389 | initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState, | |
390 | initialize_registration: unsafe extern "C" fn( | |
391 | init_state: *mut PluginInitializationState, | |
392 | ) -> *mut PluginInitializationState, | |
393 | load_type_metadata: unsafe extern "C" fn(metadata: *mut ()), | |
394 | } |
plugins/example-plugin/Cargo.toml
@@ -12,8 +12,7 @@ crate-type = ["dylib"] | ||
12 | 12 | |
13 | 13 | [dependencies] |
14 | 14 | giterated-plugin = { path = "../../giterated-plugin" } |
15 | giterated-plugin-sys = { path = "../../giterated-plugin/giterated-plugin-sys" } | |
16 | giterated-static-runtime = { path = "../../giterated-plugin/giterated-static-runtime" } | |
15 | giterated-static-runtime = { path = "../../giterated-runtime/giterated-static-runtime" } | |
17 | 16 | dlopen2 = "0.6" |
18 | 17 | tracing-subscriber = "0.3" |
19 | 18 | giterated-models = { path = "../../giterated-models" } |
plugins/example-plugin/src/lib.rs
@@ -1,5 +1,9 @@ | ||
1 | 1 | use anyhow::Error; |
2 | use giterated_models::{error::OperationError, object::{ObjectRequest, ObjectRequestError, ObjectResponse}, user::{DisplayName, User}}; | |
2 | use giterated_models::{ | |
3 | error::OperationError, | |
4 | object::{ObjectRequest, ObjectRequestError, ObjectResponse}, | |
5 | user::{DisplayName, User}, | |
6 | }; | |
3 | 7 | use giterated_plugin::{new_stack::State, plugin}; |
4 | 8 | |
5 | 9 | plugin!( |
@@ -20,9 +24,7 @@ struct PluginState; | ||
20 | 24 | pub fn init(builder: &mut PluginStackBuilder) -> Result<(), Error> { |
21 | 25 | builder.insert_state(State); |
22 | 26 | |
23 | builder | |
24 | .object::<Instance>() | |
25 | .object::<User>(); | |
27 | builder.object::<Instance>().object::<User>(); | |
26 | 28 | |
27 | 29 | builder.value(value_getter); |
28 | 30 | builder.setting_getter(setting_getter); |
@@ -33,14 +35,14 @@ pub fn init(builder: &mut PluginStackBuilder) -> Result<(), Error> { | ||
33 | 35 | async fn handler( |
34 | 36 | object: User, |
35 | 37 | operation: ObjectRequest, |
36 | state_extractor: State<PluginState> | |
38 | state_extractor: State<PluginState>, | |
37 | 39 | ) -> Result<ObjectResponse, OperationError<ObjectRequestError>> { |
38 | 40 | todo!() |
39 | 41 | } |
40 | 42 | |
41 | 43 | async fn setting_getter( |
42 | 44 | object: User, |
43 | state_extractor: State<PluginState> | |
45 | state_extractor: State<PluginState>, | |
44 | 46 | ) -> Result<DisplayName, OperationError<Error>> { |
45 | 47 | todo!() |
46 | } | |
46 | \ No newline at end of file | |
48 | } |
plugins/giterated-backend/Cargo.toml
@@ -13,7 +13,6 @@ anyhow = "1" | ||
13 | 13 | thiserror = "1" |
14 | 14 | sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-native-tls", "postgres", "macros", "migrate", "chrono" ] } |
15 | 15 | tokio = { version = "1.32", features = [ "full" ] } |
16 | giterated-plugin-sys = { path = "../../giterated-plugin/giterated-plugin-sys" } | |
17 | 16 | toml = { version = "0.8" } |
18 | 17 | tracing = "0.1" |
19 | 18 | tracing-subscriber = "0.3" |
plugins/giterated-issues/Cargo.toml
@@ -18,7 +18,6 @@ anyhow = "1" | ||
18 | 18 | thiserror = "1" |
19 | 19 | sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-native-tls", "postgres", "macros", "migrate", "chrono" ] } |
20 | 20 | tokio = { version = "1.32", features = [ "full" ] } |
21 | giterated-plugin-sys = { path = "../../giterated-plugin/giterated-plugin-sys" } | |
22 | 21 | toml = { version = "0.8" } |
23 | 22 | tracing = "0.1" |
24 | 23 | tracing-subscriber = "0.3" |
plugins/giterated-protocol/Cargo.toml
@@ -15,7 +15,6 @@ giterated-plugin = { path = "../../giterated-plugin" } | ||
15 | 15 | giterated-models = { path = "../../giterated-models" } |
16 | 16 | serde = { version = "1.0", features = [ "derive" ]} |
17 | 17 | anyhow = "1" |
18 | giterated-plugin-sys = { path = "../../giterated-plugin/giterated-plugin-sys" } | |
19 | 18 | toml = { version = "0.8" } |
20 | 19 | tracing = "0.1" |
21 | 20 | tracing-subscriber = "0.3" |