enet_proto/res/
proj.rs

1use derive_more::IsVariant;
2use enum_kinds::EnumKind;
3use serde::{
4  de::{Unexpected, Visitor},
5  Deserialize, Deserializer,
6};
7use std::fmt;
8
9pub trait EnetItem {
10  fn number(&self) -> u32;
11  fn name(&self) -> &str;
12  fn is_subscribable(&self) -> bool;
13}
14
15macro_rules! impl_item {
16  ($ty:ty : $id:ident => $sub:expr) => {
17    impl EnetItem for $ty {
18      #[inline]
19      fn number(&self) -> u32 {
20        self.number
21      }
22
23      #[inline]
24      fn name(&self) -> &str {
25        &self.name
26      }
27
28      #[inline]
29      fn is_subscribable(&self) -> bool {
30        let $id = self;
31        $sub
32      }
33    }
34  };
35
36  ($ty:ty => $sub:literal) => {
37    impl_item!($ty : _v => $sub);
38  }
39}
40
41// TODO: https://github.com/serde-rs/serde/pull/1902
42#[derive(Debug, Deserialize, EnumKind, IsVariant)]
43#[serde(tag = "TYPE", rename_all = "UPPERCASE")]
44#[enum_kind(ProjectItemKind)]
45pub enum ProjectItem {
46  #[serde(alias = "Scene")]
47  Scene(ProjectScene),
48  Binaer(ProjectBinaer),
49  Dimmer(ProjectDimmer),
50  Jalousie(ProjectJalousie),
51  None(ProjectNone),
52}
53
54impl ProjectItem {
55  #[inline]
56  pub fn kind(&self) -> ProjectItemKind {
57    ProjectItemKind::from(self)
58  }
59}
60
61impl EnetItem for ProjectItem {
62  fn number(&self) -> u32 {
63    match self {
64      ProjectItem::Scene(v) => v.number(),
65      ProjectItem::Binaer(v) => v.number(),
66      ProjectItem::Dimmer(v) => v.number(),
67      ProjectItem::Jalousie(v) => v.number(),
68      ProjectItem::None(v) => v.number(),
69    }
70  }
71
72  fn name(&self) -> &str {
73    match self {
74      ProjectItem::Scene(v) => v.name(),
75      ProjectItem::Binaer(v) => v.name(),
76      ProjectItem::Dimmer(v) => v.name(),
77      ProjectItem::Jalousie(v) => v.name(),
78      ProjectItem::None(v) => v.name(),
79    }
80  }
81
82  fn is_subscribable(&self) -> bool {
83    match self {
84      ProjectItem::Scene(v) => v.is_subscribable(),
85      ProjectItem::Binaer(v) => v.is_subscribable(),
86      ProjectItem::Dimmer(v) => v.is_subscribable(),
87      ProjectItem::Jalousie(v) => v.is_subscribable(),
88      ProjectItem::None(v) => v.is_subscribable(),
89    }
90  }
91}
92
93#[derive(Debug, Deserialize)]
94#[serde(rename_all = "UPPERCASE")]
95pub struct ProjectScene {
96  pub number: u32,
97  pub name: String,
98  pub dimmable: bool,
99}
100impl_item!(ProjectScene => false);
101
102#[derive(Debug, Deserialize)]
103#[serde(rename_all = "UPPERCASE")]
104pub struct ProjectBinaer {
105  pub number: u32,
106  pub name: String,
107  #[serde(default = "get_true", deserialize_with = "deserialize_programmable")]
108  pub programmable: bool,
109}
110impl_item!(ProjectBinaer : v => v.programmable);
111
112#[derive(Debug, Deserialize)]
113#[serde(rename_all = "UPPERCASE")]
114pub struct ProjectDimmer {
115  pub number: u32,
116  pub name: String,
117}
118impl_item!(ProjectDimmer => true);
119
120#[derive(Debug, Deserialize)]
121#[serde(rename_all = "UPPERCASE")]
122pub struct ProjectJalousie {
123  pub number: u32,
124  pub name: String,
125}
126impl_item!(ProjectJalousie => true);
127
128#[derive(Debug, Deserialize)]
129#[serde(rename_all = "UPPERCASE")]
130pub struct ProjectNone {
131  pub number: u32,
132  pub name: String,
133}
134impl_item!(ProjectNone => false);
135
136#[derive(Debug, Deserialize)]
137#[serde(rename_all = "UPPERCASE")]
138pub struct ProjectList {
139  pub number: u32,
140  pub name: String,
141  #[serde(default)]
142  pub items_order: Vec<u32>,
143  pub visible: bool,
144}
145
146struct ProgrammableVisitor;
147
148impl<'de> Visitor<'de> for ProgrammableVisitor {
149  type Value = bool;
150
151  fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
152    formatter.write_str("bool")
153  }
154
155  #[inline]
156  fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
157  where
158    E: serde::de::Error,
159  {
160    Ok(v)
161  }
162
163  #[inline]
164  fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
165  where
166    E: serde::de::Error,
167  {
168    match v {
169      "false" | "FALSE" => Ok(false),
170      "true" | "TRUE" => Ok(true),
171      _ => Err(E::invalid_value(Unexpected::Str(v), &self)),
172    }
173  }
174}
175
176fn deserialize_programmable<'de, D>(serializer: D) -> Result<bool, D::Error>
177where
178  D: Deserializer<'de>,
179{
180  serializer.deserialize_any(ProgrammableVisitor)
181}
182
183#[inline]
184fn get_true() -> bool {
185  true
186}