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

ambee/giterated

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

More restructuring

Amber - ⁨1⁩ year ago

parent: tbd commit: ⁨10b7b7c

Showing ⁨⁨124⁩ changed files⁩ with ⁨⁨4662⁩ insertions⁩ and ⁨⁨4609⁩ deletions⁩

Cargo.lock

View file
@@ -689,6 +689,7 @@ name = "giterated-abi"
689 689 version = "0.1.0"
690 690 dependencies = [
691 691 "anyhow",
692 "dlopen2",
692 693 "giterated-models",
693 694 ]
694 695
@@ -712,6 +713,13 @@ dependencies = [
712 713 [[package]]
713 714 name = "giterated-core"
714 715 version = "0.1.0"
716 dependencies = [
717 "anyhow",
718 "giterated-abi",
719 "giterated-models",
720 "giterated-static-runtime",
721 "tracing",
722 ]
715 723
716 724 [[package]]
717 725 name = "giterated-daemon"
@@ -843,6 +851,13 @@ dependencies = [
843 851 [[package]]
844 852 name = "giterated-runtime"
845 853 version = "0.1.0"
854 dependencies = [
855 "dlopen2",
856 "giterated-abi",
857 "giterated-core",
858 "giterated-models",
859 "tracing",
860 ]
846 861
847 862 [[package]]
848 863 name = "giterated-static-runtime"

Cargo.toml

View file
@@ -1,9 +1,9 @@
1 1 [workspace]
2 members = [ "giterated-abi", "giterated-core",
2 members = [ "giterated-runtime/giterated-abi", "giterated-core",
3 3 "giterated-daemon",
4 "giterated-models",
4 "giterated-core/giterated-models",
5 5 "giterated-plugin",
6 "giterated-macros",
6 "giterated-plugin/giterated-macros",
7 7 "giterated-runtime/giterated-static-runtime",
8 8 "giterated-runtime",
9 9 "plugins/example-plugin",

giterated-core/Cargo.toml

View file
@@ -6,3 +6,8 @@ edition = "2021"
6 6 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 7
8 8 [dependencies]
9 giterated-abi = { path = "../giterated-runtime/giterated-abi"}
10 giterated-static-runtime = { path = "../giterated-runtime/giterated-static-runtime"}
11 giterated-models = { path = "giterated-models" }
12 anyhow = "1"
13 tracing = "0.1"

giterated-core/giterated-models/Cargo.toml

View file
@@ -0,0 +1,41 @@
1 [package]
2 name = "giterated-models"
3 version = "0.1.0"
4 authors = ["Amber Kowalski"]
5 edition = "2021"
6 rust-version = "1.70.0"
7 description = "Giterated's Data Models"
8 homepage = "https://giterated.dev/ambee/giterated"
9 repository = "https://giterated.dev/ambee/giterated"
10 license = "MIT OR Apache-2.0"
11 keywords = ["giterated"]
12
13 # Leave until MVP
14 publish = false
15
16 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
17
18 [dependencies]
19 tracing = "0.1"
20 serde = { version = "1.0", features = [ "derive" ]}
21 serde_json = "1.0"
22 base64 = "0.21"
23 jsonwebtoken = { version = "9.1", features = ["use_pem"]}
24 rand = "0.8"
25 rsa = {version = "0.9", features = ["sha2"]}
26 semver = {version = "1.0", features = ["serde"]}
27 bincode = "1.3"
28 secrecy = { version = "0.8", features = ["serde"] }
29 thiserror = "1"
30 anyhow = "1"
31 toml = { version = "0.8" }
32 # Git backend
33 git2 = "0.18"
34 chrono = { version = "0.4", features = [ "serde" ] }
35 async-trait = "0.1"
36 url = {version = "2.4", features = ["serde"]}
37
38 # Git backend
39 sqlx = { version = "0.7", default-features = false, features = [ "macros", "chrono" ] }
40
41 #uuid = { version = "1.4", features = [ "v4", "serde" ] }

giterated-core/giterated-models/src/authenticated.rs

View file
@@ -0,0 +1,41 @@
1 use serde::{Deserialize, Serialize};
2
3 use crate::{instance::Instance, user::User};
4
5 #[repr(transparent)]
6 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
7 pub struct UserAuthenticationToken(String);
8
9 impl From<String> for UserAuthenticationToken {
10 fn from(value: String) -> Self {
11 Self(value)
12 }
13 }
14
15 impl ToString for UserAuthenticationToken {
16 fn to_string(&self) -> String {
17 self.0.clone()
18 }
19 }
20
21 impl AsRef<str> for UserAuthenticationToken {
22 fn as_ref(&self) -> &str {
23 &self.0
24 }
25 }
26
27 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
28 pub struct InstanceSignature(pub Vec<u8>);
29
30 impl AsRef<[u8]> for InstanceSignature {
31 fn as_ref(&self) -> &[u8] {
32 &self.0
33 }
34 }
35
36 #[derive(Debug, Serialize, Deserialize)]
37 pub struct UserTokenMetadata {
38 pub user: User,
39 pub generated_for: Instance,
40 pub exp: u64,
41 }

giterated-core/giterated-models/src/discovery.rs

View file
@@ -0,0 +1,15 @@
1 use serde::{Deserialize, Serialize};
2
3 use crate::{instance::Instance, repository::Repository};
4
5 #[derive(Clone, Hash, PartialEq, Eq, Debug, Serialize, Deserialize)]
6 pub enum DiscoveryItem {
7 Instance {
8 instance: Instance,
9 signature: Vec<u8>,
10 },
11 Repository {
12 repository: Repository,
13 signature: Vec<u8>,
14 },
15 }

giterated-core/giterated-models/src/error.rs

View file
@@ -0,0 +1,97 @@
1 use std::fmt::Display;
2
3 use serde::{Deserialize, Serialize};
4
5 #[derive(Debug, thiserror::Error, Deserialize, Serialize, Clone)]
6 pub enum InstanceError {
7 #[error("registration failed")]
8 RegistrationFailure,
9 #[error("authentication failed")]
10 AuthenticationFailed,
11 }
12
13 #[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
14 pub enum RepositoryError {}
15
16 #[derive(Debug, thiserror::Error, Deserialize, Serialize, Clone)]
17 pub enum UserError {}
18
19 #[derive(Debug, thiserror::Error, Serialize, Deserialize, Clone)]
20 pub enum GetValueError {
21 #[error("invalid object")]
22 InvalidObject,
23 }
24
25 #[derive(Debug, thiserror::Error, Clone)]
26 #[error("unauthorized")]
27 pub struct UnauthorizedError;
28
29 #[derive(Debug, thiserror::Error)]
30 pub enum OperationError<B> {
31 #[error("the operation was handled but an error occurred")]
32 Operation(#[from] B),
33 #[error("an internal error occurred: {0:?}")]
34 Internal(anyhow::Error),
35 #[error("the operation was unhandled or unrecognized")]
36 Unhandled,
37 }
38
39 pub trait IntoInternalError<T>: Sized {
40 fn as_internal_error<B>(self) -> Result<T, OperationError<B>>;
41
42 fn as_internal_error_with_context<B, C>(self, context: C) -> Result<T, OperationError<B>>
43 where
44 C: Display + Send + Sync + 'static,
45 {
46 let internal_error = self.as_internal_error::<B>();
47
48 match internal_error {
49 Ok(success) => Ok(success),
50 Err(OperationError::Internal(internal)) => {
51 Err(OperationError::Internal(internal.context(context)))
52 }
53 _ => unreachable!(),
54 }
55 }
56 }
57
58 impl<E: Into<anyhow::Error>, T> IntoInternalError<T> for Result<T, E> {
59 fn as_internal_error<B>(self) -> Result<T, OperationError<B>> {
60 match self {
61 Ok(success) => Ok(success),
62 Err(err) => Err(OperationError::Internal(err.into())),
63 }
64 }
65 }
66
67 impl<B> OperationError<B> {
68 pub fn into_network(self) -> NetworkOperationError<B> {
69 match self {
70 OperationError::Operation(operation_error) => {
71 NetworkOperationError::Operation(operation_error)
72 }
73 OperationError::Internal(_) => NetworkOperationError::Internal,
74 OperationError::Unhandled => NetworkOperationError::Unhandled,
75 }
76 }
77 }
78
79 #[derive(Debug, thiserror::Error)]
80 #[error("an extractor failed with an error {0}")]
81 pub struct ExtractorError<E: Into<anyhow::Error>>(#[from] pub E);
82
83 impl<T, E: Into<anyhow::Error>> IntoInternalError<T> for ExtractorError<E> {
84 fn as_internal_error<B>(self) -> Result<T, OperationError<B>> {
85 todo!()
86 }
87 }
88
89 #[derive(Serialize, Deserialize, Debug, thiserror::Error)]
90 pub enum NetworkOperationError<B> {
91 #[error("the operation was handled but an error occurred")]
92 Operation(#[from] B),
93 #[error("internal error")]
94 Internal,
95 #[error("the operation was unhandled or unrecognized")]
96 Unhandled,
97 }

giterated-core/giterated-models/src/ffi.rs

View file
@@ -0,0 +1,13 @@
1 pub trait ToFfi {
2 fn to_ffi_bytes(&self) -> Vec<u8>;
3 }
4
5 pub trait FromFfi: Sized {
6 fn from_ffi_bytes(bytes: &[u8]) -> Option<Self>;
7 }
8
9 pub trait FfiLabel {
10 fn prefix(&self) -> &'static str;
11
12 fn type_label(&self) -> &'static str;
13 }

giterated-core/giterated-models/src/handshake.rs

View file
@@ -0,0 +1,22 @@
1 use semver::Version;
2 use serde::{Deserialize, Serialize};
3
4 use crate::instance::Instance;
5
6 /// Sent by the initiator of a new inter-daemon connection.
7 #[derive(Clone, Debug, Serialize, Deserialize)]
8 pub struct InitiateHandshake {
9 pub version: Version,
10 }
11
12 /// Sent in response to [`InitiateHandshake`]
13 #[derive(Clone, Debug, Serialize, Deserialize)]
14 pub struct HandshakeResponse {
15 pub identity: Instance,
16 pub version: Version,
17 }
18
19 #[derive(Clone, Debug, Serialize, Deserialize)]
20 pub struct HandshakeFinalize {
21 pub success: bool,
22 }

giterated-core/giterated-models/src/instance/mod.rs

View file
@@ -0,0 +1,77 @@
1 use std::{fmt::Display, str::FromStr};
2
3 use serde::{Deserialize, Serialize};
4 use thiserror::Error;
5
6 mod operations;
7 mod values;
8
9 pub use operations::*;
10 use url::Url;
11
12 use crate::object::GiteratedObject;
13
14 pub struct InstanceMeta {
15 pub url: String,
16 pub public_key: String,
17 }
18
19 /// An instance, defined by the URL it can be reached at.
20 ///
21 /// # Textual Format
22 /// An instance's textual format is its URL.
23 ///
24 /// ## Examples
25 /// For the instance `giterated.dev`, the following [`Instance`] initialization
26 /// would be valid:
27 ///
28 /// ```
29 /// let instance = Instance {
30 /// url: String::from("giterated.dev")
31 /// };
32 ///
33 /// // This is correct
34 /// assert_eq!(Instance::from_str("giterated.dev").unwrap(), instance);
35 /// ```
36 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
37 pub struct Instance(pub String);
38
39 impl GiteratedObject for Instance {
40 fn object_name() -> &'static str {
41 "instance"
42 }
43
44 fn from_object_str(object_str: &str) -> Result<Self, anyhow::Error> {
45 Ok(Instance::from_str(object_str)?)
46 }
47
48 fn home_uri(&self) -> String {
49 self.0.clone()
50 }
51 }
52
53 impl Display for Instance {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.write_str(&self.0.to_string())
56 }
57 }
58
59 impl FromStr for Instance {
60 type Err = InstanceParseError;
61
62 fn from_str(s: &str) -> Result<Self, Self::Err> {
63 let with_protocol = format!("wss://{}", s);
64
65 if Url::parse(&with_protocol).is_ok() {
66 Ok(Self(s.to_string()))
67 } else {
68 Err(InstanceParseError::InvalidFormat)
69 }
70 }
71 }
72
73 #[derive(Debug, Error)]
74 pub enum InstanceParseError {
75 #[error("invalid format")]
76 InvalidFormat,
77 }

giterated-core/giterated-models/src/instance/operations.rs

View file
@@ -0,0 +1,197 @@
1 use secrecy::Secret;
2 use serde::{Deserialize, Serialize};
3
4 use crate::{
5 authenticated::UserAuthenticationToken,
6 error::{InstanceError, OperationError},
7 object::Object,
8 object_backend::ObjectBackend,
9 operation::{GiteratedOperation, OperationState},
10 repository::{Repository, RepositoryVisibility},
11 user::{Password, User},
12 };
13
14 use super::Instance;
15
16 /// An account registration request.
17 ///
18 /// # Authentication
19 /// - Instance Authentication
20 /// - **ONLY ACCEPTED WHEN SAME-INSTANCE**
21 #[derive(Clone, Debug, Serialize, Deserialize)]
22 pub struct RegisterAccountRequest {
23 pub username: String,
24 pub email: Option<String>,
25 pub password: Secret<Password>,
26 }
27
28 impl GiteratedOperation<Instance> for RegisterAccountRequest {
29 type Success = UserAuthenticationToken;
30 type Failure = InstanceError;
31 }
32
33 #[derive(Clone, Debug, Serialize, Deserialize)]
34 pub struct RegisterAccountResponse(pub UserAuthenticationToken);
35
36 /// An authentication token request.
37 ///
38 /// AKA Login Request
39 ///
40 /// # Authentication
41 /// - Instance Authentication
42 /// - Identifies the Instance to issue the token for
43 /// # Authorization
44 /// - Credentials ([`crate::backend::AuthBackend`]-based)
45 /// - Identifies the User account to issue a token for
46 /// - Decrypts user private key to issue to
47 #[derive(Clone, Debug, Serialize, Deserialize)]
48 pub struct AuthenticationTokenRequest {
49 pub instance: Instance,
50 pub username: String,
51 pub password: Secret<Password>,
52 }
53
54 impl GiteratedOperation<Instance> for AuthenticationTokenRequest {
55 type Success = UserAuthenticationToken;
56 type Failure = InstanceError;
57 }
58
59 /// An authentication token extension request.
60 ///
61 /// # Authentication
62 /// - Instance Authentication
63 /// - Identifies the Instance to issue the token for
64 /// - User Authentication
65 /// - Authenticates the validity of the token
66 /// # Authorization
67 /// - Token-based
68 /// - Validates authorization using token's authenticity
69 #[derive(Clone, Debug, Serialize, Deserialize)]
70 pub struct TokenExtensionRequest {
71 pub token: UserAuthenticationToken,
72 }
73
74 impl GiteratedOperation<Instance> for TokenExtensionRequest {
75 type Success = Option<UserAuthenticationToken>;
76 type Failure = InstanceError;
77 }
78
79 /// A request to create a repository.
80 ///
81 /// # Authentication
82 /// - Instance Authentication
83 /// - Used to validate User token `issued_for`
84 /// - User Authentication
85 /// - Used to source owning user
86 /// - Used to authorize user token against user's instance
87 /// # Authorization
88 /// - Instance Authorization
89 /// - Used to authorize action using User token requiring a correct `issued_for` and valid issuance from user's instance
90 /// - User Authorization
91 /// - Potential User permissions checks
92 #[derive(Clone, Debug, Serialize, Deserialize)]
93 pub struct RepositoryCreateRequest {
94 pub instance: Option<Instance>,
95 pub name: String,
96 pub description: Option<String>,
97 pub visibility: RepositoryVisibility,
98 pub default_branch: String,
99 pub owner: User,
100 }
101
102 impl GiteratedOperation<Instance> for RepositoryCreateRequest {
103 type Success = Repository;
104 type Failure = InstanceError;
105 }
106
107 impl<B: ObjectBackend + std::fmt::Debug> Object<Instance, B> {
108 pub async fn register_account(
109 &mut self,
110 email: Option<&str>,
111 username: &str,
112 password: &Secret<Password>,
113 operation_state: &OperationState,
114 ) -> Result<UserAuthenticationToken, OperationError<InstanceError>> {
115 self.request::<RegisterAccountRequest>(
116 RegisterAccountRequest {
117 username: username.to_string(),
118 email: email.map(|s| s.to_string()),
119 password: password.clone(),
120 },
121 operation_state,
122 )
123 .await
124 }
125
126 pub async fn authentication_token(
127 &mut self,
128 username: &str,
129 password: &Secret<Password>,
130 operation_state: &OperationState,
131 ) -> Result<UserAuthenticationToken, OperationError<InstanceError>> {
132 self.request::<AuthenticationTokenRequest>(
133 AuthenticationTokenRequest {
134 instance: self.inner.clone(),
135 username: username.to_string(),
136 password: password.clone(),
137 },
138 operation_state,
139 )
140 .await
141 }
142
143 pub async fn authentication_token_for(
144 &mut self,
145 instance: &Instance,
146 username: &str,
147 password: &Secret<Password>,
148 operation_state: &OperationState,
149 ) -> Result<UserAuthenticationToken, OperationError<InstanceError>> {
150 self.request::<AuthenticationTokenRequest>(
151 AuthenticationTokenRequest {
152 instance: instance.clone(),
153 username: username.to_string(),
154 password: password.clone(),
155 },
156 operation_state,
157 )
158 .await
159 }
160
161 pub async fn token_extension(
162 &mut self,
163 token: &UserAuthenticationToken,
164 operation_state: &OperationState,
165 ) -> Result<Option<UserAuthenticationToken>, OperationError<InstanceError>> {
166 self.request::<TokenExtensionRequest>(
167 TokenExtensionRequest {
168 token: token.clone(),
169 },
170 operation_state,
171 )
172 .await
173 }
174
175 pub async fn create_repository(
176 &mut self,
177 instance: &Instance,
178 name: &str,
179 visibility: &RepositoryVisibility,
180 default_branch: &str,
181 owner: &User,
182 operation_state: &OperationState,
183 ) -> Result<Repository, OperationError<InstanceError>> {
184 self.request::<RepositoryCreateRequest>(
185 RepositoryCreateRequest {
186 instance: Some(instance.clone()),
187 name: name.to_string(),
188 description: None,
189 visibility: visibility.clone(),
190 default_branch: default_branch.to_string(),
191 owner: owner.clone(),
192 },
193 operation_state,
194 )
195 .await
196 }
197 }

giterated-core/giterated-models/src/instance/values.rs

View file
@@ -0,0 +1 @@
1

giterated-core/giterated-models/src/lib.rs

View file
@@ -0,0 +1,15 @@
1 pub mod authenticated;
2 pub mod discovery;
3 pub mod error;
4 pub mod ffi;
5 pub mod handshake;
6 pub mod instance;
7 pub mod message;
8 pub mod object;
9 pub mod object_backend;
10 pub mod operation;
11 pub mod repository;
12 pub mod settings;
13 pub mod update;
14 pub mod user;
15 pub mod value;

giterated-core/giterated-models/src/message.rs

View file
@@ -0,0 +1,70 @@
1 use serde::Serialize;
2
3 use crate::{
4 object::{GiteratedObject, NetworkAnyObject},
5 operation::{GiteratedOperation, NetworkAnyOperation},
6 };
7 use std::fmt::Debug;
8
9 #[derive(Serialize)]
10 #[serde(bound(deserialize = "O: GiteratedObject, V: GiteratedOperation<O>"))]
11 pub struct GiteratedMessage<O: GiteratedObject, V: GiteratedOperation<O>> {
12 #[serde(with = "string")]
13 pub object: O,
14 pub operation: String,
15 pub payload: V,
16 }
17
18 #[allow(unused)]
19 mod string {
20 use std::fmt::Display;
21 use std::str::FromStr;
22
23 use serde::{de, Deserialize, Deserializer, Serializer};
24
25 pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 T: Display,
28 S: Serializer,
29 {
30 serializer.collect_str(value)
31 }
32
33 pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
34 where
35 T: FromStr,
36 T::Err: Display,
37 D: Deserializer<'de>,
38 {
39 String::deserialize(deserializer)?
40 .parse()
41 .map_err(de::Error::custom)
42 }
43 }
44
45 impl GiteratedMessage<NetworkAnyObject, NetworkAnyOperation> {
46 pub fn try_into<O: GiteratedObject, V: GiteratedOperation<O>>(
47 &self,
48 ) -> Result<GiteratedMessage<O, V>, ()> {
49 let object = O::from_object_str(&self.object.0).map_err(|_| ())?;
50 let payload = serde_json::from_slice::<V>(&self.payload.0).map_err(|_| ())?;
51
52 Ok(GiteratedMessage {
53 object,
54 operation: self.operation.clone(),
55 payload,
56 })
57 }
58 }
59
60 impl<V: GiteratedOperation<O> + Debug, O: GiteratedObject + Debug> Debug
61 for GiteratedMessage<O, V>
62 {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.debug_struct("GiteratedMessage")
65 .field("object", &self.object)
66 .field("operation", &self.operation)
67 .field("payload", &self.payload)
68 .finish()
69 }
70 }

giterated-core/giterated-models/src/object.rs

View file
@@ -0,0 +1,132 @@
1 use std::{
2 fmt::{Debug, Display},
3 str::FromStr,
4 };
5
6 use anyhow::Error;
7
8 use crate::{
9 error::{GetValueError, OperationError},
10 object_backend::ObjectBackend,
11 operation::{GiteratedOperation, OperationState},
12 settings::{GetSetting, GetSettingError, SetSetting, SetSettingError, Setting},
13 value::{GetValue, GiteratedObjectValue},
14 };
15
16 mod operations;
17 pub use operations::*;
18
19 #[derive(Debug, Clone)]
20 pub struct Object<O: GiteratedObject, B: ObjectBackend + Send + Clone> {
21 pub(crate) inner: O,
22 pub(crate) backend: B,
23 }
24
25 impl<B: ObjectBackend + Send + Sync + Clone, O: GiteratedObject> Object<O, B> {
26 pub fn object(&self) -> &O {
27 &self.inner
28 }
29
30 pub unsafe fn new_unchecked(object: O, backend: B) -> Object<O, B> {
31 Object {
32 inner: object,
33 backend,
34 }
35 }
36 }
37
38 impl<O: GiteratedObject + Display, B: ObjectBackend + Send + Sync + Clone> Display
39 for Object<O, B>
40 {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 self.inner.fmt(f)
43 }
44 }
45
46 pub trait GiteratedObject: Send + Display + FromStr + Sync + Clone {
47 fn object_name() -> &'static str;
48 fn home_uri(&self) -> String;
49
50 fn from_object_str(object_str: &str) -> Result<Self, Error>;
51 }
52
53 impl<O: GiteratedObject + Clone + Debug + 'static, B: ObjectBackend> Object<O, B> {
54 pub async fn get<V: GiteratedObjectValue<Object = O> + Send + Debug + 'static>(
55 &mut self,
56 operation_state: &OperationState,
57 ) -> Result<V, OperationError<GetValueError>> {
58 let result = self
59 .request(
60 GetValue {
61 value_name: V::value_name().to_string(),
62 },
63 operation_state,
64 )
65 .await?;
66
67 Ok(serde_json::from_slice(&result).unwrap())
68 }
69
70 pub async fn get_setting<S: Setting + Send + Clone + Debug>(
71 &mut self,
72 operation_state: &OperationState,
73 ) -> Result<S, OperationError<GetSettingError>> {
74 self.request(
75 GetSetting {
76 setting_name: S::name().to_string(),
77 },
78 operation_state,
79 )
80 .await
81 .map(|success| serde_json::from_value(success).unwrap())
82 }
83
84 pub async fn set_setting<S: Setting + Send + Clone + Debug>(
85 &mut self,
86 setting: S,
87 operation_state: &OperationState,
88 ) -> Result<(), OperationError<SetSettingError>> {
89 self.request(
90 SetSetting {
91 setting_name: S::name().to_string(),
92 value: serde_json::to_value(setting).unwrap(),
93 },
94 operation_state,
95 )
96 .await
97 }
98
99 pub async fn request<R: GiteratedOperation<O> + Debug + 'static>(
100 &mut self,
101 request: R,
102 operation_state: &OperationState,
103 ) -> Result<R::Success, OperationError<R::Failure>>
104 where
105 R::Success: Clone,
106 R::Failure: Clone,
107 {
108 self.backend
109 .object_operation(
110 self.inner.clone(),
111 R::operation_name(),
112 request,
113 operation_state,
114 )
115 .await
116 }
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-core/giterated-models/src/object/operations.rs

View file
@@ -0,0 +1,64 @@
1 use std::{convert::Infallible, fmt::Display, str::FromStr};
2
3 use serde::{Deserialize, Serialize};
4
5 use crate::{instance::Instance, operation::GiteratedOperation};
6
7 use super::GiteratedObject;
8
9 #[derive(Debug, Serialize, Deserialize, Clone)]
10 pub struct ObjectRequest(pub String);
11
12 #[derive(Serialize, Deserialize, Clone, Debug)]
13 pub struct ObjectResponse(pub String);
14
15 impl GiteratedOperation<Instance> for ObjectRequest {
16 type Success = ObjectResponse;
17
18 type Failure = ObjectRequestError;
19
20 fn operation_name() -> &'static str {
21 "object_request"
22 }
23 }
24
25 #[derive(Debug, Clone, thiserror::Error, Serialize, Deserialize)]
26 pub enum ObjectRequestError {
27 #[error("error decoding the object")]
28 Deserialization(String),
29 #[error("invalid object type")]
30 Invalid,
31 }
32
33 #[derive(Clone, Debug, Serialize, Deserialize)]
34 #[serde(transparent)]
35 #[repr(transparent)]
36 pub struct NetworkAnyObject(pub String);
37
38 impl GiteratedObject for NetworkAnyObject {
39 fn object_name() -> &'static str {
40 "any"
41 }
42
43 fn from_object_str(object_str: &str) -> Result<Self, anyhow::Error> {
44 Ok(Self(object_str.to_string()))
45 }
46
47 fn home_uri(&self) -> String {
48 todo!()
49 }
50 }
51
52 impl Display for NetworkAnyObject {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.write_str(&self.0)
55 }
56 }
57
58 impl FromStr for NetworkAnyObject {
59 type Err = Infallible;
60
61 fn from_str(s: &str) -> Result<Self, Self::Err> {
62 Ok(Self(s.to_owned()))
63 }
64 }

giterated-core/giterated-models/src/object_backend.rs

View file
@@ -0,0 +1,29 @@
1 use crate::{
2 error::OperationError,
3 object::{GiteratedObject, Object, ObjectRequestError},
4 operation::{GiteratedOperation, OperationState},
5 };
6
7 use std::fmt::Debug;
8
9 #[async_trait::async_trait(?Send)]
10 pub trait ObjectBackend: Sized + Clone + Send {
11 async fn object_operation<O, D>(
12 &self,
13 object: O,
14 operation: &str,
15 payload: D,
16 operation_state: &OperationState,
17 ) -> Result<D::Success, OperationError<D::Failure>>
18 where
19 O: GiteratedObject + Debug + 'static,
20 D: GiteratedOperation<O> + Debug + 'static,
21 D::Success: Clone,
22 D::Failure: Clone;
23
24 async fn get_object<O: GiteratedObject + Debug + 'static>(
25 &self,
26 object_str: &str,
27 operation_state: &OperationState,
28 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>>;
29 }

giterated-core/giterated-models/src/operation.rs

View file
@@ -0,0 +1,42 @@
1 use std::{any::type_name, collections::HashMap, fmt::Debug};
2
3 use serde::{de::DeserializeOwned, Deserialize, Serialize};
4
5 use crate::{ffi::FfiLabel, object::GiteratedObject};
6
7 pub trait GiteratedOperation<O: GiteratedObject>:
8 Send + Sync + Serialize + DeserializeOwned
9 {
10 type Success: Serialize + DeserializeOwned + Send;
11 type Failure: Serialize + DeserializeOwned + Send;
12
13 fn operation_name() -> &'static str {
14 type_name::<Self>()
15 }
16 }
17
18 #[derive(Clone, Debug, Serialize, Deserialize)]
19 #[serde(transparent)]
20 #[repr(transparent)]
21 pub struct NetworkAnyOperation(pub Vec<u8>);
22
23 impl<O: GiteratedObject> GiteratedOperation<O> for NetworkAnyOperation {
24 type Success = Vec<u8>;
25
26 type Failure = Vec<u8>;
27 }
28
29 #[derive(Clone, Debug, Default)]
30 pub struct OperationState {
31 states: HashMap<String, Vec<u8>>,
32 }
33
34 impl FfiLabel for OperationState {
35 fn prefix(&self) -> &'static str {
36 "dev.giterated"
37 }
38
39 fn type_label(&self) -> &'static str {
40 "operation_state"
41 }
42 }

giterated-core/giterated-models/src/repository/mod.rs

View file
@@ -0,0 +1,475 @@
1 use std::fmt::{Display, Formatter};
2 use std::str::FromStr;
3
4 use serde::{Deserialize, Serialize};
5
6 use crate::object::GiteratedObject;
7
8 use super::{instance::Instance, user::User};
9
10 mod operations;
11 mod settings;
12 mod values;
13
14 pub use operations::*;
15 pub use settings::*;
16 pub use values::*;
17
18 /// A repository, defined by the instance it exists on along with
19 /// its owner and name.
20 ///
21 /// # Textual Format
22 /// A repository's textual reference is defined as:
23 ///
24 /// `{owner: User}/{name: String}@{instance: Instance}`
25 ///
26 /// # Examples
27 /// For the repository named `foo` owned by `barson:giterated.dev` on the instance
28 /// `giterated.dev`, the following [`Repository`] initialization would
29 /// be valid:
30 ///
31 /// ```
32 //# use giterated_models::model::repository::Repository;
33 //# use giterated_models::model::instance::Instance;
34 //# use giterated_models::model::user::User;
35 /// let repository = Repository {
36 /// owner: User::from_str("barson:giterated.dev").unwrap(),
37 /// name: String::from("foo"),
38 /// instance: Instance::from_str("giterated.dev").unwrap()
39 /// };
40 ///
41 /// // This is correct
42 /// assert_eq!(Repository::from_str("barson:giterated.dev/[email protected]").unwrap(), repository);
43 /// ```
44 #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
45 pub struct Repository {
46 pub owner: User,
47 pub name: String,
48 /// Instance the repository is on
49 pub instance: Instance,
50 }
51
52 impl Repository {
53 pub fn new(instance: Instance, owner: User, name: String) -> Self {
54 Self {
55 owner,
56 name,
57 instance,
58 }
59 }
60 }
61
62 impl Display for Repository {
63 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
64 f.write_str(&format!("{}/{}@{}", self.owner, self.name, self.instance))
65 }
66 }
67
68 impl GiteratedObject for Repository {
69 fn object_name() -> &'static str {
70 "repository"
71 }
72
73 fn from_object_str(object_str: &str) -> Result<Self, anyhow::Error> {
74 Ok(Repository::from_str(object_str)?)
75 }
76
77 fn home_uri(&self) -> String {
78 self.instance.home_uri()
79 }
80 }
81
82 // impl TryFrom<String> for Repository {
83 // type Error = RepositoryParseError;
84
85 // fn try_from(value: String) -> Result<Self, Self::Error> {
86 // Self::from_str(&value)
87 // }
88 // }
89
90 impl From<String> for Repository {
91 fn from(value: String) -> Self {
92 Repository::from_str(&value).unwrap()
93 }
94 }
95
96 impl FromStr for Repository {
97 type Err = RepositoryParseError;
98
99 fn from_str(s: &str) -> Result<Self, Self::Err> {
100 let mut by_ampersand = s.split('@');
101 let mut path_split = by_ampersand.next().ok_or(RepositoryParseError)?.split('/');
102
103 let instance = Instance::from_str(by_ampersand.next().ok_or(RepositoryParseError)?)
104 .map_err(|_| RepositoryParseError)?;
105 let owner = User::from_str(path_split.next().ok_or(RepositoryParseError)?)
106 .map_err(|_| RepositoryParseError)?;
107 let name = path_split.next().ok_or(RepositoryParseError)?.to_string();
108
109 Ok(Self {
110 instance,
111 owner,
112 name,
113 })
114 }
115 }
116
117 #[derive(Debug, thiserror::Error)]
118 #[error("no parse!")]
119 pub struct RepositoryParseError;
120
121 /// Visibility of the repository to the general eye
122 #[derive(PartialEq, Eq, Debug, Hash, Serialize, Deserialize, Clone, sqlx::Type)]
123 #[sqlx(type_name = "visibility", rename_all = "lowercase")]
124 pub enum RepositoryVisibility {
125 Public,
126 Unlisted,
127 Private,
128 }
129
130 /// Implements [`Display`] for [`RepositoryVisiblity`] using [`Debug`]
131 impl Display for RepositoryVisibility {
132 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
133 write!(f, "{:?}", self)
134 }
135 }
136
137 #[derive(Clone, Debug, Serialize, Deserialize)]
138 pub struct RepositoryView {
139 /// Name of the repository
140 ///
141 /// This is different than the [`Repository`] name,
142 /// which may be a path.
143 pub name: String,
144 /// Owner of the Repository
145 pub owner: User,
146 /// Repository description
147 pub description: Option<Description>,
148 /// Repository visibility
149 pub visibility: Visibility,
150 /// Default branch of the repository
151 pub default_branch: DefaultBranch,
152 /// Last commit made to the repository
153 pub latest_commit: Option<LatestCommit>,
154 /// Repository statistics
155 pub stats: RepositoryStatistics,
156 /// Revision of the displayed tree
157 pub tree_rev: Option<String>,
158 /// Repository tree
159 pub tree: Vec<RepositoryTreeEntry>,
160 }
161
162 /// Generic repository statistics
163 #[derive(Clone, Debug, Serialize, Deserialize)]
164 pub struct RepositoryStatistics {
165 /// Amount of commits made to this branch in the repository
166 pub commits: usize,
167 /// Amount of branches the repository has
168 pub branches: usize,
169 /// Amount of tags the repository has
170 pub tags: usize,
171 }
172
173 /// Repository branch
174 #[derive(Clone, Debug, Serialize, Deserialize)]
175 pub struct RepositoryBranch {
176 /// Full reference name
177 pub name: String,
178 /// Whether the repository is stale or not
179 pub stale: bool,
180 /// The last commit made to the branch
181 pub last_commit: Option<Commit>,
182 }
183
184 #[derive(Clone, Debug, Serialize, Deserialize)]
185 pub struct RepositoryFile {
186 /// ID of the file
187 pub id: String,
188 /// Content of the file
189 pub content: Vec<u8>,
190 /// If the file is binary or not
191 pub binary: bool,
192 /// File size in bytes
193 pub size: usize,
194 }
195
196 #[derive(Clone, Debug, Serialize, Deserialize)]
197 pub struct RepositoryDiff {
198 /// "to" side of the diff commit
199 pub new_commit: Commit,
200 /// Total number of files changed
201 pub files_changed: usize,
202 /// Total number of insertions
203 pub insertions: usize,
204 /// Total number of deletions
205 pub deletions: usize,
206 /// List of changed files
207 pub files: Vec<RepositoryDiffFile>,
208 }
209
210 /// Represents the type of change made to a [`RepositoryDiffFile`]
211 #[derive(Clone, Debug, Serialize, Deserialize)]
212 pub enum RepositoryDiffFileStatus {
213 /// No changes
214 Unmodified,
215 Added,
216 Deleted,
217 /// Content changed between old and new
218 Modified,
219 /// Renamed between old and new
220 Renamed,
221 /// Copied from another old entry
222 Copied,
223 /// Ignored item in workdir
224 Ignored,
225 /// Untracked item in workdir
226 Untracked,
227 /// Type of file changed between old and new
228 Typechange,
229 /// File is unreadable
230 Unreadable,
231 /// File in the index is conflicted
232 Conflicted,
233 }
234
235 impl From<git2::Delta> for RepositoryDiffFileStatus {
236 fn from(status: git2::Delta) -> Self {
237 match status {
238 git2::Delta::Unmodified => Self::Unmodified,
239 git2::Delta::Added => Self::Added,
240 git2::Delta::Deleted => Self::Deleted,
241 git2::Delta::Modified => Self::Modified,
242 git2::Delta::Renamed => Self::Renamed,
243 git2::Delta::Copied => Self::Copied,
244 git2::Delta::Ignored => Self::Ignored,
245 git2::Delta::Untracked => Self::Untracked,
246 git2::Delta::Typechange => Self::Typechange,
247 git2::Delta::Unreadable => Self::Unreadable,
248 git2::Delta::Conflicted => Self::Conflicted,
249 }
250 }
251 }
252
253 /// Represents a single file of a diff
254 #[derive(Clone, Debug, Serialize, Deserialize)]
255 pub struct RepositoryDiffFile {
256 /// The type of change made to this file
257 pub status: RepositoryDiffFileStatus,
258 /// "From" side of the diff, can be nonexistent if file for example got added for the first time
259 pub old_file_info: Option<RepositoryDiffFileInfo>,
260 /// "To" side of the diff, can be nonexistent if file got removed
261 pub new_file_info: Option<RepositoryDiffFileInfo>,
262 /// Individual chunks of changes in this file
263 pub chunks: Vec<RepositoryDiffFileChunk>,
264 }
265
266 /// Represents one side of a file diff [`RepositoryDiffFile`]
267 #[derive(Clone, Debug, Serialize, Deserialize)]
268 pub struct RepositoryDiffFileInfo {
269 /// ID of the file
270 pub id: String,
271 /// Path of the entry relative to the working directory of the repository
272 pub path: String,
273 /// Size in bytes
274 pub size: u64,
275 /// If the file is binary or not
276 pub binary: bool,
277 }
278
279 /// Represents a single chunk of a file diff [`RepositoryDiffFile`]
280 #[derive(Clone, Debug, Serialize, Deserialize)]
281 pub struct RepositoryDiffFileChunk {
282 /// Header of the chunk
283 pub header: Option<String>,
284 /// Starting line number of the old file
285 pub old_start: u32,
286 /// Number of lines in "from" side of this chunk
287 pub old_lines: u32,
288 /// Starting line number of the new file
289 pub new_start: u32,
290 /// Number of lines in "to" side of this chunk
291 pub new_lines: u32,
292 /// Lines of the chunk
293 pub lines: Vec<RepositoryChunkLine>,
294 }
295
296 /// Represents the change type of the [`RepositoryChunkLine`], incomplete of what git actually provides.
297 #[derive(Clone, Debug, Serialize, Deserialize)]
298 pub enum RepositoryChunkLineType {
299 Context,
300 Addition,
301 Deletion,
302 }
303
304 impl From<git2::DiffLineType> for RepositoryChunkLineType {
305 fn from(line_type: git2::DiffLineType) -> Self {
306 match line_type {
307 git2::DiffLineType::Context => Self::Context,
308 git2::DiffLineType::Addition => Self::Addition,
309 git2::DiffLineType::Deletion => Self::Deletion,
310 _ => Self::Context,
311 }
312 }
313 }
314
315 /// Represents a single line of a [`RepositoryDiffFileChunk`]
316 #[derive(Clone, Debug, Serialize, Deserialize)]
317 pub struct RepositoryChunkLine {
318 /// Type of change the line is
319 pub change_type: RepositoryChunkLineType,
320 /// Content of the line
321 pub content: String,
322 /// Line number in old file
323 pub old_line_num: Option<u32>,
324 /// Line number in new file
325 pub new_line_num: Option<u32>,
326 }
327
328 #[derive(Debug, Clone, Serialize, Deserialize)]
329 pub enum RepositoryObjectType {
330 Tree,
331 Blob,
332 }
333
334 /// Stored info for our tree entries
335 #[derive(Debug, Clone, Serialize, Deserialize)]
336 pub struct RepositoryTreeEntry {
337 /// ID of the tree/blob
338 pub id: String,
339 /// Name of the tree/blob
340 pub name: String,
341 /// Type of the tree entry
342 pub object_type: RepositoryObjectType,
343 /// Git supplies us with the mode at all times, and people like it displayed.
344 pub mode: i32,
345 /// File size
346 pub size: Option<usize>,
347 /// Last commit made to the tree/blob
348 pub last_commit: Option<Commit>,
349 }
350
351 impl RepositoryTreeEntry {
352 // I love you Emilia <3
353 pub fn new(id: &str, name: &str, object_type: RepositoryObjectType, mode: i32) -> Self {
354 Self {
355 id: id.to_string(),
356 name: name.to_string(),
357 object_type,
358 mode,
359 size: None,
360 last_commit: None,
361 }
362 }
363 }
364
365 #[derive(Debug, Clone, Serialize, Deserialize)]
366 pub struct RepositoryTreeEntryWithCommit {
367 pub tree_entry: RepositoryTreeEntry,
368 pub commit: Commit,
369 }
370
371 /// Info about a git commit
372 #[derive(PartialEq, Hash, Eq, Debug, Clone, Serialize, Deserialize)]
373 pub struct Commit {
374 /// Unique commit ID
375 pub oid: String,
376 /// Shortened abbreviated OID
377 /// This starts at the git config's "core.abbrev" length (default 7 characters) and
378 /// iteratively extends to a longer string if that length is ambiguous. The
379 /// result will be unambiguous (at least until new objects are added to the repository).
380 pub short_oid: String,
381 /// First paragraph of the full message
382 pub summary: Option<String>,
383 /// Everything in the full message apart from the first paragraph
384 pub body: Option<String>,
385 /// All commit id's of the parents of this commit
386 pub parents: Vec<String>,
387 /// Who created the commit
388 pub author: CommitSignature,
389 /// Who committed the commit
390 pub committer: CommitSignature,
391 /// Time when the commit happened
392 pub time: chrono::NaiveDateTime,
393 }
394
395 /// Gets all info from [`git2::Commit`] for easy use
396 impl From<git2::Commit<'_>> for Commit {
397 fn from(commit: git2::Commit<'_>) -> Self {
398 Self {
399 oid: commit.id().to_string(),
400 // This shouldn't ever fail, as we already know the object has an oid.
401 short_oid: commit
402 .as_object()
403 .short_id()
404 .unwrap()
405 .as_str()
406 .unwrap()
407 .to_string(),
408 summary: commit.summary().map(|summary| summary.to_string()),
409 body: commit.body().map(|body| body.to_string()),
410 parents: commit
411 .parents()
412 .map(|parent| parent.id().to_string())
413 .collect::<Vec<String>>(),
414 author: commit.author().into(),
415 committer: commit.committer().into(),
416 time: chrono::NaiveDateTime::from_timestamp_opt(commit.time().seconds(), 0).unwrap(),
417 }
418 }
419 }
420
421 /// Git commit signature
422 #[derive(PartialEq, Hash, Eq, Debug, Clone, Serialize, Deserialize)]
423 pub struct CommitSignature {
424 pub name: Option<String>,
425 pub email: Option<String>,
426 pub time: chrono::NaiveDateTime,
427 }
428
429 /// Converts the signature from git2 into something usable without explicit lifetimes.
430 impl From<git2::Signature<'_>> for CommitSignature {
431 fn from(signature: git2::Signature<'_>) -> Self {
432 Self {
433 name: signature.name().map(|name| name.to_string()),
434 email: signature.email().map(|email| email.to_string()),
435 time: chrono::NaiveDateTime::from_timestamp_opt(signature.when().seconds(), 0).unwrap(),
436 }
437 }
438 }
439
440 /// The document type of a [`Commit`]'s body
441 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
442 pub enum CommitBodyType {
443 Plain,
444 Markdown,
445 }
446
447 impl Default for CommitBodyType {
448 fn default() -> Self {
449 Self::Plain
450 }
451 }
452
453 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
454 pub struct RepositorySummary {
455 pub repository: Repository,
456 pub owner: User,
457 pub visibility: RepositoryVisibility,
458 pub description: Option<String>,
459 pub last_commit: Option<Commit>,
460 }
461
462 #[derive(Clone, Debug, Serialize, Deserialize)]
463 pub struct IssueLabel {
464 pub name: String,
465 pub color: String,
466 }
467
468 #[derive(Clone, Debug, Serialize, Deserialize)]
469 pub struct RepositoryIssue {
470 pub author: User,
471 pub id: u64,
472 pub title: String,
473 pub contents: String,
474 pub labels: Vec<IssueLabel>,
475 }

giterated-core/giterated-models/src/repository/operations.rs

View file
@@ -0,0 +1,439 @@
1 use serde::{Deserialize, Serialize};
2
3 use crate::{
4 error::{OperationError, RepositoryError},
5 object::Object,
6 object_backend::ObjectBackend,
7 operation::{GiteratedOperation, OperationState},
8 };
9
10 use super::{
11 Commit, IssueLabel, Repository, RepositoryBranch, RepositoryDiff, RepositoryFile,
12 RepositoryIssue, RepositoryStatistics, RepositoryTreeEntry, RepositoryView,
13 };
14
15 /// A request to get a repository's information.
16 ///
17 /// # Authentication
18 /// - Instance Authentication
19 /// - Validate request against the `issued_for` public key
20 /// - Validate User token against the user's instance's public key
21 /// # Authorization
22 /// - User Authorization
23 /// - Potential User permissions checks
24 #[derive(Clone, Debug, Serialize, Deserialize)]
25 pub struct RepositoryInfoRequest {
26 pub extra_metadata: bool,
27 pub rev: Option<String>,
28 pub path: Option<String>,
29 }
30
31 impl GiteratedOperation<Repository> for RepositoryInfoRequest {
32 type Success = RepositoryView;
33 type Failure = RepositoryError;
34 }
35
36 /// A request to get a file from a repository using the given id.
37 ///
38 /// # Authentication
39 /// - Instance Authentication
40 /// - Validate request against the `issued_for` public key
41 /// - Validate User token against the user's instance's public key
42 /// # Authorization
43 /// - User Authorization
44 /// - Potential User permissions checks
45 #[derive(Clone, Debug, Serialize, Deserialize)]
46 pub struct RepositoryFileFromIdRequest(pub String);
47
48 impl GiteratedOperation<Repository> for RepositoryFileFromIdRequest {
49 type Success = RepositoryFile;
50 type Failure = RepositoryError;
51 }
52
53 /// A request to get a file from a repository using the given relative path.
54 /// Also returns the commit id of the rev.
55 ///
56 /// # Authentication
57 /// - Instance Authentication
58 /// - Validate request against the `issued_for` public key
59 /// - Validate User token against the user's instance's public key
60 /// # Authorization
61 /// - User Authorization
62 /// - Potential User permissions checks
63 #[derive(Clone, Debug, Serialize, Deserialize)]
64 pub struct RepositoryFileFromPathRequest {
65 pub rev: Option<String>,
66 pub path: String,
67 }
68
69 impl GiteratedOperation<Repository> for RepositoryFileFromPathRequest {
70 type Success = (RepositoryFile, String);
71 type Failure = RepositoryError;
72 }
73
74 /// A request to get the last commit made to a file, using a starting point and the path.
75 ///
76 /// # Authentication
77 /// - Instance Authentication
78 /// - Validate request against the `issued_for` public key
79 /// - Validate User token against the user's instance's public key
80 /// # Authorization
81 /// - User Authorization
82 /// - Potential User permissions checks
83 #[derive(Clone, Debug, Serialize, Deserialize)]
84 pub struct RepositoryLastCommitOfFileRequest {
85 /// ID of commit to start at
86 pub start_commit: String,
87 // Path of the file
88 pub path: String,
89 }
90
91 impl GiteratedOperation<Repository> for RepositoryLastCommitOfFileRequest {
92 type Success = Commit;
93 type Failure = RepositoryError;
94 }
95
96 /// A request to get the commit by the specified id.
97 ///
98 /// # Authentication
99 /// - Instance Authentication
100 /// - Validate request against the `issued_for` public key
101 /// - Validate User token against the user's instance's public key
102 /// # Authorization
103 /// - User Authorization
104 /// - Potential User permissions checks
105 #[derive(Clone, Debug, Serialize, Deserialize)]
106 pub struct RepositoryCommitFromIdRequest(pub String);
107
108 impl GiteratedOperation<Repository> for RepositoryCommitFromIdRequest {
109 type Success = Commit;
110 type Failure = RepositoryError;
111 }
112
113 /// A request to get the difference between two repository trees.
114 ///
115 /// # Authentication
116 /// - Instance Authentication
117 /// - Validate request against the `issued_for` public key
118 /// - Validate User token against the user's instance's public key
119 /// # Authorization
120 /// - User Authorization
121 /// - Potential User permissions checks
122 #[derive(Clone, Debug, Serialize, Deserialize)]
123 pub struct RepositoryDiffRequest {
124 pub old_id: String,
125 pub new_id: String,
126 }
127
128 impl GiteratedOperation<Repository> for RepositoryDiffRequest {
129 type Success = RepositoryDiff;
130 type Failure = RepositoryError;
131 }
132
133 /// A request to get the difference between two repository trees as a unified git patch.
134 ///
135 /// # Authentication
136 /// - Instance Authentication
137 /// - Validate request against the `issued_for` public key
138 /// - Validate User token against the user's instance's public key
139 /// # Authorization
140 /// - User Authorization
141 /// - Potential User permissions checks
142 #[derive(Clone, Debug, Serialize, Deserialize)]
143 pub struct RepositoryDiffPatchRequest {
144 pub old_id: String,
145 pub new_id: String,
146 }
147
148 impl GiteratedOperation<Repository> for RepositoryDiffPatchRequest {
149 type Success = String;
150 type Failure = RepositoryError;
151 }
152
153 /// A request to get the commit before the one with the passed id
154 ///
155 /// # Authentication
156 /// - Instance Authentication
157 /// - Validate request against the `issued_for` public key
158 /// - Validate User token against the user's instance's public key
159 /// # Authorization
160 /// - User Authorization
161 /// - Potential User permissions checks
162 #[derive(Clone, Debug, Serialize, Deserialize)]
163 pub struct RepositoryCommitBeforeRequest(pub String);
164
165 impl GiteratedOperation<Repository> for RepositoryCommitBeforeRequest {
166 type Success = Commit;
167 type Failure = RepositoryError;
168 }
169
170 #[derive(Clone, Debug, Serialize, Deserialize)]
171 pub struct RepositoryIssuesCountRequest;
172
173 impl GiteratedOperation<Repository> for RepositoryIssuesCountRequest {
174 type Success = u64;
175 type Failure = RepositoryError;
176 }
177
178 /// A request to get a repository's issues count.
179 ///
180 /// # Authentication
181 /// - Instance Authentication
182 /// - Validate request against the `issued_for` public key
183 /// - Validate User token against the user's instance's public key
184 /// # Authorization
185 /// - User Authorization
186 /// - Potential User permissions checks
187 #[derive(Clone, Debug, Serialize, Deserialize)]
188 pub struct RepositoryIssueLabelsRequest;
189
190 impl GiteratedOperation<Repository> for RepositoryIssueLabelsRequest {
191 type Success = Vec<IssueLabel>;
192 type Failure = RepositoryError;
193 }
194
195 /// A request to get a repository's issue labels.
196 ///
197 /// # Authentication
198 /// - Instance Authentication
199 /// - Validate request against the `issued_for` public key
200 /// - Validate User token against the user's instance's public key
201 /// # Authorization
202 /// - User Authorization
203 /// - Potential User permissions checks
204 #[derive(Clone, Debug, Serialize, Deserialize)]
205 pub struct RepositoryIssuesRequest;
206
207 impl GiteratedOperation<Repository> for RepositoryIssuesRequest {
208 type Success = Vec<RepositoryIssue>;
209 type Failure = RepositoryError;
210 }
211
212 /// A request to inspect the tree of a repository.
213 ///
214 /// # Authentication
215 /// - Instance Authentication
216 /// - Validate request against the `issued_for` public key
217 /// - Validate User token against the user's instance's public key
218 /// # Authorization
219 /// - User Authorization
220 /// - Potential User permissions checks
221 #[derive(Clone, Debug, Serialize, Deserialize)]
222 pub struct RepositoryFileInspectRequest {
223 /// Whether to get extra metadata for every entry (file mode, size and last commit made to it).
224 pub extra_metadata: bool,
225 /// Revision of the repository to get (branch, commit id).
226 pub rev: Option<String>,
227 /// If not given a path, it'll default to the base.
228 pub path: Option<String>,
229 }
230
231 impl GiteratedOperation<Repository> for RepositoryFileInspectRequest {
232 type Success = Vec<RepositoryTreeEntry>;
233 type Failure = RepositoryError;
234 }
235
236 /// A request to get the statistics of repository.
237 ///
238 /// # Authentication
239 /// - Instance Authentication
240 /// - Validate request against the `issued_for` public key
241 /// - Validate User token against the user's instance's public key
242 /// # Authorization
243 /// - User Authorization
244 /// - Potential User permissions checks
245 #[derive(Clone, Debug, Serialize, Deserialize)]
246 pub struct RepositoryStatisticsRequest {
247 /// Revision of the repository to get (branch, commit id).
248 pub rev: Option<String>,
249 }
250
251 impl GiteratedOperation<Repository> for RepositoryStatisticsRequest {
252 type Success = RepositoryStatistics;
253 type Failure = RepositoryError;
254 }
255
256 /// A request to get a list of branches in the repository.
257 /// Skips over references with invalid UTF-8 names.
258 ///
259 /// # Authentication
260 /// - Instance Authentication
261 /// - Validate request against the `issued_for` public key
262 /// - Validate User token against the user's instance's public key
263 /// # Authorization
264 /// - User Authorization
265 /// - Potential User permissions checks
266 #[derive(Clone, Debug, Serialize, Deserialize)]
267 pub struct RepositoryBranchesRequest;
268
269 impl GiteratedOperation<Repository> for RepositoryBranchesRequest {
270 type Success = Vec<RepositoryBranch>;
271 type Failure = RepositoryError;
272 }
273
274 impl<B: ObjectBackend + std::fmt::Debug> Object<Repository, B> {
275 pub async fn info(
276 &mut self,
277 extra_metadata: bool,
278 rev: Option<String>,
279 path: Option<String>,
280 operation_state: &OperationState,
281 ) -> Result<RepositoryView, OperationError<RepositoryError>> {
282 self.request::<RepositoryInfoRequest>(
283 RepositoryInfoRequest {
284 extra_metadata,
285 rev,
286 path,
287 },
288 operation_state,
289 )
290 .await
291 }
292
293 pub async fn file_from_id(
294 &mut self,
295 id: String,
296 operation_state: &OperationState,
297 ) -> Result<RepositoryFile, OperationError<RepositoryError>> {
298 self.request::<RepositoryFileFromIdRequest>(
299 RepositoryFileFromIdRequest(id),
300 operation_state,
301 )
302 .await
303 }
304
305 pub async fn file_from_path(
306 &mut self,
307 rev: Option<String>,
308 path: String,
309 operation_state: &OperationState,
310 ) -> Result<(RepositoryFile, String), OperationError<RepositoryError>> {
311 self.request::<RepositoryFileFromPathRequest>(
312 RepositoryFileFromPathRequest { rev, path },
313 operation_state,
314 )
315 .await
316 }
317
318 pub async fn last_commit_of_file(
319 &mut self,
320 start_commit: String,
321 path: String,
322 operation_state: &OperationState,
323 ) -> Result<Commit, OperationError<RepositoryError>> {
324 self.request::<RepositoryLastCommitOfFileRequest>(
325 RepositoryLastCommitOfFileRequest { start_commit, path },
326 operation_state,
327 )
328 .await
329 }
330
331 pub async fn commit_by_id(
332 &mut self,
333 id: String,
334 operation_state: &OperationState,
335 ) -> Result<Commit, OperationError<RepositoryError>> {
336 self.request::<RepositoryCommitFromIdRequest>(
337 RepositoryCommitFromIdRequest(id),
338 operation_state,
339 )
340 .await
341 }
342
343 pub async fn diff(
344 &mut self,
345 old_id: String,
346 new_id: String,
347 operation_state: &OperationState,
348 ) -> Result<RepositoryDiff, OperationError<RepositoryError>> {
349 self.request::<RepositoryDiffRequest>(
350 RepositoryDiffRequest { old_id, new_id },
351 operation_state,
352 )
353 .await
354 }
355
356 pub async fn diff_patch(
357 &mut self,
358 old_id: String,
359 new_id: String,
360 operation_state: &OperationState,
361 ) -> Result<String, OperationError<RepositoryError>> {
362 self.request::<RepositoryDiffPatchRequest>(
363 RepositoryDiffPatchRequest { old_id, new_id },
364 operation_state,
365 )
366 .await
367 }
368
369 pub async fn commit_before(
370 &mut self,
371 id: String,
372 operation_state: &OperationState,
373 ) -> Result<Commit, OperationError<RepositoryError>> {
374 self.request::<RepositoryCommitBeforeRequest>(
375 RepositoryCommitBeforeRequest(id),
376 operation_state,
377 )
378 .await
379 }
380
381 pub async fn statistics(
382 &mut self,
383 rev: Option<String>,
384 operation_state: &OperationState,
385 ) -> Result<RepositoryStatistics, OperationError<RepositoryError>> {
386 self.request::<RepositoryStatisticsRequest>(
387 RepositoryStatisticsRequest { rev },
388 operation_state,
389 )
390 .await
391 }
392
393 pub async fn branches(
394 &mut self,
395 operation_state: &OperationState,
396 ) -> Result<Vec<RepositoryBranch>, OperationError<RepositoryError>> {
397 self.request::<RepositoryBranchesRequest>(RepositoryBranchesRequest, operation_state)
398 .await
399 }
400
401 // pub async fn issues_count(&mut self) -> Result<u64, OperationError<RepositoryError>> {
402 // self.request::<RepositoryIssuesCountRequest>(RepositoryIssuesCountRequest)
403 // .await
404 // }
405
406 pub async fn issue_labels(
407 &mut self,
408 operation_state: &OperationState,
409 ) -> Result<Vec<IssueLabel>, OperationError<RepositoryError>> {
410 self.request::<RepositoryIssueLabelsRequest>(RepositoryIssueLabelsRequest, operation_state)
411 .await
412 }
413
414 pub async fn issues(
415 &mut self,
416 operation_state: &OperationState,
417 ) -> Result<Vec<RepositoryIssue>, OperationError<RepositoryError>> {
418 self.request::<RepositoryIssuesRequest>(RepositoryIssuesRequest, operation_state)
419 .await
420 }
421
422 pub async fn inspect_files(
423 &mut self,
424 extra_metadata: bool,
425 rev: Option<&str>,
426 path: Option<&str>,
427 operation_state: &OperationState,
428 ) -> Result<Vec<RepositoryTreeEntry>, OperationError<RepositoryError>> {
429 self.request::<RepositoryFileInspectRequest>(
430 RepositoryFileInspectRequest {
431 extra_metadata,
432 rev: rev.map(|r| r.to_string()),
433 path: path.map(|p| p.to_string()),
434 },
435 operation_state,
436 )
437 .await
438 }
439 }

giterated-core/giterated-models/src/repository/settings.rs

View file
@@ -0,0 +1,28 @@
1 use serde::{Deserialize, Serialize};
2
3 use crate::{settings::Setting, user::User};
4
5 use super::{CommitBodyType, DefaultBranch};
6
7 impl Setting for DefaultBranch {
8 fn name() -> &'static str {
9 "default_branch"
10 }
11 }
12
13 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
14 #[repr(transparent)]
15 #[serde(transparent)]
16 pub struct AccessList(pub Vec<User>);
17
18 impl Setting for AccessList {
19 fn name() -> &'static str {
20 "access_list"
21 }
22 }
23
24 impl Setting for CommitBodyType {
25 fn name() -> &'static str {
26 "commit_body_type"
27 }
28 }

giterated-core/giterated-models/src/repository/values.rs

View file
@@ -0,0 +1,99 @@
1 use std::fmt::Display;
2
3 use serde::{Deserialize, Serialize};
4
5 use crate::{settings::Setting, value::GiteratedObjectValue};
6
7 use super::{Commit, CommitBodyType, Repository, RepositoryVisibility};
8
9 // pub struct RepositorySetting<V: GiteratedObjectValue>(pub V);
10
11 // impl<O: GiteratedObject, V: GiteratedObjectValue<Object = O> + Send> GiteratedOperation<O>
12 // for RepositorySetting<V>
13 // {
14 // fn operation_name(&self) -> &'static str {
15 // "setting_get"
16 // }
17 // type Success = V;
18 // type Failure = GetValueError;
19 // }
20
21 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
22 pub struct Description(pub String);
23
24 impl Display for Description {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 f.write_str(&self.0)
27 }
28 }
29
30 impl GiteratedObjectValue for Description {
31 type Object = Repository;
32
33 fn value_name() -> &'static str {
34 "description"
35 }
36 }
37
38 impl Setting for Description {
39 fn name() -> &'static str {
40 "description"
41 }
42 }
43
44 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
45 #[repr(transparent)]
46 #[serde(transparent)]
47 pub struct Visibility(pub RepositoryVisibility);
48
49 impl GiteratedObjectValue for Visibility {
50 type Object = Repository;
51
52 fn value_name() -> &'static str {
53 "visibility"
54 }
55 }
56
57 impl Setting for Visibility {
58 fn name() -> &'static str {
59 "visibility"
60 }
61 }
62
63 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
64 #[serde(transparent)]
65 #[repr(transparent)]
66 pub struct DefaultBranch(pub String);
67
68 impl Display for DefaultBranch {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 f.write_str(&self.0)
71 }
72 }
73
74 impl GiteratedObjectValue for DefaultBranch {
75 type Object = Repository;
76
77 fn value_name() -> &'static str {
78 "default_branch"
79 }
80 }
81
82 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
83 pub struct LatestCommit(pub Option<Commit>);
84
85 impl GiteratedObjectValue for LatestCommit {
86 type Object = Repository;
87
88 fn value_name() -> &'static str {
89 "latest_commit"
90 }
91 }
92
93 impl GiteratedObjectValue for CommitBodyType {
94 type Object = Repository;
95
96 fn value_name() -> &'static str {
97 "commit_body_type"
98 }
99 }

giterated-core/giterated-models/src/settings/mod.rs

View file
@@ -0,0 +1,25 @@
1 mod operations;
2
3 use std::{any::Any, sync::Arc};
4
5 pub use operations::*;
6 use serde::{de::DeserializeOwned, Serialize};
7
8 pub trait Setting: Serialize + DeserializeOwned + Send + Sync {
9 fn name() -> &'static str;
10 }
11
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-core/giterated-models/src/settings/operations.rs

View file
@@ -0,0 +1,46 @@
1 use std::fmt::Debug;
2
3 use serde::{Deserialize, Serialize};
4 use serde_json::Value;
5 use thiserror::Error;
6
7 use crate::{object::GiteratedObject, operation::GiteratedOperation};
8
9 #[derive(Serialize, Deserialize, Debug, Clone)]
10 pub struct GetSetting {
11 pub setting_name: String,
12 }
13
14 impl<O: GiteratedObject> GiteratedOperation<O> for GetSetting {
15 fn operation_name() -> &'static str {
16 "get_setting"
17 }
18
19 type Success = Value;
20
21 type Failure = GetSettingError;
22 }
23
24 #[derive(Error, Debug, Serialize, Deserialize, Clone)]
25 pub enum GetSettingError {}
26 #[derive(Serialize, Deserialize, Debug, Clone)]
27 pub struct SetSetting {
28 pub setting_name: String,
29 pub value: Value,
30 }
31
32 impl<O: GiteratedObject> GiteratedOperation<O> for SetSetting {
33 fn operation_name() -> &'static str {
34 "set_setting"
35 }
36
37 type Success = ();
38
39 type Failure = SetSettingError;
40 }
41
42 #[derive(Error, Debug, Serialize, Deserialize, Clone)]
43 pub enum SetSettingError {
44 #[error("Invalid setting `{0}` on object `{0}`")]
45 InvalidSetting(String, String),
46 }

giterated-core/giterated-models/src/update/instance.rs

View file
@@ -0,0 +1 @@
1

giterated-core/giterated-models/src/update/mod.rs

View file
@@ -0,0 +1,9 @@
1 mod instance;
2 mod repository;
3 mod user;
4
5 pub enum GiteratedUpdateKind {
6 Instance,
7 Repository,
8 Value,
9 }

giterated-core/giterated-models/src/update/repository.rs

View file
@@ -0,0 +1 @@
1

giterated-core/giterated-models/src/update/user.rs

View file
@@ -0,0 +1 @@
1

giterated-core/giterated-models/src/user/mod.rs

View file
@@ -0,0 +1,102 @@
1 mod operations;
2 mod settings;
3 mod values;
4
5 use std::{
6 fmt::{Display, Formatter},
7 str::FromStr,
8 };
9
10 pub use operations::*;
11 use secrecy::{CloneableSecret, DebugSecret, SerializableSecret, Zeroize};
12 use serde::{Deserialize, Serialize};
13
14 pub use values::*;
15
16 use crate::{instance::Instance, object::GiteratedObject};
17
18 /// A user, defined by its username and instance.
19 ///
20 /// # Textual Format
21 /// A user's textual reference is defined as:
22 ///
23 /// `{username: String}:{instance: Instance}`
24 ///
25 /// # Examples
26 /// For the user with the username `barson` and the instance `giterated.dev`,
27 /// the following [`User`] initialization would be valid:
28 ///
29 /// ```
30 /// let user = User {
31 /// username: String::from("barson"),
32 /// instance: Instance::from_str("giterated.dev").unwrap()
33 /// };
34 ///
35 /// // This is correct
36 /// assert_eq!(User::from_str("barson:giterated.dev").unwrap(), user);
37 /// ```
38 #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
39 pub struct User {
40 pub username: String,
41 pub instance: Instance,
42 }
43
44 impl GiteratedObject for User {
45 fn object_name() -> &'static str {
46 "user"
47 }
48
49 fn from_object_str(object_str: &str) -> Result<Self, anyhow::Error> {
50 Ok(User::from_str(object_str)?)
51 }
52
53 fn home_uri(&self) -> String {
54 self.instance.home_uri()
55 }
56 }
57
58 impl Display for User {
59 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60 write!(f, "{}:{}", self.username, self.instance.0)
61 }
62 }
63
64 impl From<String> for User {
65 fn from(user_string: String) -> Self {
66 User::from_str(&user_string).unwrap()
67 }
68 }
69
70 impl FromStr for User {
71 type Err = UserParseError;
72
73 fn from_str(s: &str) -> Result<Self, Self::Err> {
74 if s.contains('/') {
75 return Err(UserParseError);
76 }
77
78 let mut colon_split = s.split(':');
79 let username = colon_split.next().ok_or(UserParseError)?.to_string();
80 let instance = Instance::from_str(colon_split.next().ok_or(UserParseError)?)
81 .map_err(|_| UserParseError)?;
82
83 Ok(Self { username, instance })
84 }
85 }
86
87 #[derive(thiserror::Error, Debug)]
88 #[error("failed to parse user")]
89 pub struct UserParseError;
90
91 #[derive(Clone, Debug, Serialize, Deserialize)]
92 pub struct Password(pub String);
93
94 impl Zeroize for Password {
95 fn zeroize(&mut self) {
96 self.0.zeroize()
97 }
98 }
99
100 impl SerializableSecret for Password {}
101 impl CloneableSecret for Password {}
102 impl DebugSecret for Password {}

giterated-core/giterated-models/src/user/operations.rs

View file
@@ -0,0 +1,40 @@
1 use serde::{Deserialize, Serialize};
2
3 use crate::{
4 error::{OperationError, UserError},
5 instance::Instance,
6 object::Object,
7 object_backend::ObjectBackend,
8 operation::{GiteratedOperation, OperationState},
9 repository::RepositorySummary,
10 };
11
12 use super::User;
13
14 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
15 pub struct UserRepositoriesRequest {
16 pub instance: Instance,
17 pub user: User,
18 }
19
20 impl GiteratedOperation<User> for UserRepositoriesRequest {
21 type Success = Vec<RepositorySummary>;
22 type Failure = UserError;
23 }
24
25 impl<B: ObjectBackend + std::fmt::Debug> Object<User, B> {
26 pub async fn repositories(
27 &mut self,
28 instance: &Instance,
29 operation_state: &OperationState,
30 ) -> Result<Vec<RepositorySummary>, OperationError<UserError>> {
31 self.request::<UserRepositoriesRequest>(
32 UserRepositoriesRequest {
33 instance: instance.clone(),
34 user: self.inner.clone(),
35 },
36 operation_state,
37 )
38 .await
39 }
40 }

giterated-core/giterated-models/src/user/settings.rs

View file
@@ -0,0 +1,15 @@
1 use crate::settings::Setting;
2
3 use super::{Bio, DisplayName};
4
5 impl Setting for Bio {
6 fn name() -> &'static str {
7 "bio"
8 }
9 }
10
11 impl Setting for DisplayName {
12 fn name() -> &'static str {
13 "display_name"
14 }
15 }

giterated-core/giterated-models/src/user/values.rs

View file
@@ -0,0 +1,41 @@
1 use std::fmt::Display;
2
3 use serde::{Deserialize, Serialize};
4
5 use crate::value::GiteratedObjectValue;
6
7 use super::User;
8
9 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
10 pub struct Bio(pub String);
11
12 impl GiteratedObjectValue for Bio {
13 type Object = User;
14
15 fn value_name() -> &'static str {
16 "bio"
17 }
18 }
19
20 impl Display for Bio {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.write_str(&self.0)
23 }
24 }
25
26 #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
27 pub struct DisplayName(pub String);
28
29 impl Display for DisplayName {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 f.write_str(&self.0)
32 }
33 }
34
35 impl GiteratedObjectValue for DisplayName {
36 type Object = User;
37
38 fn value_name() -> &'static str {
39 "display_name"
40 }
41 }

giterated-core/giterated-models/src/value.rs

View file
@@ -0,0 +1,55 @@
1 use std::{fmt::Debug, marker::PhantomData};
2
3 use serde::{de::DeserializeOwned, Deserialize, Serialize};
4 use serde_json::Value;
5
6 use crate::{error::GetValueError, object::GiteratedObject, operation::GiteratedOperation};
7
8 pub trait GiteratedObjectValue: Send + Sync + Serialize + DeserializeOwned {
9 type Object: GiteratedObject;
10
11 fn value_name() -> &'static str;
12 }
13
14 #[derive(Serialize, Deserialize, Debug, Clone)]
15 pub struct GetValue {
16 pub value_name: String,
17 }
18
19 impl<O: GiteratedObject + Send> GiteratedOperation<O> for GetValue {
20 fn operation_name() -> &'static str {
21 "get_value"
22 }
23 type Success = Vec<u8>;
24 type Failure = GetValueError;
25 }
26
27 #[derive(Serialize, Deserialize, Debug, Clone)]
28 pub struct GetValueTyped<V: GiteratedObjectValue> {
29 pub ty: PhantomData<V>,
30 }
31
32 impl<O: GiteratedObject + Send, V: GiteratedObjectValue<Object = O>> GiteratedOperation<O>
33 for GetValueTyped<V>
34 {
35 fn operation_name() -> &'static str {
36 "get_value"
37 }
38 type Success = V;
39 type Failure = GetValueError;
40 }
41
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,
46 }
47
48 impl<'s> ObjectValuePair<'s> {
49 pub fn new(object_kind: &'s str, value_name: &'s str) -> Self {
50 Self {
51 object_kind,
52 value_name,
53 }
54 }
55 }

giterated-core/src/lib.rs

View file
@@ -1,68 +1,70 @@
1 mod state;
2 mod types;
1 use giterated_abi::vtable::{runtime::RuntimeHandle, VTable};
2
3 pub mod state;
4 pub mod types;
3 5
4 6 #[derive(Clone)]
5 7 #[repr(C)]
6 8 pub struct RuntimeState {
7 pub vtable: VTable<RuntimeState>,
9 pub vtable: &'static VTable<RuntimeHandle>,
8 10 }
9 11
10 impl RuntimeState {
11 pub unsafe fn from_static() -> Self {
12 let runtime = giterated_static_runtime::get_runtime_reference();
12 // impl RuntimeState {
13 // pub unsafe fn from_static() -> Self {
14 // let runtime = giterated_static_runtime::get_runtime_reference();
13 15
14 let runtime = runtime.cast::<Box<Runtime>>().as_ref();
16 // let runtime = runtime.cast::<Box<Runtime>>().as_ref();
15 17
16 runtime.state()
17 }
18 // runtime.state()
19 // }
18 20
19 pub unsafe fn runtime_state() -> PluginState {
20 let runtime = giterated_static_runtime::get_runtime_reference();
21 // pub unsafe fn runtime_state() -> PluginState {
22 // let runtime = giterated_static_runtime::get_runtime_reference();
21 23
22 PluginState::from_raw_ptr(giterated_static_runtime::get_runtime_reference().as_ptr())
23 }
24 }
24 // PluginState::from_raw_ptr(giterated_static_runtime::get_runtime_reference().as_ptr())
25 // }
26 // }
25 27
26 #[async_trait::async_trait(?Send)]
27 impl ObjectBackend for RuntimeState {
28 async fn object_operation<O, D>(
29 &self,
30 object: O,
31 _operation: &str,
32 payload: D,
33 _operation_state: &OperationState,
34 ) -> Result<D::Success, OperationError<D::Failure>>
35 where
36 O: GiteratedObject + Debug + 'static,
37 D: GiteratedOperation<O> + Debug + 'static,
38 D::Success: Clone,
39 D::Failure: Clone,
40 {
41 // let _object = AnyObject::new(object);
42 // let _operation = AnyOperation::new(payload);
28 // #[async_trait::async_trait(?Send)]
29 // impl ObjectBackend for RuntimeState {
30 // async fn object_operation<O, D>(
31 // &self,
32 // object: O,
33 // _operation: &str,
34 // payload: D,
35 // _operation_state: &OperationState,
36 // ) -> Result<D::Success, OperationError<D::Failure>>
37 // where
38 // O: GiteratedObject + Debug + 'static,
39 // D: GiteratedOperation<O> + Debug + 'static,
40 // D::Success: Clone,
41 // D::Failure: Clone,
42 // {
43 // // let _object = AnyObject::new(object);
44 // // let _operation = AnyOperation::new(payload);
43 45
44 todo!()
45 }
46 // todo!()
47 // }
46 48
47 async fn get_object<O: GiteratedObject + Debug + 'static>(
48 &self,
49 object_str: &str,
50 operation_state: &OperationState,
51 ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
52 // let object = unsafe {
53 // (self.vtable.get_object)(
54 // Self::runtime_state(),
55 // object_str,
56 // &mut operation_state.clone(),
57 // )
58 // }?;
49 // async fn get_object<O: GiteratedObject + Debug + 'static>(
50 // &self,
51 // object_str: &str,
52 // operation_state: &OperationState,
53 // ) -> Result<Object<O, Self>, OperationError<ObjectRequestError>> {
54 // // let object = unsafe {
55 // // (self.vtable.get_object)(
56 // // Self::runtime_state(),
57 // // object_str,
58 // // &mut operation_state.clone(),
59 // // )
60 // // }?;
59 61
60 // let object = unsafe { object.cast::<O>() };
62 // // let object = unsafe { object.cast::<O>() };
61 63
62 panic!("object casted");
64 // panic!("object casted");
63 65
64 // Ok(unsafe { Object::new_unchecked(object, self.clone()) })
66 // // Ok(unsafe { Object::new_unchecked(object, self.clone()) })
65 67
66 todo!()
67 }
68 }
68 // todo!()
69 // }
70 // }

giterated-core/src/state.rs

View file
@@ -18,6 +18,7 @@ use giterated_abi::prelude::*;
18 18 use giterated_abi::value_ex::FfiValueUntyped;
19 19 use giterated_abi::vtable::ObjectABI;
20 20 use giterated_abi::vtable::VTable;
21 use giterated_models::error::OperationError;
21 22
22 23 #[repr(transparent)]
23 24 pub struct State {

giterated-core/src/types/mod.rs

View file
@@ -1,3 +1,11 @@
1 use std::collections::HashMap;
2
3 use giterated_abi::vtable::{operation::Operation, Object, Setting, VTable, Value};
4 use giterated_models::{
5 object::ObjectOperationPair, settings::ObjectSettingPair, value::ObjectValuePair,
6 };
7 use tracing::trace;
8
1 9 #[derive(Default, Clone)]
2 10 pub struct TypeMetadata {
3 11 pub objects: HashMap<&'static str, &'static VTable<Object>>,

giterated-daemon/Cargo.toml

View file
@@ -29,7 +29,7 @@ reqwest = "0.11"
29 29 argon2 = "0.5"
30 30 aes-gcm = "0.10"
31 31 semver = {version = "1.0", features = ["serde"]}
32 giterated-models = { path = "../giterated-models" }
32 giterated-models = { path = "../giterated-core/giterated-models" }
33 33 giterated-plugin = { path = "../giterated-plugin" }
34 34 giterated-protocol = { path = "../plugins/giterated-protocol" }
35 35 deadpool = "0.9"

giterated-plugin/Cargo.toml

View file
@@ -10,13 +10,13 @@ dlopen2 = "0.6"
10 10 anyhow = "1"
11 11 thiserror = "1"
12 12 tracing = "0.1"
13 giterated-models = { path = "../giterated-models" }
13 giterated-models = { path = "../giterated-core/giterated-models" }
14 14 giterated-static-runtime = { path = "../giterated-runtime/giterated-static-runtime" }
15 giterated-abi = { path = "../giterated-abi" }
15 giterated-abi = { path = "../giterated-runtime/giterated-abi" }
16 16 semver = "*"
17 17 serde_json = "1.0"
18 18 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/giterated-macros/Cargo.toml

View file
@@ -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-plugin/giterated-macros/src/lib.rs

View file
@@ -0,0 +1,44 @@
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 input = parse_macro_input!(item as ItemFn);
15
16 let func = input.sig.ident.clone();
17
18 quote! {
19 #[doc(hidden)]
20 #[no_mangle]
21 unsafe extern "C" fn __plugin_init() {
22 #func(&mut ::giterated_plugin::local::PluginStackBuilder::new()).unwrap()
23 }
24
25 #input
26 }
27 .into()
28 }
29
30 fn emit_plugin_api() -> impl Into<TokenStream> {
31 quote! {
32 #[doc(hidden)]
33 #[no_mangle]
34 unsafe extern "C" fn __load_runtime_vtable(vtable: &'static ::giterated_plugin::abi::vtable::VTable<::giterated_plugin::abi::vtable::runtime::RuntimeHandle>) {
35 todo!()
36 }
37
38 #[doc(hidden)]
39 #[no_mangle]
40 unsafe extern "C" fn __get_plugin_vtable() -> &'static ::giterated_plugin::abi::vtable::VTable<::giterated_plugin::abi::vtable::plugin::Plugin> {
41 todo!()
42 }
43 }
44 }

giterated-runtime/Cargo.toml

View file
@@ -6,3 +6,8 @@ edition = "2021"
6 6 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 7
8 8 [dependencies]
9 giterated-abi = { path = "giterated-abi" }
10 dlopen2 = "0.6"
11 giterated-models = { path = "../giterated-core/giterated-models" }
12 tracing = "0.1"
13 giterated-core = { path = "../giterated-core" }

giterated-runtime/giterated-abi/Cargo.toml

View file
@@ -0,0 +1,11 @@
1 [package]
2 name = "giterated-abi"
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]
9 giterated-models = { path = "../../giterated-core/giterated-models"}
10 anyhow = "1"
11 dlopen2 = "0.6"

giterated-runtime/giterated-abi/README.md

View file
@@ -0,0 +1,25 @@
1 # Versioning
2
3 This versioning documentation specifically refers to the version of the Giterated ABI. The Giterated ABI can, and should, update independently from the rest of the project, as needed.
4
5 ## Pre 1.0.0 (Now!)
6
7 You are able to consume `giterated-abi` in your `Cargo.toml` manifest as follows with the expectation nothing should break as `giterated-abi` updates:
8 ```
9 giterated-abi = "0.1"
10 ```
11
12 It is important to still receive patch updates automatically as we may provide shim functionality and better compatibility with future changes in these updates. There may also be security and performance fixes. Furthermore it allows for Cargo to be more precise when selecting the exact dependency version.
13
14 - Stability is **not** guaranteed.
15 - Breaking changes **can** be made between "minor" semver versions, they **should** be well documented and announced ahead of time.
16
17 ## Post 1.0.0 (Future)
18
19 You are able to consume `giterated-abi` in your `Cargo.toml` manifest as follows with the *guarantee* of compatibility.
20
21 ```
22 giterated-abi = "1"
23 ```
24
25 After 1.0.0 is released, minor updates **must not** contain changes that violate a reasonable understanding of semver. The ABI is intended to be stable and only changed in a backwards-compatible manner beyond 1.0.0.
25 \ No newline at end of file

giterated-runtime/giterated-abi/src/callback/mod.rs

View file
@@ -0,0 +1,27 @@
1 pub mod operation;
2 pub mod setting;
3 pub mod value;
4
5 use std::marker::PhantomData;
6
7 pub trait Callback {
8 type CallbackFunc;
9 }
10
11 #[derive(Copy, Clone)]
12 #[repr(C)]
13 pub struct CallbackPtr<T: Callback> {
14 callback_ptr: *const (),
15 func: T::CallbackFunc,
16 _marker: PhantomData<T>,
17 }
18
19 impl<T: Callback> CallbackPtr<T> {
20 pub unsafe fn from_raw(data: T, func: T::CallbackFunc) -> Self {
21 todo!()
22 }
23
24 pub fn func(&self) -> &T::CallbackFunc {
25 &self.func
26 }
27 }

giterated-runtime/giterated-abi/src/callback/operation.rs

View file
@@ -0,0 +1,140 @@
1 use std::future::Future;
2
3 use giterated_models::{
4 error::OperationError, object::GiteratedObject, operation::GiteratedOperation,
5 };
6
7 use crate::{
8 result::FfiResult,
9 state::State,
10 value_ex::FfiValueUntyped,
11 vtable::{operation::Operation, Object},
12 FfiFuture, FfiValueMut, FfiValueRef,
13 };
14
15 use super::{Callback, CallbackPtr};
16
17 use std::fmt::Debug;
18
19 pub struct OperationHandlerCallback(FfiValueUntyped);
20
21 impl Callback for OperationHandlerCallback {
22 type CallbackFunc = unsafe extern "C" fn(
23 CallbackPtr<OperationHandlerCallback>,
24 state: FfiValueMut<State>,
25 object: FfiValueRef<Object>,
26 operation: FfiValueRef<Operation>,
27 ) -> FfiFuture<
28 FfiResult<FfiValueUntyped, OperationError<FfiValueUntyped>>,
29 >;
30 }
31
32 pub trait IntoPluginOperationHandler<O: GiteratedObject, D: GiteratedOperation<O>, A> {
33 unsafe extern "C" fn handle(
34 callback_ptr: CallbackPtr<OperationHandlerCallback>,
35 state: FfiValueMut<State>,
36 object: FfiValueRef<Object>,
37 operation: FfiValueRef<Operation>,
38 ) -> FfiFuture<FfiResult<FfiValueUntyped, OperationError<FfiValueUntyped>>>;
39 fn callback_ptr(&self) -> CallbackPtr<OperationHandlerCallback>;
40 }
41
42 impl<F, O, D, Fut> IntoPluginOperationHandler<O, D, ()> for F
43 where
44 Fut: Future<Output = Result<D::Success, OperationError<D::Failure>>> + Send + Sync,
45 F: Fn(O, D) -> Fut + Send + Sync + 'static,
46 O: Debug + GiteratedObject + 'static,
47 D: Debug + GiteratedOperation<O> + 'static,
48 {
49 unsafe extern "C" fn handle(
50 callback: CallbackPtr<OperationHandlerCallback>,
51 state: FfiValueMut<State>,
52 object: FfiValueRef<Object>,
53 operation: FfiValueRef<Operation>,
54 ) -> FfiFuture<FfiResult<FfiValueUntyped, OperationError<FfiValueUntyped>>> {
55 todo!()
56 // let _guard = trace_span!(
57 // "operation handler",
58 // object = type_name::<O>(),
59 // operation = type_name::<D>()
60 // )
61 // .entered();
62 // let state = unsafe { state.transmute_ref::<S>() };
63
64 // // Since this is Rust code, we know that the AnyObject and AnyOperation are just boxes
65 // let object = unsafe { object.transmute_owned::<O>() };
66 // let operation = unsafe { operation.transmute_owned::<D>() };
67
68 // // Cast the callback ptr to ourselves
69 // let callback: *const F = std::mem::transmute(callback.0);
70 // let callback = callback.as_ref().unwrap();
71
72 // let state = state.clone();
73 // runtime_state.spawn_future(async move {
74 // let result = callback(state, *object, *operation).await;
75
76 // match result {
77 // Ok(success) => unsafe {
78 // todo!()
79 // // Ok(AnySuccess::from_raw(
80 // // FFIBox::from_box(Box::new(success)).untyped(),
81 // // OperationVTable::new::<O, D>(),
82 // // ))
83 // },
84 // Err(err) => match err {
85 // OperationError::Operation(_) => todo!(),
86 // OperationError::Internal(_) => todo!(),
87 // OperationError::Unhandled => todo!(),
88 // },
89 // }
90 // })
91 }
92
93 fn callback_ptr(&self) -> CallbackPtr<OperationHandlerCallback> {
94 // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) }
95
96 todo!()
97 }
98 }
99
100 impl<F, O, D, Fut, A1> IntoPluginOperationHandler<O, D, (A1,)> for F
101 where
102 Fut: Future<Output = Result<D::Success, OperationError<D::Failure>>>,
103 F: Fn(O, D, A1) -> Fut,
104 O: Debug + GiteratedObject,
105 D: Debug + GiteratedOperation<O>,
106 {
107 unsafe extern "C" fn handle(
108 _callback_ptr: CallbackPtr<OperationHandlerCallback>,
109 state: FfiValueMut<State>,
110 object: FfiValueRef<Object>,
111 operation: FfiValueRef<Operation>,
112 ) -> FfiFuture<FfiResult<FfiValueUntyped, OperationError<FfiValueUntyped>>> {
113 todo!()
114 }
115
116 fn callback_ptr(&self) -> CallbackPtr<OperationHandlerCallback> {
117 todo!()
118 }
119 }
120
121 impl<F, O, D, Fut, A1, A2> IntoPluginOperationHandler<O, D, (A1, A2)> for F
122 where
123 Fut: Future<Output = Result<D::Success, OperationError<D::Failure>>>,
124 F: Fn(O, D, A1, A2) -> Fut,
125 O: Debug + GiteratedObject,
126 D: Debug + GiteratedOperation<O>,
127 {
128 unsafe extern "C" fn handle(
129 _callback_ptr: CallbackPtr<OperationHandlerCallback>,
130 state: FfiValueMut<State>,
131 object: FfiValueRef<Object>,
132 operation: FfiValueRef<Operation>,
133 ) -> FfiFuture<FfiResult<FfiValueUntyped, OperationError<FfiValueUntyped>>> {
134 todo!()
135 }
136
137 fn callback_ptr(&self) -> CallbackPtr<OperationHandlerCallback> {
138 todo!()
139 }
140 }

giterated-runtime/giterated-abi/src/callback/setting.rs

View file
@@ -0,0 +1,161 @@
1 use std::future::Future;
2
3 use giterated_models::{error::OperationError, object::GiteratedObject};
4
5 use crate::{
6 state::State,
7 value_ex::FfiValueUntyped,
8 vtable::{Object, Setting},
9 FfiFuture, FfiValueMut, FfiValueRef,
10 };
11
12 use super::{Callback, CallbackPtr};
13
14 pub struct SettingGetterCallback(FfiValueUntyped);
15
16 impl Callback for SettingGetterCallback {
17 type CallbackFunc = unsafe extern "C" fn(
18 CallbackPtr<SettingGetterCallback>,
19 state: FfiValueMut<State>,
20 object: FfiValueRef<Object>,
21 ) -> FfiFuture<Result<Setting, ()>>;
22 }
23
24 pub trait IntoPluginSettingGetter<O, OS> {
25 unsafe extern "C" fn get_setting(
26 callback_ptr: CallbackPtr<SettingGetterCallback>,
27 state: FfiValueMut<State>,
28 object: FfiValueRef<Object>,
29 ) -> FfiFuture<Result<Setting, ()>>;
30
31 fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback> {
32 // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) }
33 todo!()
34 }
35 }
36
37 impl<F, O, OS, Fut> IntoPluginSettingGetter<O, OS> for F
38 where
39 Fut: Future<Output = Result<OS, OperationError<anyhow::Error>>> + Send + Sync + 'static,
40 O: GiteratedObject + Send + Sync + 'static,
41 OS: giterated_models::settings::Setting + Send + Sync + 'static,
42 F: Fn(O) -> Fut + Send + Sync + 'static,
43 {
44 unsafe extern "C" fn get_setting(
45 callback: CallbackPtr<SettingGetterCallback>,
46 state: FfiValueMut<State>,
47 mut object: FfiValueRef<Object>,
48 ) -> FfiFuture<Result<Setting, ()>> {
49 // let _guard = trace_span!(
50 // "get_setting handler",
51 // object = O::object_name(),
52 // setting = OS::name()
53 // )
54 // .entered();
55 // let state = unsafe { state.transmute_ref::<S>() };
56
57 // let object = unsafe { object.transmute_owned::<O>() };
58
59 // // Cast the callback ptr to ourselves
60 // let callback: *const F = std::mem::transmute(callback.0);
61 // let callback = callback.as_ref().unwrap();
62
63 // let state = state.clone();
64 // runtime_state.spawn_future(async move {
65 // let result = callback(state, *object).await;
66
67 // match result {
68 // Ok(success) => unsafe { Ok(NewAnySetting::new(success)) },
69 // Err(err) => match err {
70 // OperationError::Operation(_) => todo!(),
71 // OperationError::Internal(_) => todo!(),
72 // OperationError::Unhandled => todo!(),
73 // },
74 // }
75
76 todo!()
77 // })
78 }
79 }
80
81 pub trait IntoPluginSettingSetter<O, OS> {
82 unsafe extern "C" fn set_setting(
83 callback_ptr: CallbackPtr<SettingGetterCallback>,
84 state: FfiValueMut<State>,
85 object: FfiValueRef<Object>,
86 setting: Setting,
87 ) -> FfiFuture<Result<(), ()>>;
88
89 fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback> {
90 // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) }
91 todo!()
92 }
93 }
94
95 impl<F, O, OS, Fut> IntoPluginSettingSetter<O, OS> for F
96 where
97 Fut: Future<Output = Result<(), OperationError<anyhow::Error>>>,
98 O: GiteratedObject,
99 OS: giterated_models::settings::Setting,
100 F: Fn(O, OS) -> Fut,
101 {
102 unsafe extern "C" fn set_setting(
103 callback: CallbackPtr<SettingGetterCallback>,
104 state: FfiValueMut<State>,
105 mut object: FfiValueRef<Object>,
106 _setting: Setting,
107 ) -> FfiFuture<Result<(), ()>> {
108 // let _guard = trace_span!(
109 // "get_setting handler",
110 // object = O::object_name(),
111 // setting = OS::name()
112 // )
113 // .entered();
114 // let _state = unsafe { state.transmute_ref::<S>() };
115
116 // let _object = unsafe { object.transmute_owned::<O>() };
117
118 // // Cast the callback ptr to ourselves
119 // let callback: *const F = std::mem::transmute(callback.0);
120 // let _callback = callback.as_ref().unwrap();
121
122 // let result = callback(state.clone(), *object);
123
124 // match result {
125 // Ok(setting) => Ok(NewAnySetting::new(setting)),
126 // Err(_) => todo!(),
127 // }
128 todo!()
129 }
130 }
131
132 pub struct SettingChangeCallback(FfiValueUntyped);
133
134 impl Callback for SettingChangeCallback {
135 type CallbackFunc = unsafe extern "C" fn(
136 state: FfiValueMut<State>,
137 object: FfiValueRef<Object>,
138 setting_name: &str,
139 new_setting: Setting,
140 );
141 }
142
143 pub trait IntoSettingChangeCallback<S, O> {
144 unsafe extern "C" fn setting_changed(
145 state: FfiValueMut<State>,
146 object: FfiValueRef<Object>,
147 setting_name: &str,
148 new_setting: Setting,
149 );
150 }
151
152 impl<F, S, O> IntoSettingChangeCallback<S, O> for F {
153 unsafe extern "C" fn setting_changed(
154 state: FfiValueMut<State>,
155 _object: FfiValueRef<Object>,
156 _setting_name: &str,
157 _new_setting: Setting,
158 ) {
159 todo!()
160 }
161 }

giterated-runtime/giterated-abi/src/callback/value.rs

View file
@@ -0,0 +1,117 @@
1 use std::future::Future;
2
3 use giterated_models::{
4 error::OperationError, object::GiteratedObject, value::GiteratedObjectValue,
5 };
6
7 use crate::{
8 result::{FfiError, FfiResult},
9 state::State,
10 vtable::{Object, Value},
11 FfiFuture, FfiSliceRef, FfiValueMut, FfiValueRef,
12 };
13
14 use super::{setting::SettingGetterCallback, Callback, CallbackPtr};
15
16 #[derive(Copy, Clone)]
17 pub struct ValueGetterCallback(CallbackPtr<ValueGetterCallback>);
18
19 impl Callback for ValueGetterCallback {
20 type CallbackFunc = unsafe extern "C" fn(
21 CallbackPtr<ValueGetterCallback>,
22 state: FfiValueMut<State>,
23 object: FfiValueRef<Object>,
24 ) -> FfiFuture<FfiResult<Value, FfiError>>;
25 }
26
27 pub trait IntoPluginValueGetter<O, V> {
28 unsafe extern "C" fn get_value(
29 callback: CallbackPtr<SettingGetterCallback>,
30 state: FfiValueMut<State>,
31 object: FfiValueRef<Object>,
32 ) -> FfiFuture<FfiResult<Value, FfiError>>;
33
34 fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback>;
35 }
36
37 impl<F, O, V, Fut> IntoPluginValueGetter<O, V> for F
38 where
39 Fut: Future<Output = Result<V, OperationError<anyhow::Error>>> + Send + Sync,
40 O: GiteratedObject + 'static,
41 V: GiteratedObjectValue<Object = O> + Send + Sync + 'static,
42 F: Fn(O) -> Fut + Send + Sync + 'static,
43 {
44 unsafe extern "C" fn get_value(
45 callback: CallbackPtr<SettingGetterCallback>,
46 state: FfiValueMut<State>,
47 mut object: FfiValueRef<Object>,
48 ) -> FfiFuture<FfiResult<Value, FfiError>> {
49 // let _guard = trace_span!(
50 // "get_value handler",
51 // object = O::object_name(),
52 // value = V::value_name()
53 // )
54 // .entered();
55 // let state = unsafe { state.transmute_ref::<S>() };
56
57 // let object = unsafe { object.transmute_owned::<O>() };
58
59 // // Cast the callback ptr to ourselves
60 // let callback: *const F = std::mem::transmute(callback.0);
61 // let callback = callback.as_ref().unwrap();
62
63 // let state = state.clone();
64 // runtime_state.spawn_future(async move {
65 // let result = callback(state, *object).await;
66
67 // match result {
68 // Ok(success) => unsafe { Ok(NewAnyValue::new(success)) },
69 // Err(err) => match err {
70 // OperationError::Operation(_) => todo!(),
71 // OperationError::Internal(_) => todo!(),
72 // OperationError::Unhandled => todo!(),
73 // },
74 // }
75 // })
76
77 todo!()
78 }
79
80 fn callback_ptr(&self) -> CallbackPtr<SettingGetterCallback> {
81 todo!()
82 // unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) }
83 }
84 }
85
86 pub struct ValueChangeCallback(CallbackPtr<ValueChangeCallback>);
87
88 impl Callback for ValueChangeCallback {
89 type CallbackFunc = unsafe extern "C" fn(
90 state: FfiValueMut<State>,
91 object: FfiValueRef<Object>,
92 value_name: FfiSliceRef<str>,
93 new_value: Value,
94 ) -> FfiFuture<()>;
95 }
96
97 pub trait IntoValueChangeCallback<S, O> {
98 unsafe extern "C" fn value_changed(
99 callback: CallbackPtr<ValueChangeCallback>,
100 state: FfiValueMut<State>,
101 object: FfiValueRef<Object>,
102 value_name: FfiSliceRef<str>,
103 new_value: Value,
104 ) -> FfiFuture<()>;
105 }
106
107 impl<F, S, O> IntoValueChangeCallback<S, O> for F {
108 unsafe extern "C" fn value_changed(
109 callback: CallbackPtr<ValueChangeCallback>,
110 state: FfiValueMut<State>,
111 _object: FfiValueRef<Object>,
112 _value_name: FfiSliceRef<str>,
113 _new_value: Value,
114 ) -> FfiFuture<()> {
115 todo!()
116 }
117 }

giterated-runtime/giterated-abi/src/future.rs

View file
@@ -0,0 +1,56 @@
1 use std::marker::PhantomData;
2
3 use crate::{FfiValue, FfiValueMut};
4
5 #[repr(C)]
6 pub struct FfiFuture<Output> {
7 poll_fn: unsafe extern "C" fn(FfiValueMut<FfiFuture<()>>, FfiValueMut<()>) -> RuntimeFuturePoll,
8 wake_fn: unsafe extern "C" fn(FfiValueMut<FfiFuture<()>>, FfiValueMut<()>),
9
10 poll_state: FfiValue<()>,
11 pub waker_state: Option<FfiValue<()>>,
12
13 _output_marker: PhantomData<Output>,
14 }
15
16 unsafe impl<Output> Send for FfiFuture<Output> where Output: Send {}
17 unsafe impl<Output> Sync for FfiFuture<Output> where Output: Sync {}
18
19 impl<Output> FfiFuture<Output> {
20 /// Docs here!
21 /// # SAFETY
22 /// TODO :(
23 pub unsafe fn poll(&mut self) -> RuntimeFuturePoll {
24 todo!()
25 }
26
27 /// Docs here!
28 /// # SAFETY
29 /// TODO :(
30 pub unsafe fn from_raw<PS>(
31 _poll_fn: unsafe extern "C" fn(
32 FfiValueMut<FfiFuture<()>>,
33 FfiValueMut<()>,
34 ) -> RuntimeFuturePoll,
35 _poll_state: PS,
36 ) -> Self {
37 todo!()
38 }
39
40 /// Docs here!
41 /// # SAFETY
42 /// Very not in progress text :)
43 pub unsafe fn write_waker<WS>(
44 &mut self,
45 _wake_fn: unsafe extern "C" fn(FfiValueMut<FfiFuture<()>>),
46 _waker_state: WS,
47 ) {
48 todo!()
49 }
50 }
51
52 #[repr(C)]
53 pub enum RuntimeFuturePoll {
54 Ready(FfiValue<()>),
55 Pending,
56 }

giterated-runtime/giterated-abi/src/heap.rs

View file
@@ -0,0 +1,26 @@
1 use std::{mem::MaybeUninit, ptr::drop_in_place};
2
3 use crate::{abi_backing::HeapValueBacking, FfiValue};
4
5 pub trait HeapPlacable {
6 unsafe extern "C" fn free(value: FfiValue<Self>, taken: bool);
7 }
8
9 impl<T> HeapPlacable for T {
10 unsafe extern "C" fn free(value: FfiValue<Self>, taken: bool) {
11 if !taken {
12 drop(Box::from_raw(value.inner as *mut HeapValueBacking<T>))
13 } else {
14 let allocation = Box::from_raw(value.inner as *mut T);
15
16 // Since we "took" the value, kindly inform the compiler that it can't
17 // treat the value like it exists
18 let allocation_uninit: Box<HeapValueBacking<MaybeUninit<T>>> =
19 unsafe { core::mem::transmute(allocation) };
20
21 // Since the compiler has no idea whether the value exists or not, it won't try and
22 // drop it. Success!
23 drop(allocation_uninit);
24 }
25 }
26 }

giterated-runtime/giterated-abi/src/lib.rs

View file
@@ -0,0 +1,556 @@
1 //! Giterated ABI
2 //! # ABI
3 //!
4 //! ## Value ABI
5 //!
6 //! At its core, the Giterated Runtime uses the `extern "C"` ABI. What that means is likely platform specific, and doesn't matter.
7 //! You are intended to compile the Giterated Runtime and Plugins for your local machine, all with a similar idea of what
8 //! your "local machine" is.
9 //!
10 //! Values are passed using the `FFI` type. There are four categories of value that the `FFI` type enables you to pass:
11 //!
12 //! | `FFI` Type Category | Placed Backing? | Owned? |
13 //! |---------------------|-----------------|--------|
14 //! | Slice | Heap/Stack | No |
15 //! | Referenced Slice | Stack | No |
16 //! | Referenced Value | No | No |
17 //! | Owned Value | Heap | Yes |
18 //!
19 //! For an FFI type to have a "placed backing" is for it to have some data structure beyond the data it represents, placed
20 //! somewhere in memory. Some types only require stack placement while some offer both stack and heap placement.
21 //!
22 //! Stack-placed values can be shared by `PinnedRef` and `PinnedMut`, and thus can only be owned by the caller.
23 //!
24 //! Heap-placed values can be shared by `Owned`, `PinnedRef`, and `PinnedMut`. They can be owned by any one consumer,
25 //! When the handle with ownership is `Drop`'d by the sole consumer, it will free the object using the associated `Drop` callback.
26 //!
27 //! ### Safety Intents
28 //!
29 //! This API is designed to simplify interaction with FFI values, and provide a static ABI for those values to be passed. It
30 //! is key to enabling ownership across FFI while ensuring associated dropping and allocation freeing logic is ran.
31 //!
32 //! The contract the developer has to follow is made simpler by this system, and it allows for generic code to be written to
33 //! interact with FFI-given values and pass values using FFI.
34 //!
35 //! ### Stability Guarantees
36 //!
37 //! There are no plans to guarantee stability until 1.0.0. At that point you can expect the ABI to remain stable until the major version
38 //! is incremented again. There will be an appropriate deprecation process and changeover period.
39 //!
40 //! ### Memory Representation
41 //!
42 //! Please check out the source code, sorry if you needed that from the docs!
43 //!
44 //! ## Object, Operation, Setting, Value, Plugin, and Runtime ABIs
45 //!
46 //! The Giterated Runtime uses vtables to accomplish the goal of ensuring maximum compatibility. For every object that is shared
47 //! between plugins, a vtable is used to allow each plugin to provide their own code for interacting with the object.
48 //!
49 //! When objects switch "runtime domains" (e.g. host -> plugin, plugin -> plugin, plugin -> host), their vtable is swapped out
50 //! for the new runtime domain's own vtables.
51 //!
52 //! ### Untyped "Objects" (see above header for list)
53 //!
54 //! Untyped objects, in memory, are represented by a data pointer and a vtable pointer. Exactly like Rust traits. However, to
55 //! prevent small compilation differences and other random garbage from making the interface not perfectly compatible we use
56 //! the local plugin's idea of the vtable for the object at all times. An object that the plugin does not have a vtable for cannot
57 //! be relevant to the plugin.
58 //!
59 //! It is important that the object's base representation in memory remain unchanged between major versions, but the vtables that provide methods for
60 //! that object may be grown. The methods that operate on that object may be changed in an non-breaking fashion, and bugs can be
61 //! fixed.
62 //!
63 //! ## Futures ABI
64 //!
65 //! The Giterated Runtime has an async runtime that allows for futures to be shared and awaited across FFI boundaries while only
66 //! executing the future within the context of the Plugin who is running the underlying future.
67 //!
68 //! Futures are spawned onto the `RuntimeState` with the `RuntimeFuturesExt` trait. This takes a Rust future, boxes it, and
69 //! provides a `RuntimeFuture` handle that can be used to drive the underlying Rust future locally. The `RuntimeFuture` handle
70 //! is thread-safe and can be shared with the callee and `.await`'d directly like any other future.
71 //!
72 //! ### RuntimeFuture
73 //!
74 //! The `RuntimeFuture` mixes a vtable with data to allow for any caller to drive a spawned future. It contains:
75 //!
76 //! - A `poll_fn` which is used to poll the future for `Ready`-ness
77 //! - A `wake_fn` which is used to wake the callee to poll for (expected) `Ready`-ness, it is populated when the `RuntimeFuture` is `await`'d.
78 //!
79 //! When the `RuntimeFuture` is polled, it causes the inner future to also be polled. We provide the inner future with a waker
80 //! that triggers the `RuntimeFuture`'s waker so it is polled again. Breaking character to point out how freaking cool that is.
81 //!
82 //! `RuntimeFuture`s drop the associated inner future as they drop.
83
84 pub mod callback;
85 mod future;
86 pub mod heap;
87 pub mod model_impl;
88 pub mod plugin;
89 pub mod result;
90 pub mod state;
91 pub mod vtable;
92 use abi_backing::{HeapValueBacking, SliceBacking};
93 pub use future::{FfiFuture, RuntimeFuturePoll};
94 use heap::HeapPlacable;
95 use prelude::value_ex::FfiValueUntyped;
96
97 use std::{
98 marker::PhantomData,
99 mem::{transmute, MaybeUninit},
100 ops::{Deref, DerefMut},
101 };
102
103 use abi_types::{Slice, SliceMut, SliceRef, Value, ValueMut, ValueRef};
104 use guards::{HeapPinnedSlice, HeapPinnedValue, StackPinnedSlice, StackPinnedValue};
105
106 #[doc(hidden)]
107 pub mod prelude {
108 pub use crate::Ffi;
109 pub use crate::StackPinned;
110 pub use crate::*;
111 pub use crate::{FfiSlice, FfiSliceRef, FfiValue, FfiValueRef};
112 }
113
114 /// Slice Reference
115 /// Heap or Stack Placed
116 pub type FfiSliceRef<T> = Ffi<T, SliceRef>;
117
118 /// Mutable Slice Reference
119 /// Heap or Stack Placed
120 pub type FfiSliceMut<T> = Ffi<T, SliceMut>;
121
122 /// Value Reference
123 /// Heap or Stack Placed
124 pub type FfiValueRef<T> = Ffi<T, ValueRef>;
125
126 /// Mutable Value Reference
127 /// Heap or Stack Placed
128 pub type FfiValueMut<T> = Ffi<T, ValueMut>;
129
130 /// Owned Value
131 /// Heap Placed
132 pub type FfiValue<T> = Ffi<T, Value>;
133
134 /// Owned Slice
135 /// Heap Placed
136 pub type FfiSlice<T> = Ffi<T, Slice>;
137
138 pub mod value_ex {
139 use crate::{abi_types::Value, Ffi};
140
141 pub type FfiValueUntyped = Ffi<(), Value>;
142 pub type FfiValueRefUntyped = Ffi<(), Value>;
143 }
144
145 /// A value passed over FFI, following the Giterated ABI.
146 ///
147 /// The function of the [`Ffi`] type is to take an arbitrary pointer and send it over FFI.
148 /// Both the caller and callee **must** have the same understanding of what the pointer represents.
149 /// The [`Ffi`] type is also used to encode ownership information.
150 ///
151 /// # The Pointer
152 /// The pointer contained within the [`Ffi`] is transmuted based on the provided `ABI` on the
153 /// [`Ffi`] type signature.
154 #[repr(transparent)]
155 pub struct Ffi<T: ?Sized, ABI> {
156 inner: *const (),
157 _type_marker: PhantomData<T>,
158 _abi_marker: PhantomData<ABI>,
159 }
160
161 impl<T> FfiSlice<T> {
162 #[inline(always)]
163 pub fn pin(&self) -> HeapPinnedSlice<'_, T> {
164 unsafe { HeapPinnedSlice::from_raw(self) }
165 }
166 }
167
168 impl<T> Deref for FfiSlice<T> {
169 type Target = [T];
170
171 #[inline(always)]
172 fn deref(&self) -> &Self::Target {
173 let inner: *const SliceBacking<[T]> = unsafe { transmute(self.inner) };
174 let backing = unsafe { inner.as_ref().unwrap_unchecked() };
175
176 unsafe {
177 core::slice::from_raw_parts(
178 backing.slice as *mut T,
179 usize::try_from(backing.count).unwrap_unchecked(),
180 )
181 }
182 }
183 }
184 impl<T> DerefMut for FfiSlice<T> {
185 #[inline(always)]
186 fn deref_mut(&mut self) -> &mut Self::Target {
187 let inner: *mut SliceBacking<[T]> = unsafe { transmute(self.inner) };
188 let backing = unsafe { inner.as_mut().unwrap_unchecked() };
189
190 unsafe {
191 core::slice::from_raw_parts_mut(
192 backing.slice as *mut T,
193 usize::try_from(backing.count).unwrap_unchecked(),
194 )
195 }
196 }
197 }
198
199 impl<T> FfiSliceRef<T> {}
200
201 impl<T> Deref for FfiSliceRef<[T]> {
202 type Target = [T];
203
204 #[inline(always)]
205 fn deref(&self) -> &Self::Target {
206 let inner: *const SliceBacking<[T]> = unsafe { transmute(self.inner) };
207
208 let backing = unsafe { inner.as_ref().unwrap_unchecked() };
209
210 unsafe {
211 core::slice::from_raw_parts(
212 backing.slice as *const T,
213 usize::try_from(backing.count).unwrap_unchecked(),
214 )
215 }
216 }
217 }
218
219 impl<T> FfiValueRef<T> {}
220
221 impl<T> Deref for FfiValueRef<T> {
222 type Target = T;
223
224 #[inline(always)]
225 fn deref(&self) -> &Self::Target {
226 let inner: *const T = unsafe { transmute(self.inner) };
227
228 match unsafe { inner.as_ref() } {
229 Some(val) => val,
230 _ => unreachable!(),
231 }
232 }
233 }
234
235 impl<T> Deref for FfiValueMut<T> {
236 type Target = T;
237
238 fn deref(&self) -> &Self::Target {
239 let inner: *mut T = unsafe { transmute(self.inner) };
240
241 unsafe { inner.as_ref().unwrap_unchecked() }
242 }
243 }
244 impl<T> DerefMut for FfiValueMut<T> {
245 fn deref_mut(&mut self) -> &mut Self::Target {
246 let inner: *mut T = unsafe { transmute(self.inner) };
247
248 unsafe { inner.as_mut().unwrap_unchecked() }
249 }
250 }
251
252 impl<T> std::fmt::Display for FfiValueRef<T>
253 where
254 T: std::fmt::Display,
255 {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 unsafe { (self.inner as *const T).as_ref().unwrap() }.fmt(f)
258 }
259 }
260
261 impl<T> FfiValue<T> {
262 pub fn new(value: T) -> Self {
263 let value = Box::new(HeapValueBacking {
264 value,
265 drop_fn: <T as HeapPlacable>::free,
266 });
267
268 FfiValue {
269 inner: Box::into_raw(value) as _,
270 _type_marker: PhantomData,
271 _abi_marker: PhantomData,
272 }
273 }
274
275 pub fn erase_type(self) -> FfiValueUntyped {
276 unsafe { transmute(self) }
277 }
278
279 pub fn pin(&self) -> HeapPinnedValue<'_, T> {
280 unsafe { HeapPinnedValue::from_raw(self) }
281 }
282
283 pub fn take(self) -> T {
284 // This all boils down to moving `T` out of the `FfiValue` and dropping the backing
285 // storage for said `FfiValue`. Despite the use of unsafe this is exactly how moving
286 // a value onto the stack works.
287
288 let inner = self.inner as *mut T;
289 let mut move_target: MaybeUninit<T> = MaybeUninit::zeroed();
290
291 unsafe { move_target.as_mut_ptr().copy_from(inner, 1) }
292
293 let inner_descriptor: *mut HeapValueBacking<T> = unsafe { transmute(self.inner) };
294
295 unsafe { (inner_descriptor.as_mut().unwrap_unchecked().drop_fn)(self, true) };
296
297 unsafe { move_target.assume_init() }
298 }
299 }
300
301 impl<T> Deref for FfiValue<T> {
302 type Target = T;
303
304 #[inline(always)]
305 fn deref(&self) -> &Self::Target {
306 let inner: *const T = unsafe { transmute(self.inner) };
307
308 unsafe { inner.as_ref().unwrap_unchecked() }
309 }
310 }
311 impl<T> DerefMut for FfiValue<T> {
312 #[inline(always)]
313 fn deref_mut(&mut self) -> &mut Self::Target {
314 let inner: *mut T = unsafe { transmute(self.inner) };
315
316 unsafe { inner.as_mut().unwrap_unchecked() }
317 }
318 }
319
320 mod abi_backing {
321 use std::{marker::PhantomData, mem::transmute};
322
323 use crate::{FfiSlice, FfiValue};
324
325 #[repr(C)]
326 pub struct HeapValueBacking<T: Sized> {
327 pub(super) value: T,
328 pub(super) drop_fn: unsafe extern "C" fn(value: FfiValue<T>, taken: bool),
329 }
330
331 pub struct SliceBacking<T: ?Sized> {
332 pub(crate) count: u64,
333 pub(crate) slice: *const (),
334 _marker: PhantomData<T>,
335 }
336
337 impl<T: ?Sized> SliceBacking<T> {
338 /// Creates a new slice backing from a raw slice pointer and a count.
339 ///
340 /// # SAFETY
341 ///
342 /// `slice` **must** refer to a valid slice, with a length greater than or equal to the
343 /// value provided as `count`.
344 #[inline(always)]
345 pub(crate) unsafe fn from_raw(count: u64, slice: *const ()) -> Self {
346 Self {
347 count,
348 slice,
349 _marker: PhantomData,
350 }
351 }
352
353 /// Creates a new slice backing from an [`FfiSlice`].
354 ///
355 /// # SAFETY
356 ///
357 /// The resultant [`SliceBacking`] **must not** outlive the backing [`FfiSlice`].
358 #[inline(always)]
359 pub(crate) unsafe fn from_heap(slice: &FfiSlice<T>) -> Self {
360 let heap_backing: *const SliceBacking<T> = unsafe { transmute(slice.inner) };
361
362 let heap_backing = unsafe { heap_backing.as_ref().unwrap_unchecked() };
363
364 Self {
365 count: heap_backing.count,
366 slice: heap_backing.slice,
367 _marker: PhantomData,
368 }
369 }
370 }
371 }
372
373 mod guards {
374 use std::marker::PhantomData;
375
376 use crate::{
377 abi_backing::SliceBacking, Ffi, FfiSlice, FfiSliceMut, FfiSliceRef, FfiValue, FfiValueMut,
378 FfiValueRef,
379 };
380
381 #[repr(transparent)]
382 pub struct StackPinnedSlice<'v, T: ?Sized> {
383 _lifetime: PhantomData<&'v T>,
384 slice: SliceBacking<T>,
385 }
386
387 impl<'v, T> StackPinnedSlice<'v, T> {
388 #[inline(always)]
389 pub fn as_ref(&self) -> FfiSliceRef<T> {
390 FfiSliceRef {
391 inner: &self.slice as *const _ as *const (),
392 _type_marker: PhantomData,
393 _abi_marker: PhantomData,
394 }
395 }
396
397 #[inline(always)]
398 pub fn as_mut(&mut self) -> FfiSliceMut<T> {
399 FfiSliceMut {
400 inner: &mut self.slice as *mut _ as *mut (),
401 _type_marker: PhantomData,
402 _abi_marker: PhantomData,
403 }
404 }
405 }
406
407 impl<'v, T> StackPinnedSlice<'v, T> {
408 /// Creates a stack pinned slice guard from a borrowed slice.
409 ///
410 /// # SAFETY
411 /// This function itself isn't "unsafe" but other code will become unsafe if the `slice`
412 /// becomes invalid or moves. You'd have to violate safety rules somewhere else to do that,
413 /// though.
414 #[inline(always)]
415 pub(crate) unsafe fn from_raw(slice: &'v [T]) -> StackPinnedSlice<'v, T> {
416 Self {
417 _lifetime: PhantomData,
418 slice: SliceBacking::from_raw(
419 u64::try_from(slice.len()).unwrap(),
420 slice.as_ptr() as *const (),
421 ),
422 }
423 }
424 }
425
426 pub struct StackPinnedValue<'v, T> {
427 value_ref: &'v T,
428 }
429
430 impl<'v, T> StackPinnedValue<'v, T> {
431 /// Grants a reference to the pinned value.
432 ///
433 /// # SAFETY
434 /// - The granted reference **must not** outlive the lifetime of `&self`.
435 /// - There **must not** be a mutable reference created or mutable dereference performed during the lifetime of the [`FfiValueRef`].
436 #[inline(always)]
437 pub unsafe fn grant_ref(&self) -> FfiValueRef<T> {
438 Ffi {
439 inner: self.value_ref as *const _ as *const (),
440 _type_marker: PhantomData,
441 _abi_marker: PhantomData,
442 }
443 }
444 }
445
446 impl<'v, T> StackPinnedValue<'v, T> {
447 #[inline(always)]
448 pub(crate) fn from_raw(value: &'v T) -> Self {
449 Self { value_ref: value }
450 }
451 }
452
453 pub struct HeapPinnedSlice<'v, T> {
454 _lifetime: PhantomData<&'v T>,
455 slice: SliceBacking<T>,
456 }
457
458 impl<'v, T> HeapPinnedSlice<'v, T> {
459 /// Creates a pin guard from a heap placed slice.
460 ///
461 /// # SAFETY
462 /// The `slice` **must not** be moved and **must not** have a mutable reference given during the lifetime
463 /// of the returned [`HeapPinnedSlice`] guard.
464 #[inline(always)]
465 pub(crate) unsafe fn from_raw(slice: &'v FfiSlice<T>) -> HeapPinnedSlice<'v, T> {
466 Self {
467 _lifetime: PhantomData,
468 slice: SliceBacking::from_heap(slice),
469 }
470 }
471
472 pub unsafe fn grant_ref(&self) -> FfiSliceRef<T> {
473 FfiSliceRef {
474 inner: &self.slice as *const _ as *const (),
475 _type_marker: PhantomData,
476 _abi_marker: PhantomData,
477 }
478 }
479
480 pub unsafe fn grant_mut(&mut self) -> FfiSliceMut<T> {
481 FfiSliceMut {
482 inner: &mut self.slice as *mut _ as *mut (),
483 _type_marker: PhantomData,
484 _abi_marker: PhantomData,
485 }
486 }
487 }
488
489 #[repr(transparent)]
490 pub struct HeapPinnedValue<'v, T> {
491 value: &'v FfiValue<T>,
492 }
493
494 impl<'v, T> HeapPinnedValue<'v, T> {
495 #[inline(always)]
496 pub(crate) unsafe fn from_raw(value: &'v FfiValue<T>) -> HeapPinnedValue<'v, T> {
497 Self { value }
498 }
499
500 #[inline(always)]
501 pub unsafe fn grant_ref(&self) -> FfiValueRef<T> {
502 FfiValueRef {
503 inner: self.value.inner,
504 _type_marker: PhantomData,
505 _abi_marker: PhantomData,
506 }
507 }
508
509 #[inline(always)]
510 pub unsafe fn grant_mut(&mut self) -> FfiValueMut<T> {
511 FfiValueMut {
512 inner: self.value.inner,
513 _type_marker: PhantomData,
514 _abi_marker: PhantomData,
515 }
516 }
517 }
518 }
519
520 mod abi_types {
521 pub struct Slice;
522
523 pub struct SliceRef;
524
525 pub struct SliceMut;
526
527 pub struct ValueRef;
528
529 pub struct ValueMut;
530
531 pub struct Value;
532 }
533
534 pub trait StackPinned<'p> {
535 type Pinned: ?Sized + 'p;
536
537 fn pin(&'p self) -> Self::Pinned;
538 }
539
540 impl<'p, T: 'p> StackPinned<'p> for [T] {
541 type Pinned = StackPinnedSlice<'p, T>;
542
543 #[inline(always)]
544 fn pin(&'p self) -> StackPinnedSlice<'p, T> {
545 unsafe { StackPinnedSlice::from_raw(self) }
546 }
547 }
548
549 impl<'p, T: 'p> StackPinned<'p> for T {
550 type Pinned = StackPinnedValue<'p, T>;
551
552 #[inline(always)]
553 fn pin(&'p self) -> Self::Pinned {
554 StackPinnedValue::from_raw(self)
555 }
556 }

giterated-runtime/giterated-abi/src/model_impl/mod.rs

View file
@@ -0,0 +1,104 @@
1 use std::ffi::CStr;
2
3 use giterated_models::{object::GiteratedObject, operation::GiteratedOperation};
4
5 use crate::{
6 result::{FfiError, FfiResult},
7 value_ex::{FfiValueRefUntyped, FfiValueUntyped},
8 vtable::{
9 operation::{IntoOperationVTable, Operation},
10 IntoObjectVTable, IntoSettingVTable, IntoValueVTable, Object, Setting,
11 },
12 FfiSlice, FfiSliceRef, FfiValueRef,
13 };
14
15 impl<T> IntoObjectVTable for T
16 where
17 T: GiteratedObject,
18 {
19 fn object_kind() -> &'static CStr {
20 todo!()
21 }
22
23 unsafe extern "C" fn to_str(this: FfiValueRef<Object>) -> FfiSlice<str> {
24 todo!()
25 }
26
27 unsafe extern "C" fn from_str(from: FfiSliceRef<str>) -> FfiResult<Object, FfiError> {
28 todo!()
29 }
30
31 unsafe extern "C" fn home_uri(this: FfiValueRef<Object>) -> FfiSlice<str> {
32 todo!()
33 }
34 }
35
36 impl<T, O> IntoOperationVTable<O> for T
37 where
38 T: GiteratedOperation<O>,
39 O: GiteratedObject,
40 {
41 fn operation_kind() -> &'static CStr {
42 todo!()
43 }
44
45 unsafe extern "C" fn operation_serialize(
46 this: FfiValueRef<Operation>,
47 ) -> FfiResult<FfiSlice<[u8]>, FfiError> {
48 todo!()
49 }
50
51 unsafe extern "C" fn operation_deserialize(
52 buffer: FfiSliceRef<[u8]>,
53 ) -> FfiResult<Operation, FfiError> {
54 todo!()
55 }
56
57 unsafe extern "C" fn success_serialize(
58 success: FfiValueRefUntyped,
59 ) -> FfiResult<FfiSlice<[u8]>, FfiError> {
60 todo!()
61 }
62
63 unsafe extern "C" fn success_deserialize(
64 buffer: FfiSliceRef<[u8]>,
65 ) -> FfiResult<FfiValueUntyped, FfiError> {
66 todo!()
67 }
68
69 unsafe extern "C" fn failure_serialize(
70 failure: FfiValueRefUntyped,
71 ) -> FfiResult<FfiSlice<[u8]>, FfiError> {
72 todo!()
73 }
74
75 unsafe extern "C" fn failure_deserialize(
76 buffer: FfiSliceRef<[u8]>,
77 ) -> FfiResult<FfiValueUntyped, FfiError> {
78 todo!()
79 }
80 }
81
82 impl<T> IntoValueVTable for T {
83 unsafe extern "C" fn serialize(
84 buffer: FfiSliceRef<[u8]>,
85 ) -> FfiResult<crate::vtable::Value, FfiError> {
86 todo!()
87 }
88
89 unsafe extern "C" fn deserialize(
90 this: crate::vtable::Value,
91 ) -> FfiResult<FfiSlice<[u8]>, FfiError> {
92 todo!()
93 }
94 }
95
96 impl<T> IntoSettingVTable for T {
97 unsafe extern "C" fn serialize(this: Setting) -> FfiResult<FfiSlice<[u8]>, FfiError> {
98 todo!()
99 }
100
101 unsafe extern "C" fn deserialize(buffer: FfiSliceRef<[u8]>) -> FfiResult<Setting, FfiError> {
102 todo!()
103 }
104 }

giterated-runtime/giterated-abi/src/plugin.rs

View file
@@ -0,0 +1,13 @@
1 use dlopen2::wrapper::WrapperApi;
2
3 use crate::vtable::{
4 plugin::{Plugin, PluginVTable},
5 runtime::{RuntimeHandle, RuntimeVTable},
6 VTable,
7 };
8
9 #[derive(WrapperApi)]
10 pub struct GiteratedPluginAbi {
11 __load_runtime_vtable: unsafe extern "C" fn(vtable: &'static VTable<RuntimeHandle>),
12 __get_plugin_vtable: unsafe extern "C" fn() -> &'static VTable<Plugin>,
13 }

giterated-runtime/giterated-abi/src/result.rs

View file
@@ -0,0 +1,12 @@
1 use crate::FfiSlice;
2
3 #[repr(C)]
4 pub enum FfiResult<T, E> {
5 Ok(T),
6 Err(E),
7 }
8
9 #[repr(C)]
10 pub struct FfiError {
11 last_error: FfiSlice<str>,
12 }

giterated-runtime/giterated-abi/src/state.rs

View file
@@ -0,0 +1,136 @@
1 use anyhow::Error;
2
3 pub trait FromOperationState<O, D>: Sized {
4 fn from_operation_state(
5 state: &mut State,
6 object: &O,
7 operation: &D,
8 ) -> Result<Self, OperationError<Error>>;
9 }
10
11 pub struct StateExtractor<T>(T);
12
13 impl<T: FromState> FromState for StateExtractor<T> {
14 fn from_state(state: &mut State) -> Result<Self, Error> {
15 todo!()
16 }
17 }
18
19 use giterated_models::error::OperationError;
20
21 use crate::{
22 value_ex::FfiValueUntyped,
23 vtable::{ObjectABI, VTable},
24 };
25
26 #[repr(transparent)]
27 pub struct State {
28 inner: StateHandle,
29 }
30
31 #[repr(transparent)]
32 struct StateHandle {
33 state: FfiValueUntyped,
34 }
35
36 #[repr(C)]
37 struct StateItem<T: ?Sized> {
38 /// The pointer to the next item.
39 ///
40 /// `next_item` is most likely always an `FfiValue<StateItem<()>>` and that's how we free them.
41 next_item: *const StateItem<()>,
42 pub state_uuid: u128,
43 pub state: T,
44 }
45
46 impl Drop for State {
47 fn drop(&mut self) {
48 let state_manager = unsafe { StateManager::new(self) };
49
50 for state in state_manager {}
51 }
52 }
53
54 struct StateManager<'s> {
55 state: &'s mut State,
56 last: Option<StateHandle>,
57 }
58
59 impl<'s> StateManager<'s> {
60 pub unsafe fn new(handle: &'s mut State) -> Self {
61 todo!()
62 }
63
64 pub unsafe fn write_state<S: StateUUID>(&mut self, state: S) -> Self {
65 todo!()
66 }
67
68 pub unsafe fn get_state<S: StateUUID>(&mut self) -> Option<&S> {
69 todo!()
70 }
71 }
72
73 impl<'s> Iterator for StateManager<'s> {
74 type Item = StateItem<()>;
75
76 fn next(&mut self) -> Option<StateItem<()>> {
77 todo!()
78 }
79 }
80
81 pub trait StateUUID {
82 fn uuid() -> u128;
83
84 fn unsafe_hint_copy() -> Option<bool> {
85 None
86 }
87 }
88
89 /// State values for the current execution domain. 99.99% of the time this means "plugin-specific"
90 ///
91 /// The remainder 0.01% of the time it refers to the daemon's runtime domain.
92 pub struct DomainState(StateItem<()>);
93
94 impl StateUUID for DomainState {
95 fn uuid() -> u128 {
96 todo!()
97 }
98 }
99
100 pub struct RuntimeState(StateItem<&'static VTable<Runtime>>);
101
102 impl StateUUID for RuntimeState {
103 fn uuid() -> u128 {
104 todo!()
105 }
106 }
107
108 impl RuntimeState {
109 pub fn queue_insert_state<S: StateUUID>(&mut self, state: S) {
110 todo!()
111 }
112 }
113
114 pub struct Runtime {
115 pub queue_insert_state: unsafe extern "C" fn(state_uuid: u128, state: FfiValueUntyped),
116 }
117
118 impl ObjectABI for Runtime {
119 type VTable = Runtime;
120 }
121
122 pub trait FromState: Sized {
123 fn from_state(state: &mut State) -> Result<Self, Error>;
124 }
125
126 impl<T: StateUUID> FromState for T {
127 fn from_state(state: &mut State) -> Result<Self, Error> {
128 todo!()
129 }
130 }
131
132 impl<T: FromState> FromState for Option<T> {
133 fn from_state(state: &mut State) -> Result<Self, Error> {
134 todo!()
135 }
136 }

giterated-runtime/giterated-abi/src/vtable/mod.rs

View file
@@ -0,0 +1,41 @@
1 use std::{marker::PhantomData, mem::transmute, ops::Deref};
2
3 pub mod object;
4 pub mod operation;
5 pub mod plugin;
6 pub mod plugin_initialization;
7 pub mod runtime;
8 mod setting;
9 mod value;
10
11 pub use object::*;
12 pub use setting::*;
13 pub use value::*;
14
15 pub trait ObjectABI {
16 type VTable;
17 }
18
19 #[repr(transparent)]
20 pub struct VTable<T: ObjectABI> {
21 _marker: PhantomData<T>,
22 }
23
24 impl<T: ObjectABI> VTable<T> {
25 /// Creates a new `VTable<T>` reference to a static vtable in memory.
26 ///
27 /// Might be unsafe? It seems like it should be safe...
28 pub const fn new<V>(vtable: &'static V) -> &'static Self {
29 // We're going to transmute the reference to the typed vtable to us
30 // which will probably be fine
31 unsafe { transmute(vtable) }
32 }
33 }
34
35 impl<T: ObjectABI> Deref for VTable<T> {
36 type Target = T::VTable;
37
38 fn deref(&self) -> &Self::Target {
39 unsafe { transmute(self) }
40 }
41 }

giterated-runtime/giterated-abi/src/vtable/object.rs

View file
@@ -0,0 +1,67 @@
1 use std::{ffi::CStr, str::FromStr};
2
3 use crate::{
4 result::{FfiError, FfiResult},
5 value_ex::FfiValueUntyped,
6 FfiSlice, FfiSliceRef, FfiValueRef,
7 };
8
9 use super::{ObjectABI, VTable};
10
11 #[repr(C)]
12 pub struct Object {
13 inner: FfiValueUntyped,
14 vtable: &'static VTable<Object>,
15 }
16
17 impl Object {
18 pub fn home_uri(&self) -> String {
19 todo!()
20 }
21 }
22
23 impl<O: IntoObjectVTable> From<O> for Object {
24 fn from(value: O) -> Self {
25 todo!()
26 }
27 }
28
29 impl ToString for Object {
30 fn to_string(&self) -> String {
31 todo!()
32 }
33 }
34
35 impl FromStr for Object {
36 type Err = FfiError;
37
38 fn from_str(s: &str) -> Result<Self, Self::Err> {
39 todo!()
40 }
41 }
42
43 impl ObjectABI for Object {
44 type VTable = ObjectVTable;
45 }
46
47 pub struct ObjectVTable {
48 pub object_kind: &'static CStr,
49 pub to_str: unsafe extern "C" fn(this: FfiValueRef<Object>) -> FfiSlice<str>,
50 pub from_str: unsafe extern "C" fn(from: FfiSliceRef<str>) -> FfiResult<Object, FfiError>,
51 pub home_uri: unsafe extern "C" fn(this: FfiValueRef<Object>) -> FfiSlice<str>,
52 }
53
54 impl ObjectVTable {
55 pub const fn new<O: IntoObjectVTable>() -> Self {
56 todo!()
57 }
58 }
59
60 pub trait IntoObjectVTable: Sized {
61 const VTABLE: &'static VTable<Object> = VTable::new(&ObjectVTable::new::<Self>());
62
63 fn object_kind() -> &'static CStr;
64 unsafe extern "C" fn to_str(this: FfiValueRef<Object>) -> FfiSlice<str>;
65 unsafe extern "C" fn from_str(from: FfiSliceRef<str>) -> FfiResult<Object, FfiError>;
66 unsafe extern "C" fn home_uri(this: FfiValueRef<Object>) -> FfiSlice<str>;
67 }

giterated-runtime/giterated-abi/src/vtable/operation.rs

View file
@@ -0,0 +1,103 @@
1 use std::ffi::CStr;
2
3 use crate::{
4 result::{FfiError, FfiResult},
5 value_ex::{FfiValueRefUntyped, FfiValueUntyped},
6 FfiSlice, FfiSliceRef, FfiValue, FfiValueRef,
7 };
8
9 use super::{ObjectABI, VTable};
10
11 #[repr(C)]
12 pub struct Operation {
13 inner: FfiValueUntyped,
14 vtable: &'static VTable<Operation>,
15 }
16
17 impl Operation {
18 pub fn operation_kind(&self) -> &'static str {
19 todo!()
20 }
21
22 pub fn serialize(&self) -> Vec<u8> {
23 todo!()
24 }
25
26 pub fn deserialize_from<O, T: IntoOperationVTable<O>>(buffer: &[u8]) -> Result<Self, FfiError> {
27 todo!()
28 }
29 }
30
31 impl ObjectABI for Operation {
32 type VTable = OperationVTable;
33 }
34
35 pub struct OperationVTable {
36 pub operation_kind: &'static CStr,
37 pub operation_serialize:
38 unsafe extern "C" fn(this: FfiValueRef<Operation>) -> FfiResult<FfiSlice<[u8]>, FfiError>,
39 pub operation_deserialize:
40 unsafe extern "C" fn(buffer: FfiSliceRef<[u8]>) -> FfiResult<Operation, FfiError>,
41 pub success_serialize:
42 unsafe extern "C" fn(success: FfiValueRefUntyped) -> FfiResult<FfiSlice<[u8]>, FfiError>,
43 pub success_deserialize:
44 unsafe extern "C" fn(buffer: FfiSliceRef<[u8]>) -> FfiResult<FfiValueUntyped, FfiError>,
45 pub failure_serialize:
46 unsafe extern "C" fn(failure: FfiValueRefUntyped) -> FfiResult<FfiSlice<[u8]>, FfiError>,
47 pub failure_deserialize:
48 unsafe extern "C" fn(buffer: FfiSliceRef<[u8]>) -> FfiResult<FfiValueUntyped, FfiError>,
49 }
50
51 impl OperationVTable {
52 pub const fn new<O, T: IntoOperationVTable<O>>() -> Self {
53 todo!()
54 }
55
56 pub fn serialize(&self, operation: Operation) -> Result<Vec<u8>, FfiError> {
57 todo!()
58 }
59
60 pub fn deserialize(&self, buffer: &[u8]) -> Result<Operation, FfiError> {
61 todo!()
62 }
63
64 pub fn serialize_success(&self, success: FfiValueUntyped) -> Result<Vec<u8>, FfiError> {
65 todo!()
66 }
67
68 pub fn deserialize_success(&self, buffer: &[u8]) -> Result<FfiValueUntyped, FfiError> {
69 todo!()
70 }
71
72 pub fn serialize_failure(&self, failure: FfiValueUntyped) -> Result<Vec<u8>, FfiError> {
73 todo!()
74 }
75
76 pub fn deserialize_failure(&self, buffer: &[u8]) -> Result<FfiValueUntyped, FfiError> {
77 todo!()
78 }
79 }
80
81 pub trait IntoOperationVTable<O>: Sized {
82 const VTABLE: &'static VTable<Operation> = VTable::new(&OperationVTable::new::<O, Self>());
83
84 fn operation_kind() -> &'static CStr;
85 unsafe extern "C" fn operation_serialize(
86 this: FfiValueRef<Operation>,
87 ) -> FfiResult<FfiSlice<[u8]>, FfiError>;
88 unsafe extern "C" fn operation_deserialize(
89 buffer: FfiSliceRef<[u8]>,
90 ) -> FfiResult<Operation, FfiError>;
91 unsafe extern "C" fn success_serialize(
92 success: FfiValueRefUntyped,
93 ) -> FfiResult<FfiSlice<[u8]>, FfiError>;
94 unsafe extern "C" fn success_deserialize(
95 buffer: FfiSliceRef<[u8]>,
96 ) -> FfiResult<FfiValueUntyped, FfiError>;
97 unsafe extern "C" fn failure_serialize(
98 failure: FfiValueRefUntyped,
99 ) -> FfiResult<FfiSlice<[u8]>, FfiError>;
100 unsafe extern "C" fn failure_deserialize(
101 buffer: FfiSliceRef<[u8]>,
102 ) -> FfiResult<FfiValueUntyped, FfiError>;
103 }

giterated-runtime/giterated-abi/src/vtable/plugin.rs

View file
@@ -0,0 +1,25 @@
1 use crate::{value_ex::FfiValueRefUntyped, FfiSliceRef, FfiValueRef};
2
3 use super::ObjectABI;
4
5 pub struct Plugin {}
6
7 impl ObjectABI for Plugin {
8 type VTable = PluginVTable;
9 }
10
11 pub struct PluginVTable {
12 pub plugin_name: unsafe extern "C" fn() -> FfiSliceRef<str>,
13 pub plugin_version: unsafe extern "C" fn() -> FfiSliceRef<str>,
14 pub type_metadata: unsafe extern "C" fn() -> FfiValueRefUntyped,
15 }
16
17 impl PluginVTable {
18 pub fn plugin_name(&self) -> &'static str {
19 todo!()
20 }
21
22 pub fn type_metadata(&self) -> FfiValueRefUntyped {
23 todo!()
24 }
25 }

giterated-runtime/giterated-abi/src/vtable/plugin_initialization.rs

View file
@@ -0,0 +1,65 @@
1 use crate::{
2 callback::{
3 operation::OperationHandlerCallback, setting::SettingGetterCallback,
4 value::ValueGetterCallback, CallbackPtr,
5 },
6 FfiValueMut,
7 };
8
9 use super::{operation::Operation, Object, ObjectABI, Setting, VTable, Value};
10
11 #[repr(C)]
12 pub struct HostVTable {}
13
14 #[repr(C)]
15 #[derive(Clone, Copy)]
16 pub struct InitializationVTable {
17 pub register_object:
18 unsafe extern "C" fn(state: FfiValueMut<()>, &'static str, &'static VTable<Object>),
19 pub register_operation: unsafe extern "C" fn(
20 state: FfiValueMut<()>,
21 &'static str,
22 &'static str,
23 &'static VTable<Operation>,
24 ),
25 pub register_setting: unsafe extern "C" fn(
26 state: FfiValueMut<()>,
27 &'static str,
28 &'static str,
29 &'static VTable<Setting>,
30 ),
31 pub register_value: unsafe extern "C" fn(
32 state: FfiValueMut<()>,
33 &'static str,
34 &'static str,
35 &'static VTable<Value>,
36 ),
37
38 pub operation_handler: unsafe extern "C" fn(
39 state: FfiValueMut<()>,
40 &'static str,
41 &'static str,
42 CallbackPtr<OperationHandlerCallback>,
43 ),
44
45 pub value_getter: unsafe extern "C" fn(
46 state: FfiValueMut<()>,
47 &'static str,
48 &'static str,
49 CallbackPtr<ValueGetterCallback>,
50 ),
51
52 pub setting_getter: unsafe extern "C" fn(
53 state: FfiValueMut<()>,
54 &'static str,
55 &'static str,
56 CallbackPtr<SettingGetterCallback>,
57 ),
58 }
59
60 impl ObjectABI for InitializationVTable {
61 type VTable = InitializationVTable;
62 }
63
64 unsafe impl Sync for InitializationVTable {}
65 unsafe impl Send for InitializationVTable {}

giterated-runtime/giterated-abi/src/vtable/runtime.rs

View file
@@ -0,0 +1,52 @@
1 use giterated_models::{error::OperationError, object::ObjectRequestError};
2
3 use crate::{
4 result::{FfiError, FfiResult},
5 state::State,
6 value_ex::FfiValueUntyped,
7 FfiFuture, FfiSliceRef, FfiValueMut,
8 };
9
10 use super::{Object, ObjectABI};
11
12 pub struct RuntimeHandle;
13
14 impl ObjectABI for RuntimeHandle {
15 type VTable = RuntimeVTable;
16 }
17
18 #[derive(Clone, Copy)]
19 pub struct RuntimeVTable {
20 pub(crate) handle_fn: unsafe extern "C" fn(
21 FfiSliceRef<str>,
22 FfiSliceRef<str>,
23 FfiSliceRef<str>,
24 FfiSliceRef<[u8]>,
25 FfiSliceRef<[u8]>,
26 ) -> FfiFuture<
27 FfiResult<FfiValueUntyped, OperationError<FfiError>>,
28 >,
29 pub(crate) get_object:
30 unsafe extern "C" fn(
31 &str,
32 state: FfiValueMut<State>,
33 ) -> FfiResult<Object, OperationError<ObjectRequestError>>,
34 }
35
36 unsafe impl Send for RuntimeVTable {}
37 unsafe impl Sync for RuntimeVTable {}
38
39 pub trait IntoRuntimeVtable {
40 unsafe extern "C" fn handle(
41 object_kind: FfiSliceRef<str>,
42 operation_name: FfiSliceRef<str>,
43 object: FfiSliceRef<str>,
44 operation_payload: FfiSliceRef<[u8]>,
45 operation_state: FfiSliceRef<[u8]>,
46 ) -> FfiFuture<FfiResult<FfiValueUntyped, OperationError<FfiError>>>;
47
48 unsafe extern "C" fn get_object(
49 object_str: &str,
50 operation_state: FfiValueMut<State>,
51 ) -> FfiResult<Object, OperationError<ObjectRequestError>>;
52 }

giterated-runtime/giterated-abi/src/vtable/setting.rs

View file
@@ -0,0 +1,53 @@
1 use crate::{
2 result::{FfiError, FfiResult},
3 value_ex::FfiValueUntyped,
4 FfiSlice, FfiSliceRef,
5 };
6
7 use super::{ObjectABI, VTable};
8
9 #[repr(C)]
10 pub struct Setting {
11 inner: FfiValueUntyped,
12 vtable: &'static VTable<Setting>,
13 }
14
15 // impl<T: IntoSettingVTable> From<T> for Setting {
16 // fn from(value: T) -> Self {
17 // todo!()
18 // }
19 // }
20
21 impl ObjectABI for Setting {
22 type VTable = SettingVTable;
23 }
24
25 pub struct SettingVTable {
26 pub serialize: unsafe extern "C" fn(this: Setting) -> FfiResult<FfiSlice<[u8]>, FfiError>,
27 pub deserialize:
28 unsafe extern "C" fn(buffer: FfiSliceRef<[u8]>) -> FfiResult<Setting, FfiError>,
29 }
30
31 impl SettingVTable {
32 pub const fn new<S: IntoSettingVTable>() -> Self {
33 Self {
34 serialize: S::serialize,
35 deserialize: S::deserialize,
36 }
37 }
38
39 pub fn serialize(&self, setting: Setting) -> Result<Vec<u8>, FfiError> {
40 todo!()
41 }
42
43 pub fn deserialize(&self, buffer: &[u8]) -> Result<Setting, FfiError> {
44 todo!()
45 }
46 }
47
48 pub trait IntoSettingVTable: Sized {
49 const VTABLE: &'static VTable<Setting> = VTable::new(&SettingVTable::new::<Self>());
50
51 unsafe extern "C" fn serialize(this: Setting) -> FfiResult<FfiSlice<[u8]>, FfiError>;
52 unsafe extern "C" fn deserialize(buffer: FfiSliceRef<[u8]>) -> FfiResult<Setting, FfiError>;
53 }

giterated-runtime/giterated-abi/src/vtable/value.rs

View file
@@ -0,0 +1,52 @@
1 use crate::{
2 result::{FfiError, FfiResult},
3 value_ex::FfiValueUntyped,
4 FfiSlice, FfiSliceRef,
5 };
6
7 use super::{ObjectABI, VTable};
8
9 #[repr(C)]
10 pub struct Value {
11 inner: FfiValueUntyped,
12 vtable: &'static VTable<Value>,
13 }
14
15 impl Value {
16 pub fn from<T: IntoValueVTable>(value: T) -> Self {
17 todo!()
18 }
19 }
20
21 impl ObjectABI for Value {
22 type VTable = ValueVTable;
23 }
24
25 pub struct ValueVTable {
26 pub serialize: unsafe extern "C" fn(buffer: FfiSliceRef<[u8]>) -> FfiResult<Value, FfiError>,
27 pub deserialize: unsafe extern "C" fn(this: Value) -> FfiResult<FfiSlice<[u8]>, FfiError>,
28 }
29
30 impl ValueVTable {
31 pub const fn new<V: IntoValueVTable>() -> Self {
32 Self {
33 serialize: V::serialize,
34 deserialize: V::deserialize,
35 }
36 }
37
38 pub fn serialize(&self, value: &Value) -> Result<Vec<u8>, FfiError> {
39 todo!()
40 }
41
42 pub fn deserialize(&self, buffer: &[u8]) -> Result<Value, FfiError> {
43 todo!()
44 }
45 }
46
47 pub trait IntoValueVTable: Sized {
48 const VTABLE: &'static VTable<Value> = VTable::new(&ValueVTable::new::<Self>());
49
50 unsafe extern "C" fn serialize(buffer: FfiSliceRef<[u8]>) -> FfiResult<Value, FfiError>;
51 unsafe extern "C" fn deserialize(this: Value) -> FfiResult<FfiSlice<[u8]>, FfiError>;
52 }

giterated-runtime/src/lib.rs

View file
@@ -1,50 +1,55 @@
1 mod operation_walker;
2 pub mod plugin;
3
4 use std::{collections::HashMap, sync::Arc};
5
6 use dlopen2::wrapper::Container;
7 use giterated_abi::{
8 callback::{
9 operation::OperationHandlerCallback,
10 setting::{SettingChangeCallback, SettingGetterCallback},
11 value::{ValueChangeCallback, ValueGetterCallback},
12 CallbackPtr,
13 },
14 plugin::GiteratedPluginAbi,
15 vtable::{
16 operation::Operation, plugin::Plugin, runtime::RuntimeHandle, Object, Setting, VTable,
17 Value,
18 },
19 };
20 use giterated_core::types::TypeMetadata;
21 use giterated_models::{
22 error::OperationError,
23 object::{GiteratedObject, ObjectOperationPair},
24 operation::GiteratedOperation,
25 settings::ObjectSettingPair,
26 value::ObjectValuePair,
27 };
28 use operation_walker::OperationHandlerRules;
29 use plugin::initialization::PluginInitializationState;
30 use tracing::{debug, debug_span, trace, trace_span, warn};
31
1 32 pub struct Runtime {
2 plugins: Vec<PluginHandle>,
33 plugins: Vec<RuntimePlugin>,
3 34 handlers: RuntimeHandlers,
4 35 }
5 36
6 pub struct FfiRuntimeMetadata {
7 runtime: PluginState,
37 #[derive(Clone)]
38 pub struct RuntimePlugin {
39 vtable: &'static VTable<Plugin>,
40 library: Arc<Container<GiteratedPluginAbi>>,
8 41 }
9 42
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 {
43 impl RuntimePlugin {
44 pub fn name(&self) -> &'static str {
20 45 todo!()
21 46 }
22 47
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))
48 pub fn version(&self) -> &'static str {
49 todo!()
50 }
47 51
52 pub fn metadata(&self) -> &TypeMetadata {
48 53 todo!()
49 54 }
50 55 }
@@ -57,23 +62,16 @@ impl Runtime {
57 62 })
58 63 }
59 64
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 }
65 pub fn state(self: &Box<Self>) -> RuntimeHandle {
66 RuntimeHandle
69 67 }
70 68
71 69 pub fn insert_plugin(
72 70 &mut self,
73 mut plugin: PluginHandle,
71 mut plugin: RuntimePlugin,
74 72 mut initialization: PluginInitializationState,
75 73 ) {
76 let _guard = debug_span!("inserting plugin", meta = debug(&plugin.meta)).entered();
74 let _guard = debug_span!("inserting plugin", meta = debug(&plugin.name())).entered();
77 75
78 76 for (pair, callback) in initialization.operation_handlers.drain() {
79 77 let _guard =
@@ -127,7 +125,8 @@ impl Runtime {
127 125 }
128 126
129 127 pub fn init(self: Box<Self>) {
130 unsafe { giterated_static_runtime::initialize_runtime(Box::into_raw(self).cast::<()>()) }
128 todo!()
129 // unsafe { giterated_static_runtime::initialize_runtime(Box::into_raw(self).cast::<()>()) }
131 130 }
132 131
133 132 // pub async fn handle(
@@ -154,6 +153,99 @@ impl Runtime {
154 153 }
155 154 }
156 155
156 pub struct RuntimeDomain {
157 plugin: RuntimePlugin,
158 }
159
160 impl RuntimeDomain {
161 pub fn from_plugin(plugin: &RuntimePlugin) -> Self {
162 Self {
163 plugin: plugin.clone(),
164 }
165 }
166
167 pub fn object_vtable(&self, object_kind: &str) -> Option<&'static VTable<Object>> {
168 self.plugin.metadata().objects.get(object_kind).copied()
169 }
170
171 pub fn operation_vtable(
172 &self,
173 object_kind: &str,
174 operation_name: &str,
175 ) -> Option<&'static VTable<Operation>> {
176 self.plugin
177 .metadata()
178 .operations
179 .get(&ObjectOperationPair::new(object_kind, operation_name))
180 .copied()
181 }
182
183 pub fn setting_vtable(
184 &self,
185 object_kind: &str,
186 setting_name: &str,
187 ) -> Option<&'static VTable<Setting>> {
188 self.plugin
189 .metadata()
190 .settings
191 .get(&ObjectSettingPair::new(object_kind, setting_name))
192 .copied()
193 }
194
195 pub fn value_vtable(
196 &self,
197 object_kind: &str,
198 value_name: &str,
199 ) -> Option<&'static VTable<Value>> {
200 self.plugin
201 .metadata()
202 .values
203 .get(&ObjectValuePair::new(object_kind, value_name))
204 .copied()
205 }
206 }
207
208 #[repr(C)]
209 pub struct FFIPluginMeta {
210 pub name: *const u8,
211 pub name_len: usize,
212 pub version: *const u8,
213 pub version_len: usize,
214 }
215
216 // pub struct RuntimePlugin {
217 // handle: PluginHandle,
218 // type_metadata: Arc<TypeMetadata>,
219 // }
220
221 impl RuntimePlugin {
222 // pub fn plugin_meta(&self) -> PluginMeta {
223 // let meta = unsafe { self.handle.raw.plugin_meta() };
224
225 // let name = unsafe { std::slice::from_raw_parts(meta.name, meta.name_len) };
226 // let version = unsafe { std::slice::from_raw_parts(meta.version, meta.version_len) };
227
228 // let name = std::str::from_utf8(name).unwrap();
229 // let version = std::str::from_utf8(version).unwrap();
230
231 // PluginMeta {
232 // name: String::from(name),
233 // version: Version::parse(version).unwrap(),
234 // }
235 // }
236 }
237
238 // #[derive(WrapperApi)]
239 // pub struct GiteratedPluginApi {
240 // plugin_meta: unsafe extern "C" fn() -> FFIPluginMeta,
241 // load_host_vtable: unsafe extern "C" fn(vtable: &HostVTable),
242 // load_initialization_vtable: unsafe extern "C" fn(vtable: &'static VTable<Initialization>),
243 // initialize: unsafe extern "C" fn(runtime_state: *const RuntimeState) -> PluginState,
244 // initialize_registration: unsafe extern "C" fn(
245 // init_state: *mut PluginInitializationState,
246 // ) -> *mut PluginInitializationState,
247 // load_type_metadata: unsafe extern "C" fn(metadata: *mut ()),
248 // }
157 249 #[derive(Default)]
158 250 pub struct RuntimeHandlers {
159 251 operation_handlers: HashMap<
@@ -288,107 +380,3 @@ impl RuntimeHandlers {
288 380 OperationHandlerRules::new(object_kind, operation_name, self)
289 381 }
290 382 }
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 }

giterated-runtime/src/operation_walker.rs

View file
@@ -0,0 +1,270 @@
1 use giterated_abi::{result::FfiError, value_ex::FfiValueUntyped, vtable::runtime::RuntimeHandle};
2 use giterated_models::{
3 error::OperationError, object::ObjectOperationPair, operation::GiteratedOperation,
4 settings::GetSetting, value::GetValue,
5 };
6
7 use tracing::{debug_span, trace, trace_span};
8
9 use super::{ObjectSettingPair, ObjectValuePair, RuntimeHandlers};
10
11 /// A wrapper for operation handling that enforces handling rules.
12 ///
13 /// # Handler Resolution
14 /// In order, handler resolution will be attempted as follows:
15 ///
16 /// | Index | object_kind | operation_kind | Special Case? |
17 /// |-------|-------------|-----------------|---------------|
18 /// | 1 | `any` | `typed` | No |
19 /// | 2 | `typed` | `any` | No |
20 /// | 3 | `any` | `any` | No |
21 /// | 4 | `any` | `GetValue` | ⚠️ Yes ⚠️ |
22 /// | 5 | `any` | `GetSetting` | ⚠️ Yes ⚠️ |
23 /// | 6 | `any` | `SetSetting` | ⚠️ Yes ⚠️ |
24 /// | 7 | `any` | `ObjectRequest` | ⚠️ Yes ⚠️ |
25 /// | 8 | `typed` | `typed` | No |
26 pub struct OperationHandlerRules<'a> {
27 object_kind: &'a str,
28 operation_name: &'a str,
29 handlers: &'a RuntimeHandlers,
30 }
31
32 impl<'o> OperationHandlerRules<'o> {
33 pub fn new(
34 object_kind: &'o str,
35 operation_name: &'o str,
36 handlers: &'o RuntimeHandlers,
37 ) -> Self {
38 Self {
39 object_kind,
40 operation_name,
41 handlers,
42 }
43 }
44
45 pub async fn handle(
46 &self,
47 runtime: &RuntimeHandle,
48 object: &str,
49 operation_payload: &[u8],
50 ) -> Result<FfiValueUntyped, OperationError<FfiError>> {
51 // object_kind: `any`
52 // operation_kind: `typed`
53 if let Some(_handler) = self
54 .handlers
55 .operation_handlers
56 .get(&ObjectOperationPair::new("any", self.operation_name))
57 {
58 todo!()
59 }
60
61 // object_kind: `typed`
62 // operation_kind: `any`
63 if let Some(_handler) = self
64 .handlers
65 .operation_handlers
66 .get(&ObjectOperationPair::new(self.object_kind, "any"))
67 {}
68
69 // object_kind: `any`
70 // operation_kind: `any`
71 if let Some(_handler) = self
72 .handlers
73 .operation_handlers
74 .get(&ObjectOperationPair::new("any", "any"))
75 {}
76
77 // ⚠️ Special Case ⚠️
78 // object_kind: `any`
79 // operation_kind: `GetValue`
80 if self.operation_name == "get_value" {
81 let operation: GetValue = todo!();
82 let _guard = trace_span!(
83 "get_value handler resolving",
84 object = self.object_kind,
85 value = operation.value_name
86 )
87 .entered();
88
89 if let Some((domain, callback)) = self.handlers.value_getters.get(
90 &ObjectValuePair::new(self.object_kind, &operation.value_name),
91 ) {
92 trace_span!(
93 "get_value handler.",
94 object = self.object_kind,
95 value_name = operation.value_name
96 );
97
98 let object_vtable = domain
99 .object_vtable(self.object_kind)
100 .ok_or_else(|| OperationError::Unhandled)?;
101 trace!("Resolved object vtable for {}", self.object_kind);
102
103 let _value_vtable = domain
104 .value_vtable(self.object_kind, &operation.value_name)
105 .ok_or_else(|| OperationError::Unhandled)?;
106 trace!(
107 "Resolved value vtable for {}::{}",
108 self.object_kind,
109 operation.value_name
110 );
111
112 // let object = unsafe { (object_vtable.from_str)(object) }
113 // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?;
114
115 // let _guard = debug_span!("get_value handler");
116
117 // let result = unsafe {
118 // (callback.func)(
119 // callback.callback_ptr,
120 // runtime_state,
121 // &domain.plugin.state,
122 // object,
123 // )
124 // }
125 // .await;
126
127 // match result {
128 // Ok(value) => return Ok(value.into()),
129 // Err(_err) => todo!(),
130 // }
131
132 todo!()
133 } else {
134 trace!("Failed to resolve handler.");
135 }
136 }
137
138 // ⚠️ Special Case ⚠️
139 // object_kind: `any`
140 // operation_kind: `GetSetting`
141 if self.operation_name == "get_setting" {
142 let operation: GetSetting = todo!();
143 let _guard = trace_span!(
144 "get_setting handler resolving",
145 object = self.object_kind,
146 setting = operation.setting_name
147 )
148 .entered();
149
150 if let Some((domain, callback)) = self.handlers.setting_getters.get(
151 &ObjectSettingPair::new(self.object_kind, &operation.setting_name),
152 ) {
153 trace_span!(
154 "get_setting handler.",
155 object = self.object_kind,
156 setting_name = operation.setting_name
157 );
158
159 let object_vtable = domain
160 .object_vtable(self.object_kind)
161 .ok_or_else(|| OperationError::Unhandled)?;
162 trace!("Resolved object vtable for {}", self.object_kind);
163
164 let _setting_vtable = domain
165 .setting_vtable(self.object_kind, &operation.setting_name)
166 .ok_or_else(|| OperationError::Unhandled)?;
167 trace!("Resolved setting vtable for {}", operation.setting_name);
168
169 todo!()
170
171 // let object = unsafe { (object_vtable.from_str)(object) }
172 // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?;
173
174 // let _guard = debug_span!("get_value handler");
175
176 // let result = unsafe {
177 // (callback.func())(
178 // callback.callback_ptr,
179 // runtime_state,
180 // &domain.plugin.state,
181 // object,
182 // )
183 // }
184 // .await;
185
186 // match result {
187 // Ok(value) => {
188 // let vtable = unsafe { (value.vtable.get_setting_vtable)() };
189 // let return_value: Value = serde_json::from_slice(unsafe {
190 // (value.vtable.serialize)(value).unwrap().as_ref()
191 // })
192 // .unwrap();
193
194 // todo!()
195
196 // // return Ok(unsafe {
197 // // AnySuccess::from_raw(
198 // // FFIBox::from_box(Box::new(return_value)).untyped(),
199 // // vtable,
200 // // )
201 // // });
202 // }
203 // Err(_err) => todo!(),
204 // }
205 } else {
206 trace!("Failed to resolve handler.");
207 }
208 }
209
210 // ⚠️ Special Case ⚠️
211 // object_kind: `any`
212 // operation_kind: `SetSetting`
213 self.operation_name == "set_setting";
214
215 // ⚠️ Special Case ⚠️
216 // object_kind: `any`
217 // operation_kind: `ObjectRequest`
218 self.operation_name == "object_request";
219
220 // object_kind: `typed`
221 // operation_kind: `typed`
222 if let Some((domain, handler)) =
223 self.handlers
224 .operation_handlers
225 .get(&ObjectOperationPair::new(
226 self.object_kind,
227 self.operation_name,
228 ))
229 {
230 let _guard = trace_span!("typed_typed handler resolved").entered();
231
232 let object_vtable = domain
233 .object_vtable(self.object_kind)
234 .ok_or_else(|| OperationError::Unhandled)?;
235 trace!("Resolved object vtable for {}", self.object_kind);
236
237 let operation_vtable = domain
238 .operation_vtable(self.object_kind, self.operation_name)
239 .ok_or_else(|| OperationError::Unhandled)?;
240 trace!(
241 "Resolved operation vtable for {}::{}",
242 self.object_kind,
243 self.operation_name
244 );
245
246 todo!()
247
248 // let object = unsafe { (object_vtable.from_str)(object) }
249 // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?;
250 // let operation = unsafe { (operation_vtable.deserialize)(operation_payload) }
251 // .map_err(|_| OperationError::Internal(anyhow::anyhow!("yikes!")))?;
252 // trace!("Parsed operation data");
253
254 // let _guard = debug_span!("calling handler").entered();
255 // let result = unsafe {
256 // (handler.func)(
257 // handler.callback_ptr,
258 // runtime_state,
259 // &domain.plugin.state,
260 // object,
261 // operation,
262 // )
263 // };
264
265 // return result.await;
266 }
267
268 Err(OperationError::Unhandled)
269 }
270 }

giterated-runtime/src/plugin/initialization.rs

View file
@@ -0,0 +1,19 @@
1 use std::collections::HashMap;
2
3 use giterated_abi::callback::{
4 operation::OperationHandlerCallback, setting::SettingGetterCallback,
5 value::ValueGetterCallback, CallbackPtr,
6 };
7 use giterated_core::types::TypeMetadata;
8 use giterated_models::{
9 object::ObjectOperationPair, settings::ObjectSettingPair, value::ObjectValuePair,
10 };
11
12 #[derive(Default)]
13 pub struct PluginInitializationState {
14 pub type_metadata: TypeMetadata,
15 pub operation_handlers:
16 HashMap<ObjectOperationPair<'static>, CallbackPtr<OperationHandlerCallback>>,
17 pub value_getters: HashMap<ObjectValuePair<'static>, CallbackPtr<ValueGetterCallback>>,
18 pub setting_getters: HashMap<ObjectSettingPair<'static>, CallbackPtr<SettingGetterCallback>>,
19 }

giterated-runtime/src/plugin/mod.rs

View file
@@ -0,0 +1 @@
1 pub mod initialization;

plugins/example-plugin/Cargo.toml

View file
@@ -15,7 +15,7 @@ giterated-plugin = { path = "../../giterated-plugin" }
15 15 giterated-static-runtime = { path = "../../giterated-runtime/giterated-static-runtime" }
16 16 dlopen2 = "0.6"
17 17 tracing-subscriber = "0.3"
18 giterated-models = { path = "../../giterated-models" }
18 giterated-models = { path = "../../giterated-core/giterated-models" }
19 19 tracing = "0.1"
20 20 serde_json = "1.0"
21 21 anyhow = "1"

plugins/example-plugin/src/lib.rs

View file
@@ -33,13 +33,9 @@ impl StateUUID for PluginState {
33 33 /// build the plugin's stack.
34 34 #[plugin::init]
35 35 pub fn init(builder: &mut PluginStackBuilder) -> Result<(), Error> {
36 builder
37 .insert_state(PluginState);
38 builder
39 .object::<Instance>()
40 .object::<User>();
41 builder
42 .setting_getter(setting_getter);
36 builder.insert_state(PluginState);
37 builder.object::<Instance>().object::<User>();
38 builder.setting_getter(setting_getter);
43 39
44 40 Ok(())
45 41 }

plugins/giterated-backend/Cargo.toml

View file
@@ -7,7 +7,7 @@ edition = "2021"
7 7
8 8 [dependencies]
9 9 giterated-plugin = { path = "../../giterated-plugin" }
10 giterated-models = { path = "../../giterated-models" }
10 giterated-models = { path = "../../giterated-core/giterated-models" }
11 11 serde = { version = "1.0", features = [ "derive" ]}
12 12 anyhow = "1"
13 13 thiserror = "1"

plugins/giterated-issues/Cargo.toml

View file
@@ -12,7 +12,7 @@ crate-type = ["rlib", "dylib"]
12 12
13 13 [dependencies]
14 14 giterated-plugin = { path = "../../giterated-plugin" }
15 giterated-models = { path = "../../giterated-models" }
15 giterated-models = { path = "../../giterated-core/giterated-models" }
16 16 serde = { version = "1.0", features = [ "derive" ]}
17 17 anyhow = "1"
18 18 thiserror = "1"

plugins/giterated-protocol/Cargo.toml

View file
@@ -12,7 +12,7 @@ crate-type = ["dylib", "rlib"]
12 12
13 13 [dependencies]
14 14 giterated-plugin = { path = "../../giterated-plugin" }
15 giterated-models = { path = "../../giterated-models" }
15 giterated-models = { path = "../../giterated-core/giterated-models" }
16 16 serde = { version = "1.0", features = [ "derive" ]}
17 17 anyhow = "1"
18 18 toml = { version = "0.8" }