summaryrefslogtreecommitdiff
path: root/src/session.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/session.rs
parent1047933fcb9e5b80401eae5e7e188dfd1fe32a91 (diff)
Make Capability into CapabilityDyn and Add non-dyn Capability trait
Diffstat (limited to 'src/session.rs')
-rw-r--r--src/session.rs113
1 files changed, 97 insertions, 16 deletions
diff --git a/src/session.rs b/src/session.rs
index 82a3563..b9e508e 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -3,7 +3,7 @@ use std::any::Any;
use std::collections::BTreeMap;
use std::collections::btree_map::{Iter, Keys};
-use crate::capabilities::{AccountCapabilities, CapabilityParsers, ServerCapabilities};
+use crate::capabilities::{AccountCapabilities, CapabilityRegistry, ServerCapabilities};
use crate::*;
// 2: JMAP Session Resource {{{
@@ -50,13 +50,13 @@ pub struct JMAPSession {
impl JMAPSession {
/// Get session from the json
- pub fn from_json(json: &str, parsers: CapabilityParsers) -> Result<Self, serde_json::Error> {
+ pub fn from_json(json: &str, parsers: CapabilityRegistry) -> Result<Self, serde_json::Error> {
let session: ISession = serde_json::from_str(json)?;
Ok(Self::from_intermediate(session, parsers))
}
/// Get session from the ISession object
- pub fn from_intermediate(session: ISession, parsers: CapabilityParsers) -> Self {
+ pub fn from_intermediate(session: ISession, parsers: CapabilityRegistry) -> Self {
let mut accounts = BTreeMap::new();
for acc in session.accounts.keys() {
accounts.insert(acc.clone(), None);
@@ -155,12 +155,63 @@ impl JMAPSession {
// Appendix A: tests {{{
#[cfg(test)]
mod test {
- use crate::JMAPId;
+ use serde::{Deserialize, Serialize};
+ use serde_json::Value;
+
use crate::capabilities::{
- Capability, CapabilityCollection, JMAPCoreCapability, URN_JMAP_CORE,
+ AccountCapabilities, Capability, CapabilityCollection, CapabilityDyn, JMAPCoreCapability,
};
+ use crate::{JArr, JDate, JMAPId, JNumber, JObj, JUTCDate, JUnknown, from_junknown};
use std::assert_matches;
+ enum DeserializeTestCapability {
+ Session(DTC_Session),
+ Account(DTC_Session, DTC_Account),
+ }
+
+ #[derive(Serialize, Deserialize, Clone)]
+ struct DTC_Session {
+ num: JNumber,
+ numArr: JArr<JNumber>,
+ bool: bool,
+ str: String,
+ boolObj: JObj<JMAPId, bool>,
+ date: JDate,
+ }
+
+ #[derive(Serialize, Deserialize, Clone)]
+ struct DTC_Account {
+ #[serde(skip)]
+ account_id: Option<JMAPId>,
+ utc_date: JUTCDate,
+ }
+
+ impl Capability for DeserializeTestCapability {
+ const URN: &str = "urn:xyz:wilkuu:deser_test";
+
+ fn from_object(obj: &crate::JObject) -> Self {
+ Self::Session(from_junknown(obj.clone()).unwrap())
+ }
+
+ fn account_cap(&self, account_id: JMAPId, obj: &crate::JObject) -> Self {
+ let session_cap = (match self {
+ Self::Session(s) => s,
+ Self::Account(s, _) => s,
+ })
+ .clone();
+ let mut acc: DTC_Account = from_junknown(obj.clone()).unwrap();
+ acc.account_id = Some(account_id);
+ Self::Account(session_cap, acc)
+ }
+
+ fn account(&self) -> Option<JMAPId> {
+ match self {
+ Self::Session(_) => None,
+ Self::Account(_, a) => Some(a.account_id.clone().expect("This should always be Some, considering that we create it with the account_id in account_cap")),
+ }
+ }
+ }
+
#[test]
fn intermediate_parse_test() {
let in1 = r#"
@@ -254,6 +305,14 @@ mod test {
"urn:ietf:params:jmap:contacts": {},
"https://example.com/apis/foobar": {
"maxFoosFinangled": 42
+ },
+ "urn:xyz:wilkuu:deser_test": {
+ "num": 12.0,
+ "numArr": [1,2.0,3.0],
+ "bool": true,
+ "str": "string",
+ "boolObj": { "a": true, "b": false },
+ "date": "2026-08-10T10:00:00+02:00"
}
},
"accounts": {
@@ -267,13 +326,17 @@ mod test {
"maxMailboxDepth": 10
},
"urn:ietf:params:jmap:contacts": {
- }
+ },
+ "urn:xyz:wilkuu:deser_test": {
+ "utc_date": "2026-08-10T12:00:00Z"
+ }
}
}
},
"primaryAccounts": {
"urn:ietf:params:jmap:mail": "A13824",
- "urn:ietf:params:jmap:contacts": "A13824"
+ "urn:ietf:params:jmap:contacts": "A13824",
+ "urn:xyz:wilkuu_deser_test": "A13824"
},
"username": "john@example.com",
"apiUrl": "https://jmap.example.com/api/",
@@ -284,7 +347,9 @@ mod test {
}
"#;
- let parsers = crate::session::CapabilityParsers::default();
+ let mut parsers = crate::session::CapabilityRegistry::default();
+ parsers.add_capability::<DeserializeTestCapability>();
+
let mut session = match crate::session::JMAPSession::from_json(in1, parsers) {
Ok(i) => i,
Err(e) => unreachable!("Error in parsing json {:?}", e),
@@ -296,13 +361,13 @@ mod test {
assert!(
session
.capabilities
- .get_capability::<JMAPCoreCapability>(URN_JMAP_CORE)
+ .get_capability::<JMAPCoreCapability>()
.is_some()
);
let account = session.get_account(&crate::JMAPId("A13824".to_string()));
- assert_matches!(account, None);
+ assert!(account.is_none());
let account_opt = session.eval_get_account(&crate::JMAPId("A13824".to_string()));
- assert_matches!(account_opt, Some(_));
+ assert!(account_opt.is_some());
let account_opt = session.eval_get_account_mut(&crate::JMAPId("A13824".to_string()));
let account = account_opt.unwrap();
assert_eq!(
@@ -312,13 +377,29 @@ mod test {
.keys()
.map(Clone::clone)
.collect::<Vec<String>>(),
- vec![URN_JMAP_CORE]
+ vec![JMAPCoreCapability::URN, DeserializeTestCapability::URN]
);
- let cap: &mut JMAPCoreCapability = account
- .capabilities
- .get_capability_mut(URN_JMAP_CORE)
- .unwrap();
+ let cap: &mut JMAPCoreCapability = account.capabilities.get_capability_mut().unwrap();
assert_eq!(cap.account(), Some(JMAPId("A13824".to_string())));
+
+ let deser_cap: &mut DeserializeTestCapability =
+ account.capabilities.get_capability_mut().unwrap();
+ assert_eq!(deser_cap.account(), Some(JMAPId("A13824".to_string())));
+ match deser_cap {
+ DeserializeTestCapability::Session(_) => unreachable!("This should be an account cap"),
+ DeserializeTestCapability::Account(s, _a) => {
+ assert_eq!(s.num, 12.0);
+ assert_eq!(s.numArr, vec![1.0, 2.0, 3.0]);
+ assert!(s.bool);
+ assert_eq!(s.str, "string");
+ assert_eq!(s.boolObj.get(&JMAPId("a".to_string())), Some(true).as_ref());
+ assert_eq!(
+ s.boolObj.get(&JMAPId("b".to_string())),
+ Some(false).as_ref()
+ );
+ // TODO: Test dates
+ }
+ }
}
}
// }}}