158 lines
5.1 KiB
Rust
158 lines
5.1 KiB
Rust
use crate::meme::{Matcher, Meme, MemeIdent};
|
|
use serde::{
|
|
de::{self, Deserializer, MapAccess, Visitor},
|
|
Deserialize,
|
|
};
|
|
use std::path::PathBuf;
|
|
use url::Url;
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct Config {
|
|
pub homeserver_url: Url,
|
|
pub user_id: String,
|
|
pub password: String,
|
|
pub device_name: Option<String>,
|
|
pub sendmeme_command: Option<String>,
|
|
pub memes: Vec<Meme>,
|
|
pub store_path: PathBuf,
|
|
#[serde(default = "default_clear_threshold")]
|
|
pub clear_cache_threshold: u32,
|
|
}
|
|
|
|
fn default_clear_threshold() -> u32 {
|
|
10
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Meme {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
const FIELDS: &[&str] = &["keyword", "id", "randomcat"];
|
|
enum Field {
|
|
Keyword,
|
|
Ident(IdentField),
|
|
Matcher,
|
|
MatchCase,
|
|
}
|
|
|
|
enum IdentField {
|
|
RandomCat,
|
|
Id,
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Field {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct Vis;
|
|
|
|
impl<'de> Visitor<'de> for Vis {
|
|
type Value = Field;
|
|
fn expecting(
|
|
&self,
|
|
fmt: &mut std::fmt::Formatter<'_>,
|
|
) -> Result<(), std::fmt::Error> {
|
|
fmt.write_str("a field for a meme")
|
|
}
|
|
|
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
Ok(match v {
|
|
"keyword" => Field::Keyword,
|
|
"randomcat" => Field::Ident(IdentField::RandomCat),
|
|
"id" => Field::Ident(IdentField::Id),
|
|
"match" => Field::Matcher,
|
|
"match_case" => Field::MatchCase,
|
|
_ => return Err(de::Error::unknown_field(v, FIELDS)),
|
|
})
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_identifier(Vis)
|
|
}
|
|
}
|
|
|
|
struct Vis;
|
|
|
|
impl<'de> Visitor<'de> for Vis {
|
|
type Value = Meme;
|
|
fn expecting(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
fmt.write_str("a meme")
|
|
}
|
|
|
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
|
where
|
|
A: MapAccess<'de>,
|
|
{
|
|
let mut keyword = None;
|
|
let mut ident = None;
|
|
let mut matcher = None;
|
|
let mut match_case = None;
|
|
|
|
while let Some(key) = map.next_key()? {
|
|
match key {
|
|
Field::Keyword => {
|
|
if keyword.is_some() {
|
|
return Err(de::Error::duplicate_field("keyword"));
|
|
}
|
|
|
|
keyword = Some(map.next_value()?);
|
|
},
|
|
|
|
Field::Ident(i) => {
|
|
if ident.is_some() {
|
|
return Err(de::Error::duplicate_field(
|
|
"ident, can only have one.",
|
|
));
|
|
}
|
|
|
|
match i {
|
|
IdentField::Id => {
|
|
ident = Some(MemeIdent::Id(map.next_value()?));
|
|
},
|
|
IdentField::RandomCat => {
|
|
ident = Some(MemeIdent::RandomCat(map.next_value()?));
|
|
},
|
|
}
|
|
},
|
|
|
|
Field::Matcher => {
|
|
if matcher.is_some() {
|
|
return Err(de::Error::duplicate_field("match"));
|
|
}
|
|
|
|
matcher = Some(map.next_value()?);
|
|
},
|
|
|
|
Field::MatchCase => {
|
|
if match_case.is_some() {
|
|
return Err(de::Error::duplicate_field("match"));
|
|
}
|
|
|
|
match_case = Some(map.next_value()?);
|
|
},
|
|
}
|
|
}
|
|
|
|
let keyword = keyword.ok_or_else(|| de::Error::missing_field("keyword"))?;
|
|
let ident = ident.ok_or_else(|| de::Error::missing_field("ident"))?;
|
|
let matcher = matcher.unwrap_or(Matcher::Begins);
|
|
let match_case = match_case.unwrap_or(false);
|
|
|
|
Ok(Meme {
|
|
keyword,
|
|
ident,
|
|
matcher,
|
|
match_case,
|
|
})
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_struct("Meme", FIELDS, Vis)
|
|
}
|
|
}
|