diff --git a/src/push.rs b/src/push.rs index 94877976..f98642c2 100644 --- a/src/push.rs +++ b/src/push.rs @@ -2,11 +2,34 @@ //! //! [push]: https://matrix.org/docs/spec/client_server/r0.6.0#id89 -use serde::{Deserialize, Serialize}; +use std::fmt::{self, Formatter}; + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_json::value::RawValue as RawJsonValue; mod tweak_serde; +/// This represents the different actions that should be taken when a rule is matched, and +/// controls how notifications are delivered to the client. +/// +/// See https://matrix.org/docs/spec/client_server/r0.6.0#actions for details. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub enum Action { + /// Causes matching events to generate a notification. + Notify, + + /// Prevents matching events from generating a notification. + DontNotify, + + /// Behaves like notify but homeservers may choose to coalesce multiple events + /// into a single notification. + Coalesce, + + /// Sets an entry in the 'tweaks' dictionary sent to the push gateway. + SetTweak(Tweak), +} + /// The `set_tweak` action. #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(from = "tweak_serde::Tweak", into = "tweak_serde::Tweak")] @@ -35,3 +58,62 @@ pub enum Tweak { value: Box, }, } + +impl<'de> Deserialize<'de> for Action { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::{MapAccess, Visitor}; + + struct ActionVisitor; + impl<'de> Visitor<'de> for ActionVisitor { + type Value = Action; + + fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result { + write!(formatter, "a valid action object") + } + + /// Match a simple action type + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match v { + "notify" => Ok(Action::Notify), + "dont_notify" => Ok(Action::DontNotify), + "coalesce" => Ok(Action::Coalesce), + s => Err(E::unknown_variant( + &s, + &["notify", "dont_notify", "coalesce"], + )), + } + } + + /// Match the more complex set_tweaks action object as a key-value map + fn visit_map(self, map: A) -> Result + where + A: MapAccess<'de>, + { + Tweak::deserialize(serde::de::value::MapAccessDeserializer::new(map)) + .map(Action::SetTweak) + } + } + + deserializer.deserialize_any(ActionVisitor) + } +} + +impl Serialize for Action { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Action::Notify => serializer.serialize_unit_variant("Action", 0, "notify"), + Action::DontNotify => serializer.serialize_unit_variant("Action", 1, "dont_notify"), + Action::Coalesce => serializer.serialize_unit_variant("Action", 2, "coalesce"), + Action::SetTweak(kind) => kind.serialize(serializer), + } + } +}