use core::ops::Deref; use serde::{ ser::{SerializeSeq, SerializeStruct}, Serialize, Serializer, }; use crate::{ homeassistant::{AvailabilityTopics, Component, Entity}, Topic, }; #[derive(Serialize)] pub(super) struct AvailabilityTopicItem<'a> { topic: Topic<&'a str>, } struct AvailabilityTopicList<'a, T: Deref, const N: usize> { list: &'a [Topic; N], } impl<'a, const N: usize, T: Deref> AvailabilityTopicList<'a, T, N> { pub(super) fn new(list: &'a [Topic; N]) -> Self { Self { list } } } impl, const N: usize> Serialize for AvailabilityTopicList<'_, T, N> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut serializer = serializer.serialize_seq(Some(N))?; for topic in self.list { serializer.serialize_element(&AvailabilityTopicItem { topic: topic.as_ref(), })?; } serializer.end() } } pub(super) struct List<'a, T: Serialize, const N: usize> { list: &'a [T; N], } impl<'a, T: Serialize, const N: usize> List<'a, T, N> { pub(super) fn new(list: &'a [T; N]) -> Self { Self { list } } } impl Serialize for List<'_, T, N> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let mut serializer = serializer.serialize_seq(Some(N))?; for item in self.list { serializer.serialize_element(item)?; } serializer.end() } } pub(super) struct DiscoverySerializer<'a, const A: usize, C: Component, S: Serializer> { pub(super) discovery: &'a Entity<'a, A, C>, pub(super) inner: S, } impl Serializer for DiscoverySerializer<'_, A, C, S> { type Ok = S::Ok; type Error = S::Error; type SerializeSeq = S::SerializeSeq; type SerializeTuple = S::SerializeTuple; type SerializeTupleStruct = S::SerializeTupleStruct; type SerializeTupleVariant = S::SerializeTupleVariant; type SerializeMap = S::SerializeMap; type SerializeStruct = S::SerializeStruct; type SerializeStructVariant = S::SerializeStructVariant; fn serialize_struct( self, name: &'static str, mut len: usize, ) -> Result { len += 5; if self.discovery.state_topic.is_some() { len += 1; } if self.discovery.command_topic.is_some() { len += 1; } if self.discovery.unique_id.is_some() { len += 1; } if !matches!(self.discovery.availability, AvailabilityTopics::None) { len += 2; } let mut serializer = self.inner.serialize_struct(name, len)?; serializer.serialize_field("dev", &self.discovery.device)?; serializer.serialize_field("o", &self.discovery.origin)?; serializer.serialize_field("p", C::platform())?; serializer.serialize_field("obj_id", self.discovery.object_id)?; serializer.serialize_field("name", self.discovery.name)?; if let Some(t) = self.discovery.state_topic { serializer.serialize_field("stat_t", &t)?; } else { serializer.skip_field("stat_t")?; } if let Some(t) = self.discovery.command_topic { serializer.serialize_field("cmd_t", &t)?; } else { serializer.skip_field("cmd_t")?; } match &self.discovery.availability { AvailabilityTopics::None => { serializer.skip_field("avty")?; serializer.skip_field("avty_mode")?; } AvailabilityTopics::All(topics) => { serializer.serialize_field("avty_mode", "all")?; serializer.serialize_field("avty", &AvailabilityTopicList::new(topics))?; } AvailabilityTopics::Any(topics) => { serializer.serialize_field("avty_mode", "any")?; serializer.serialize_field("avty", &AvailabilityTopicList::new(topics))?; } AvailabilityTopics::Latest(topics) => { serializer.serialize_field("avty_mode", "latest")?; serializer.serialize_field("avty", &AvailabilityTopicList::new(topics))?; } } if let Some(v) = self.discovery.unique_id { serializer.serialize_field("uniq_id", v)?; } else { serializer.skip_field("uniq_id")?; } Ok(serializer) } fn serialize_bool(self, _: bool) -> Result { unimplemented!() } fn serialize_i8(self, _: i8) -> Result { unimplemented!() } fn serialize_i16(self, _: i16) -> Result { unimplemented!() } fn serialize_i32(self, _: i32) -> Result { unimplemented!() } fn serialize_i64(self, _: i64) -> Result { unimplemented!() } fn serialize_u8(self, _: u8) -> Result { unimplemented!() } fn serialize_u16(self, _: u16) -> Result { unimplemented!() } fn serialize_u32(self, _: u32) -> Result { unimplemented!() } fn serialize_u64(self, _: u64) -> Result { unimplemented!() } fn serialize_f32(self, _: f32) -> Result { unimplemented!() } fn serialize_f64(self, _: f64) -> Result { unimplemented!() } fn serialize_char(self, _: char) -> Result { unimplemented!() } fn serialize_str(self, _: &str) -> Result { unimplemented!() } fn serialize_bytes(self, _: &[u8]) -> Result { unimplemented!() } fn serialize_none(self) -> Result { unimplemented!() } fn serialize_some(self, _: &T) -> Result where T: ?Sized + Serialize, { unimplemented!() } fn serialize_unit(self) -> Result { unimplemented!() } fn serialize_unit_struct(self, _: &'static str) -> Result { unimplemented!() } fn serialize_unit_variant( self, _: &'static str, _: u32, _: &'static str, ) -> Result { unimplemented!() } fn serialize_newtype_struct(self, _: &'static str, _: &T) -> Result where T: ?Sized + Serialize, { unimplemented!() } fn serialize_newtype_variant( self, _: &'static str, _: u32, _: &'static str, _: &T, ) -> Result where T: ?Sized + Serialize, { unimplemented!() } fn serialize_seq(self, _: Option) -> Result { unimplemented!() } fn serialize_tuple(self, _: usize) -> Result { unimplemented!() } fn serialize_tuple_struct( self, _: &'static str, _: usize, ) -> Result { unimplemented!() } fn serialize_tuple_variant( self, _: &'static str, _: u32, _: &'static str, _: usize, ) -> Result { unimplemented!() } fn serialize_map(self, _: Option) -> Result { unimplemented!() } fn serialize_struct_variant( self, _: &'static str, _: u32, _: &'static str, _: usize, ) -> Result { unimplemented!() } fn serialize_i128(self, _: i128) -> Result { unimplemented!() } fn serialize_u128(self, _: u128) -> Result { unimplemented!() } fn collect_seq(self, _: I) -> Result where I: IntoIterator, ::Item: Serialize, { unimplemented!() } fn collect_map(self, _: I) -> Result where K: Serialize, V: Serialize, I: IntoIterator, { unimplemented!() } fn collect_str(self, _: &T) -> Result where T: ?Sized + core::fmt::Display, { unimplemented!() } fn is_human_readable(&self) -> bool { unimplemented!() } }