use std::collections::BTreeMap;
use as_variant::as_variant;
use salvo::prelude::*;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::serde::{JsonValue, RawJsonValue, from_raw_json_value};
#[derive(ToSchema, Clone, Debug)]
pub enum Action {
Notify,
SetTweak(Tweak),
#[doc(hidden)]
#[salvo(schema(skip))]
_Custom(CustomAction),
}
impl Action {
pub fn is_highlight(&self) -> bool {
matches!(self, Action::SetTweak(Tweak::Highlight(true)))
}
pub fn should_notify(&self) -> bool {
matches!(self, Action::Notify)
}
pub fn sound(&self) -> Option<&str> {
as_variant!(self, Action::SetTweak(Tweak::Sound(sound)) => sound)
}
}
#[derive(ToSchema, Deserialize, Serialize, Clone, Debug)]
#[serde(from = "tweak_serde::Tweak", into = "tweak_serde::Tweak")]
pub enum Tweak {
Sound(String),
Highlight(#[serde(default = "crate::serde::default_true")] bool),
Custom {
name: String,
#[salvo(schema(value_type = Object, additional_properties = true))]
value: Box<RawJsonValue>,
},
}
impl<'de> Deserialize<'de> for Action {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = Box::<RawJsonValue>::deserialize(deserializer)?;
let custom: CustomAction = from_raw_json_value(&json)?;
match &custom {
CustomAction::String(s) => match s.as_str() {
"notify" => Ok(Action::Notify),
_ => Ok(Action::_Custom(custom)),
},
CustomAction::Object(o) => {
if o.get("set_tweak").is_some() {
Ok(Action::SetTweak(from_raw_json_value(&json)?))
} else {
Ok(Action::_Custom(custom))
}
}
}
}
}
impl Serialize for Action {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Action::Notify => serializer.serialize_unit_variant("Action", 0, "notify"),
Action::SetTweak(kind) => kind.serialize(serializer),
Action::_Custom(custom) => custom.serialize(serializer),
}
}
}
#[doc(hidden)]
#[allow(unknown_lints, unnameable_types)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CustomAction {
String(String),
Object(BTreeMap<String, JsonValue>),
}
mod tweak_serde {
use serde::{Deserialize, Serialize};
use crate::serde::RawJsonValue;
#[derive(Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub(crate) enum Tweak {
Sound(SoundTweak),
Highlight(HighlightTweak),
Custom {
#[serde(rename = "set_tweak")]
name: String,
value: Box<RawJsonValue>,
},
}
#[derive(Clone, PartialEq, Deserialize, Serialize)]
#[serde(tag = "set_tweak", rename = "sound")]
pub(crate) struct SoundTweak {
value: String,
}
#[derive(Clone, PartialEq, Deserialize, Serialize)]
#[serde(tag = "set_tweak", rename = "highlight")]
pub(crate) struct HighlightTweak {
#[serde(
default = "crate::serde::default_true",
skip_serializing_if = "crate::serde::is_true"
)]
value: bool,
}
impl From<super::Tweak> for Tweak {
fn from(tweak: super::Tweak) -> Self {
use super::Tweak::*;
match tweak {
Sound(value) => Self::Sound(SoundTweak { value }),
Highlight(value) => Self::Highlight(HighlightTweak { value }),
Custom { name, value } => Self::Custom { name, value },
}
}
}
impl From<Tweak> for super::Tweak {
fn from(tweak: Tweak) -> Self {
use Tweak::*;
match tweak {
Sound(SoundTweak { value }) => Self::Sound(value),
Highlight(HighlightTweak { value }) => Self::Highlight(value),
Custom { name, value } => Self::Custom { name, value },
}
}
}
}