use crc_any::CRCu64;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::protocol::{enums::EnumEntryMavCmdFlags, enums::EnumEntryMavCmdParam, Deprecated, Description, Fingerprint};
use crate::utils::{Buildable, Builder};
pub type EnumEntryValue = u32;
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "specta", derive(specta::Type))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EnumEntry {
value: EnumEntryValue,
name: String,
name_stripped: String,
description: Description,
cmd_flags: Option<EnumEntryMavCmdFlags>,
params: Vec<EnumEntryMavCmdParam>,
wip: bool,
deprecated: Option<Deprecated>,
defined_in: String,
}
impl Buildable for EnumEntry {
type Builder = EnumEntryBuilder;
fn to_builder(&self) -> EnumEntryBuilder {
EnumEntryBuilder {
entry: self.clone(),
}
}
}
impl EnumEntry {
pub fn builder() -> EnumEntryBuilder {
EnumEntryBuilder::new()
}
pub fn value(&self) -> EnumEntryValue {
self.value
}
pub fn name(&self) -> &str {
&self.name
}
pub fn name_stripped(&self) -> &str {
&self.name_stripped
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn cmd_flags(&self) -> Option<&EnumEntryMavCmdFlags> {
self.cmd_flags.as_ref()
}
pub fn params(&self) -> &[EnumEntryMavCmdParam] {
self.params.as_ref()
}
pub fn wip(&self) -> bool {
self.wip
}
pub fn deprecated(&self) -> Option<&Deprecated> {
self.deprecated.as_ref()
}
pub fn defined_in(&self) -> &str {
self.defined_in.as_str()
}
pub fn fingerprint(&self) -> Fingerprint {
let mut crc_calculator = CRCu64::crc64();
crc_calculator.digest(format!("{:?} ", self.name).as_bytes());
crc_calculator.digest(&self.value.to_le_bytes());
if let Some(cmd_flags) = &self.cmd_flags {
crc_calculator.digest(format!("{cmd_flags:?} ").as_bytes());
}
if let Some(deprecated) = &self.deprecated {
crc_calculator.digest(format!("{deprecated:?} ").as_bytes());
}
crc_calculator.digest(format!("{:?} ", self.defined_in).as_bytes());
crc_calculator.digest(format!("{:?} ", self.params).as_bytes());
crc_calculator.digest(&[self.wip as u8]);
crc_calculator.get_crc().into()
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EnumEntryBuilder {
entry: EnumEntry,
}
impl Builder for EnumEntryBuilder {
type Buildable = EnumEntry;
fn build(&self) -> EnumEntry {
#[allow(clippy::match_single_binding)]
match self.entry.clone() {
EnumEntry {
value,
name,
name_stripped,
description,
cmd_flags,
params,
wip,
deprecated,
defined_in,
} => EnumEntry {
value,
name,
name_stripped,
description,
cmd_flags,
params,
wip,
deprecated,
defined_in,
},
}
}
}
impl EnumEntryBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn set_value(&mut self, value: EnumEntryValue) -> &mut Self {
self.entry.value = value;
self
}
pub fn set_name(&mut self, name: impl AsRef<str>) -> &mut Self {
self.entry.name = name.as_ref().to_string();
self
}
pub fn set_name_stripped(&mut self, name_stripped: String) -> &mut Self {
self.entry.name_stripped = name_stripped;
self
}
pub fn set_description(&mut self, description: impl AsRef<str>) -> &mut Self {
self.entry.description = Description::new(description);
self
}
pub fn set_cmd_flags(&mut self, cmd_flags: Option<EnumEntryMavCmdFlags>) -> &mut Self {
self.entry.cmd_flags = cmd_flags;
self
}
pub fn set_params(&mut self, params: Vec<EnumEntryMavCmdParam>) -> &mut Self {
self.entry.params = params;
self
}
pub fn set_wip(&mut self, wip: bool) -> &mut Self {
self.entry.wip = wip;
self
}
pub fn set_deprecated(&mut self, deprecated: Option<Deprecated>) -> &mut Self {
self.entry.deprecated = deprecated;
self
}
pub fn set_defined_in(&mut self, defined_in: impl AsRef<str>) -> &mut Self {
self.entry.defined_in = defined_in.as_ref().to_string();
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::{DeprecatedSince, Units};
#[test]
fn enum_entry_builder() {
let entry = EnumEntryBuilder::new()
.set_value(10)
.set_name("name")
.set_description("description")
.set_cmd_flags(Some(
EnumEntryMavCmdFlags::builder()
.set_has_location(Some(true))
.build(),
))
.set_params(vec![EnumEntryMavCmdParam::builder()
.set_units(Some(Units::AmpereHour))
.build()])
.set_wip(true)
.set_deprecated(Some(Deprecated::new(
DeprecatedSince::default(),
"better".to_string(),
)))
.set_defined_in("unknown".to_string())
.build();
assert!(matches!(entry, EnumEntry { .. }));
assert_eq!(entry.value(), 10);
assert_eq!(entry.name(), "name");
assert_eq!(entry.description(), "description");
assert!(entry.cmd_flags().unwrap().has_location().unwrap());
assert_eq!(entry.params().len(), 1);
assert!(matches!(
entry.params().get(0).unwrap().units(),
Some(Units::AmpereHour)
));
assert!(entry.wip());
assert_eq!(entry.deprecated().unwrap().replaced_by(), "better");
assert_eq!(entry.defined_in(), "unknown");
}
}