use crate::description::util::IterUtil;
use crate::dmx_mode::DmxMode;
use crate::fixture_type::FixtureType;
use crate::validation::{ValidationError, ValidationErrorType, ValidationObject, ValidationResult};
use crate::values::{Name, Node};
use serde::de::{Error, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::Formatter;
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Protocols {
#[serde(rename = "FTRDM", skip_serializing_if = "Option::is_none")]
pub rdm: Option<Rdm>,
#[serde(rename = "Art-Net", skip_serializing_if = "Option::is_none")]
pub art_net: Option<ArtNet>,
#[serde(rename = "sACN", skip_serializing_if = "Option::is_none")]
pub sacn: Option<Sacn>,
#[serde(rename = "PosiStageNet", skip_serializing_if = "Option::is_none")]
pub posi_stage_net: Option<PosiStageNet>,
#[serde(rename = "OpenSoundControl", skip_serializing_if = "Option::is_none")]
pub open_sound_control: Option<OpenSoundControl>,
#[serde(rename = "CITP", skip_serializing_if = "Option::is_none")]
pub citp: Option<Citp>,
}
impl Protocols {
pub fn validate(&self, parent_fixture_type: &FixtureType, result: &mut ValidationResult) {
if let Some(rdm) = &self.rdm {
rdm.validate(parent_fixture_type, result);
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Rdm {
#[serde(
rename = "@ManufacturerID",
serialize_with = "serialize_hex",
deserialize_with = "deserialize_hex"
)]
pub manufacturer_id: u32,
#[serde(
rename = "@DeviceModelID",
serialize_with = "serialize_hex",
deserialize_with = "deserialize_hex"
)]
pub device_model_id: u32,
#[serde(
rename = "SoftwareVersionID",
skip_serializing_if = "Vec::is_empty",
default
)]
pub software_versions: Vec<SoftwareVersion>,
}
impl Rdm {
pub fn validate(&self, parent_fixture_type: &FixtureType, result: &mut ValidationResult) {
let duplicate_software_version = self
.software_versions
.iter()
.map(|version| version.value)
.find_duplicate();
if let Some(version) = duplicate_software_version {
result.errors.push(ValidationError::new(
ValidationObject::SoftwareVersion,
format!("{:#x}", version),
ValidationErrorType::DuplicateName,
));
}
for version in &self.software_versions {
version.validate(parent_fixture_type, result);
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SoftwareVersion {
#[serde(
rename = "@Value",
serialize_with = "serialize_hex",
deserialize_with = "deserialize_hex"
)]
pub value: u32,
#[serde(
rename = "DMXPersonality",
skip_serializing_if = "Vec::is_empty",
default
)]
pub personalities: Vec<DmxPersonality>,
}
impl SoftwareVersion {
pub fn validate(&self, parent_fixture_type: &FixtureType, result: &mut ValidationResult) {
let duplicate_personality = self
.personalities
.iter()
.map(|personality| personality.value)
.find_duplicate();
if let Some(personality) = duplicate_personality {
result.errors.push(ValidationError::new(
ValidationObject::DmxPersonality,
format!("{:#x}", personality),
ValidationErrorType::DuplicateName,
));
}
for personality in &self.personalities {
personality.validate(parent_fixture_type, result);
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DmxPersonality {
#[serde(
rename = "@Value",
serialize_with = "serialize_hex",
deserialize_with = "deserialize_hex"
)]
pub value: u32,
#[serde(rename = "@DMXMode")]
pub dmx_mode: Name,
}
impl DmxPersonality {
pub fn dmx_mode<'s>(&self, parent_fixture_type: &'s FixtureType) -> Option<&'s DmxMode> {
parent_fixture_type.dmx_mode(&self.dmx_mode)
}
pub fn validate(&self, parent_fixture_type: &FixtureType, result: &mut ValidationResult) {
if self.dmx_mode(parent_fixture_type).is_none() {
result.errors.push(ValidationError::new(
ValidationObject::DmxPersonality,
format!("{:#x}", self.value),
ValidationErrorType::LinkNotFound(
ValidationObject::DmxMode,
Node::new([self.dmx_mode.clone()]),
),
));
}
}
}
fn serialize_hex<S>(value: &u32, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{value:#x}"))
}
fn deserialize_hex<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
D: Deserializer<'de>,
{
struct HexVisitor;
impl<'de> Visitor<'de> for HexVisitor {
type Value = u32;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a hexadecimal integer in the format 0xAAAA")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
let Some(hex) = v.strip_prefix("0x") else {
return Err(E::invalid_value(Unexpected::Str(v), &self));
};
u32::from_str_radix(hex, 16).map_err(|_| E::invalid_value(Unexpected::Str(v), &self))
}
}
deserializer.deserialize_str(HexVisitor)
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ArtNet {
#[serde(rename = "Map", skip_serializing_if = "Vec::is_empty", default)]
pub maps: Vec<ProtocolMap>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Sacn {
#[serde(rename = "Map", skip_serializing_if = "Vec::is_empty", default)]
pub maps: Vec<ProtocolMap>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ProtocolMap {
#[serde(rename = "@Key")]
pub key: u32,
#[serde(rename = "@Value")]
pub value: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PosiStageNet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct OpenSoundControl;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Citp;