summaryrefslogtreecommitdiff
path: root/src/capabilities.rs
diff options
context:
space:
mode:
authorJakub Stachurski <jakub@wilkuu.nl>2026-08-22 00:59:22 +0200
committerJakub Stachurski <jakub@wilkuu.nl>2026-08-22 00:59:22 +0200
commit030c489d2bc34f267cadacdec8cd13249672ccb5 (patch)
treeff7b67753acf1fbc313655334784728809079f40 /src/capabilities.rs
parent1047933fcb9e5b80401eae5e7e188dfd1fe32a91 (diff)
Make Capability into CapabilityDyn and Add non-dyn Capability trait
Diffstat (limited to '')
-rw-r--r--src/capabilities.rs109
1 files changed, 68 insertions, 41 deletions
diff --git a/src/capabilities.rs b/src/capabilities.rs
index 63a526c..63aa6e8 100644
--- a/src/capabilities.rs
+++ b/src/capabilities.rs
@@ -1,6 +1,8 @@
use std::any::Any;
use std::collections::BTreeMap;
+use serde::{Deserialize, Serialize};
+
use crate::session::ISession;
use crate::*;
@@ -9,7 +11,23 @@ use crate::*;
pub const URN_JMAP_CORE: &str = "urn:ietf:params:jmap:core";
// Capabilities {{{
-pub trait Capability {
+
+pub trait Capability: 'static + Sized {
+ const URN: &str;
+
+ fn from_object(obj: &JObject) -> Self;
+ fn account_cap(&self, account_id: JMAPId, obj: &JObject) -> Self;
+ fn account(&self) -> Option<JMAPId>;
+ fn from_object_dyn(obj: &JObject) -> Box<dyn CapabilityDyn> {
+ Box::new(Self::from_object(obj))
+ }
+
+ fn is_account_capability(&self) -> bool {
+ self.account().is_some()
+ }
+}
+
+pub trait CapabilityDyn {
// Get urn of the capability
fn get_urn(&self) -> &'static str;
@@ -23,38 +41,61 @@ pub trait Capability {
fn to_any(self) -> Box<dyn Any>;
/// Given a capability and accountCapabilities Object get a capability
- fn account_cap(&self, account_id: JMAPId, obj: &JObject) -> Box<dyn Capability>;
+ fn account_cap_dyn(&self, account_id: JMAPId, obj: &JObject) -> Box<dyn CapabilityDyn>;
/// Return the account if this capabilities has been given info for account
- fn account(&self) -> Option<JMAPId>;
+ fn account_dyn(&self) -> Option<JMAPId>;
+}
+
+impl<T: Capability> CapabilityDyn for T {
+ fn get_urn(&self) -> &'static str {
+ T::URN
+ }
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+
+ fn as_any_mut(&mut self) -> &mut dyn Any {
+ self
+ }
+
+ fn to_any(self) -> Box<dyn Any> {
+ Box::new(self)
+ }
+
+ fn account_cap_dyn(&self, account_id: JMAPId, obj: &JObject) -> Box<dyn CapabilityDyn> {
+ Box::new(self.account_cap(account_id, obj))
+ }
+
+ fn account_dyn(&self) -> Option<JMAPId> {
+ self.account()
+ }
}
/// A function that parses a JObject into a Capability Trait object.
/// This capability will be able to implement functionality to the JMAPSession object.
-pub type CapabilityParser = Box<dyn Fn(JObject) -> Box<dyn Capability>>;
+pub type CapabilityParser = Box<dyn Fn(&JObject) -> Box<dyn CapabilityDyn>>;
/// Collection of CapabilityParser
-pub struct CapabilityParsers(pub BTreeMap<String, CapabilityParser>);
+pub struct CapabilityRegistry(pub BTreeMap<String, CapabilityParser>);
-impl Default for CapabilityParsers {
+impl Default for CapabilityRegistry {
fn default() -> Self {
let mut c = Self::new();
- c.insert(
- URN_JMAP_CORE.to_string(),
- Box::new(JMAPCoreCapability::from_object),
- );
+ c.add_capability::<JMAPCoreCapability>();
c
}
}
-impl CapabilityParsers {
+impl CapabilityRegistry {
/// Create a collection of parsers
pub fn new() -> Self {
Self(BTreeMap::new())
}
/// Insert a parser
- pub fn insert(&mut self, urn: String, parser: CapabilityParser) {
- self.0.insert(urn, parser);
+ pub fn add_capability<T: Capability>(&mut self) {
+ self.0
+ .insert(T::URN.to_string(), Box::new(T::from_object_dyn));
}
/// Use the parsers to create a list of capabilities supported by the server in the session.
@@ -62,7 +103,7 @@ impl CapabilityParsers {
let mut out = BTreeMap::new();
for (urn, cap) in session.capabilities.iter() {
if let Some(parser) = self.0.get(urn) {
- out.insert(urn.clone(), parser(cap.clone()));
+ out.insert(urn.clone(), parser(cap));
};
}
ServerCapabilities(out)
@@ -70,20 +111,20 @@ impl CapabilityParsers {
}
/// The backing datatype in the CapabilityCollection trait.
-pub type CapabilityMap = BTreeMap<String, Box<dyn Capability>>;
+pub type CapabilityMap = BTreeMap<String, Box<dyn CapabilityDyn>>;
/// Trait for list of capabilities, or any URN -> Capabilty collection
pub trait CapabilityCollection {
fn inner(&self) -> &CapabilityMap;
fn inner_mut(&mut self) -> &mut CapabilityMap;
- fn get_capability<T: 'static + Capability>(&self, urn: &str) -> Option<&T> {
- self.inner().get(urn)?.as_any().downcast_ref::<T>()
+ fn get_capability<T: Capability>(&self) -> Option<&T> {
+ self.inner().get(T::URN)?.as_any().downcast_ref::<T>()
}
- fn get_capability_mut<T: 'static + Capability>(&mut self, urn: &str) -> Option<&mut T> {
+ fn get_capability_mut<T: Capability>(&mut self) -> Option<&mut T> {
self.inner_mut()
- .get_mut(urn)?
+ .get_mut(T::URN)?
.as_any_mut()
.downcast_mut::<T>()
}
@@ -122,7 +163,7 @@ impl ServerCapabilities {
let empty = JObj::new();
for (urn, scap) in self.0.iter() {
let ccap = acc.accountCapabilities.get(urn).unwrap_or(&empty);
- out.insert(urn.clone(), scap.account_cap(client.clone(), ccap));
+ out.insert(urn.clone(), scap.account_cap_dyn(client.clone(), ccap));
}
AccountCapabilities(out)
})
@@ -167,23 +208,16 @@ pub struct JMAPCoreCapability {
}
impl Capability for JMAPCoreCapability {
- fn get_urn(&self) -> &'static str {
- URN_JMAP_CORE
- }
- fn as_any(&self) -> &dyn Any {
- self
- }
+ const URN: &str = URN_JMAP_CORE;
- fn as_any_mut(&mut self) -> &mut dyn Any {
- self
- }
-
- fn to_any(self) -> Box<dyn Any> {
- Box::new(self)
+ fn from_object(obj: &JObject) -> Self {
+ // TODO: Unwrap
+ let out: Self = serde_json::from_value(JUnknown::Object(obj.clone()).into()).unwrap();
+ out
}
- fn account_cap(&self, account_id: JMAPId, _: &JObject) -> Box<dyn Capability> {
- let mut out: Box<JMAPCoreCapability> = Box::new(self.clone());
+ fn account_cap(&self, account_id: JMAPId, _: &JObject) -> Self {
+ let mut out = self.clone();
out.accountId = Some(account_id);
out
}
@@ -193,11 +227,4 @@ impl Capability for JMAPCoreCapability {
}
}
-impl JMAPCoreCapability {
- fn from_object(obj: JObject) -> Box<dyn Capability> {
- // TODO: Unwrap
- let out: Self = serde_json::from_value(JUnknown::Object(obj).into()).unwrap();
- Box::new(out)
- }
-}
// }}}