use jiff::civil::DateTime; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use serde_json::{Number, Value}; use std::any::Any; use std::collections::BTreeMap; use std::collections::btree_map::{Iter, Keys}; use std::hash::Hash; // 1.1 Notational Conventions {{{ // Types // *, unknown value #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(untagged)] pub enum JUnknown { Object(BTreeMap), Array(Vec), Uint(JUint), Int(JInt), Number(JNumber), JDate(JDate), String(String), Id(JMAPId), Bool(bool), Null, // Json(serde_json::Value) } /// Implement from for serde_json::Value so that we can use serde to covert unknown to actual types /// :3 impl From for Value { fn from(value: JUnknown) -> Self { match value { JUnknown::Number(n) => { Value::Number(serde_json::Number::from_f64(n).unwrap_or(Number::from(999))) } JUnknown::Int(n) => Value::Number(serde_json::Number::from(n)), JUnknown::Uint(n) => Value::Number(serde_json::Number::from(n)), JUnknown::JDate(jdate) => Value::String(jdate.0.to_string()), JUnknown::Object(btree_map) => { let mut map = serde_json::map::Map::with_capacity(btree_map.len()); for (k, v) in btree_map.into_iter() { let val = v.into(); map.insert(k, val); } Value::Object(map) } JUnknown::Array(junknowns) => { Value::Array(junknowns.into_iter().map(|x| x.into()).collect()) } JUnknown::String(x) => Value::String(x), JUnknown::Id(jmapid) => Value::String(jmapid.0), JUnknown::Bool(bool) => Value::Bool(bool), JUnknown::Null => Value::Null, } } } // JSON String type // pub type JString = String; // JSON Number type pub type JNumber = f64; // JSON Boolean type // pub type JBool = bool; // A[B] is a JSON object where keys are all of type A and values type B; pub type JObj where A: Serialize, B: Serialize, A: DeserializeOwned, B: DeserializeOwned, = BTreeMap; pub type JObject = JObj; /// A[] is an array of type A pub type JArr where A: Serialize, A: DeserializeOwned, = Vec; //}}} // 1.2 The ID data type {{{ /// The ID data type /// Where Id is given as a data type, it means a String of at least 1 and a maximum of 255 octets in size, /// and it MUST only contain characters from the "URL and Filename Safe" base64 alphabet, as defined in Section 5 of [RFC4648], /// excluding the pad character (=). This means the allowed characters are the ASCII alphanumeric characters (A-Za-z0-9), hyphen (-), and underscore (_). /// TODO: Add the restrictions above #[derive(Serialize, Deserialize, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)] pub struct JMAPId(String); //}}} // 1.3 Int and UnsignedInt {{{ type JInt = i64; type JUint = u64; // }}} // 1.4 Date and UTCDate data Types {{{ /// Where date is given a type, it meanse a string in date-time format [RFC3339]. /// TODO: To ensure a normalized form, the time-setfrac MUST always be ommitted if zero, and any /// letters in the string (eg. "T" and "Z") must be uppercase. #[derive(Deserialize, Serialize, Clone, Debug)] pub struct JDate(DateTime); impl JDate { /// Convert from a JUTCDate type to system time pub fn from_utcdate(date: JDate) -> Self { // FIXME: unwrap Self( date.0 .to_zoned(jiff::tz::TimeZone::system()) .unwrap() .datetime(), ) } /// Parse from a string pub fn from_string(str: &str) -> Result { Ok(Self(str.parse()?)) } /// Get the inner date for reading purposes pub fn get_date(&self) -> &DateTime { &self.0 } /// Convert from jiff datetime pub fn from_datetime(datetime: DateTime) -> Self { Self(datetime) } } /// Where UTCDate is given as a type, it means a Date where the time-offset component MUST be Z (i.e., it must be in UTC time). For example, 2014-10-30T06:12:00Z #[derive(Deserialize, Serialize, Clone, Debug)] pub struct JUTCDate(DateTime); impl JUTCDate { /// Convert from a JDate type pub fn from_date(date: JDate) -> Self { // FIXME: unwrap Self(date.0.to_zoned(jiff::tz::TimeZone::UTC).unwrap().datetime()) } /// Parse from a string pub fn from_string(str: &str) -> Result { Ok(Self( str.parse::()? .to_zoned(jiff::tz::TimeZone::UTC) .datetime(), )) } /// Get the inner date for reading purposes pub fn get_date(&self) -> &DateTime { &self.0 } /// Convert from jiff datetime pub fn from_datetime(datetime: DateTime) -> Self { // FIXME: unwrap Self( datetime .to_zoned(jiff::tz::TimeZone::UTC) .unwrap() .datetime(), ) } } //}}} pub mod capabilities; /// 2 JMAP Session resource pub mod session;