use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[allow(clippy::struct_excessive_bools)]
pub struct Perms {
pub read: bool,
pub write: bool,
pub events: bool,
pub additional_authorization: bool,
pub timed_write: bool,
pub hidden: bool,
pub write_response: bool,
}
impl Perms {
fn codes(self) -> Vec<&'static str> {
let mut v = Vec::new();
if self.read {
v.push("pr");
}
if self.write {
v.push("pw");
}
if self.events {
v.push("ev");
}
if self.additional_authorization {
v.push("aa");
}
if self.timed_write {
v.push("tw");
}
if self.hidden {
v.push("hd");
}
if self.write_response {
v.push("wr");
}
v
}
}
impl Serialize for Perms {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
let codes = self.codes();
let mut seq = s.serialize_seq(Some(codes.len()))?;
for c in codes {
seq.serialize_element(c)?;
}
seq.end()
}
}
impl<'de> Deserialize<'de> for Perms {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
struct PermsVisitor;
impl<'de> Visitor<'de> for PermsVisitor {
type Value = Perms;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("an array of HAP permission codes")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Perms, A::Error> {
let mut p = Perms::default();
while let Some(code) = seq.next_element::<String>()? {
match code.as_str() {
"pr" => p.read = true,
"pw" => p.write = true,
"ev" => p.events = true,
"aa" => p.additional_authorization = true,
"tw" => p.timed_write = true,
"hd" => p.hidden = true,
"wr" => p.write_response = true,
_ => {}
}
}
Ok(p)
}
}
d.deserialize_seq(PermsVisitor)
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn parses_pr_pw_ev() {
let p: Perms = serde_json::from_str(r#"["pr","pw","ev"]"#).unwrap();
assert!(p.read && p.write && p.events);
assert!(!p.hidden);
}
#[test]
fn serializes_in_canonical_order() {
let p = Perms {
read: true,
events: true,
..Perms::default()
};
assert_eq!(serde_json::to_string(&p).unwrap(), r#"["pr","ev"]"#);
}
#[test]
fn ignores_unknown_codes() {
let p: Perms = serde_json::from_str(r#"["pr","xx"]"#).unwrap();
assert!(p.read);
}
}