fission_core/
capability.rs1use serde::{Deserialize, Serialize};
2use std::marker::PhantomData;
3
4#[derive(Clone, Debug)]
6pub struct CapabilityCtx {
7 pub req_id: u64,
9}
10
11pub trait OperationCapability: Send + 'static {
16 type Request: Serialize + for<'de> Deserialize<'de> + Send + 'static;
17 type Ok: Serialize + for<'de> Deserialize<'de> + Send + 'static;
18 type Err: Serialize + for<'de> Deserialize<'de> + Send + 'static;
19}
20
21#[derive(Copy, Clone)]
23pub struct CapabilityType<C: OperationCapability> {
24 pub name: &'static str,
26 _marker: PhantomData<fn() -> C>,
27}
28
29impl<C: OperationCapability> CapabilityType<C> {
30 pub const fn new(name: &'static str) -> Self {
31 Self {
32 name,
33 _marker: PhantomData,
34 }
35 }
36}
37
38impl<C: OperationCapability> std::fmt::Debug for CapabilityType<C> {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 f.debug_struct("CapabilityType")
41 .field("name", &self.name)
42 .finish()
43 }
44}
45
46impl<C: OperationCapability> PartialEq for CapabilityType<C> {
47 fn eq(&self, other: &Self) -> bool {
48 self.name == other.name
49 }
50}
51
52impl<C: OperationCapability> Eq for CapabilityType<C> {}
53
54impl<C: OperationCapability> std::hash::Hash for CapabilityType<C> {
55 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
56 self.name.hash(state);
57 }
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
61pub struct OperationCapabilityInvocation {
62 pub capability_name: String,
63 pub request: Vec<u8>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
67pub enum CapabilityInvocationPayload {
68 Operation(OperationCapabilityInvocation),
69}
70
71#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
72pub struct OpenUrlRequest {
73 pub url: String,
74 pub in_app: bool,
75}
76
77pub struct OpenUrlCapability;
78
79impl OperationCapability for OpenUrlCapability {
80 type Request = OpenUrlRequest;
81 type Ok = ();
82 type Err = String;
83}
84
85pub const OPEN_URL: CapabilityType<OpenUrlCapability> = CapabilityType::new("fission.ui.open_url");
86
87#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
94pub struct PickOpenFilesRequest {
95 pub allow_multiple: bool,
96 pub mime_types: Vec<String>,
97 pub extensions: Vec<String>,
98}
99
100#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
102pub struct PickedFile {
103 pub name: String,
104 pub content_type: String,
105 pub bytes: Vec<u8>,
106}
107
108#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
110pub struct PickOpenFilesResult {
111 pub files: Vec<PickedFile>,
112}
113
114#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
116pub struct PickOpenFilesError {
117 pub code: String,
118 pub message: String,
119}
120
121pub struct PickOpenFilesCapability;
122
123impl OperationCapability for PickOpenFilesCapability {
124 type Request = PickOpenFilesRequest;
125 type Ok = PickOpenFilesResult;
126 type Err = PickOpenFilesError;
127}
128
129pub const PICK_OPEN_FILES: CapabilityType<PickOpenFilesCapability> =
130 CapabilityType::new("fission.fs.pick_open");
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn pick_open_files_round_trips() {
138 let request = PickOpenFilesRequest {
139 allow_multiple: true,
140 mime_types: vec!["image/png".into(), "application/pdf".into()],
141 extensions: vec!["png".into(), "pdf".into()],
142 };
143 let bytes = serde_json::to_vec(&request).unwrap();
144 let decoded: PickOpenFilesRequest = serde_json::from_slice(&bytes).unwrap();
145 assert_eq!(decoded, request);
146
147 let result = PickOpenFilesResult {
148 files: vec![PickedFile {
149 name: "receipt.pdf".into(),
150 content_type: "application/pdf".into(),
151 bytes: b"hello".to_vec(),
152 }],
153 };
154 let bytes = serde_json::to_vec(&result).unwrap();
155 let decoded: PickOpenFilesResult = serde_json::from_slice(&bytes).unwrap();
156 assert_eq!(decoded, result);
157 }
158
159 #[test]
160 fn open_url_round_trips() {
161 let request = OpenUrlRequest {
162 url: "https://fission.dev".into(),
163 in_app: false,
164 };
165
166 let bytes = serde_json::to_vec(&request).unwrap();
167 let decoded: OpenUrlRequest = serde_json::from_slice(&bytes).unwrap();
168
169 assert_eq!(decoded, request);
170 }
171}