use alloc::string::String;
use alloc::vec::Vec;
use super::{FieldDescriptor, FieldType, MessageDescriptor};
use crate::error::{MavlinkError, Result};
use crate::frame::MAX_PAYLOAD;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OwnedFieldDescriptor {
pub name: String,
pub ty: FieldType,
pub array_len: u8,
pub extension: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OwnedMessageDescriptor {
id: u32,
name: String,
crc_extra: u8,
fields: Vec<OwnedFieldDescriptor>,
}
impl OwnedMessageDescriptor {
pub fn from_descriptor(descriptor: &MessageDescriptor<'_>) -> Self {
Self {
id: descriptor.id,
name: String::from(descriptor.name),
crc_extra: descriptor.crc_extra,
fields: descriptor
.fields
.iter()
.map(|field| OwnedFieldDescriptor {
name: String::from(field.name),
ty: field.ty,
array_len: field.array_len,
extension: field.extension,
})
.collect(),
}
}
pub fn id(&self) -> u32 {
self.id
}
pub fn name(&self) -> &str {
&self.name
}
pub fn crc_extra(&self) -> u8 {
self.crc_extra
}
pub fn fields(&self) -> &[OwnedFieldDescriptor] {
&self.fields
}
pub fn with_descriptor<R>(&self, query: impl FnOnce(&MessageDescriptor<'_>) -> R) -> R {
let fields: Vec<FieldDescriptor<'_>> = self
.fields
.iter()
.map(|field| FieldDescriptor {
name: &field.name,
ty: field.ty,
array_len: field.array_len,
extension: field.extension,
})
.collect();
query(&MessageDescriptor {
id: self.id,
name: &self.name,
crc_extra: self.crc_extra,
fields: &fields,
})
}
}
#[derive(Clone, Debug, Default)]
pub struct MessageDescriptorBuilder {
id: u32,
name: String,
fields: Vec<OwnedFieldDescriptor>,
}
impl MessageDescriptorBuilder {
pub fn new(id: u32, name: impl Into<String>) -> Self {
Self {
id,
name: name.into(),
fields: Vec::new(),
}
}
pub fn field(mut self, name: impl Into<String>, ty: FieldType, array_len: u8) -> Self {
self.fields.push(OwnedFieldDescriptor {
name: name.into(),
ty,
array_len,
extension: false,
});
self
}
pub fn extension(mut self, name: impl Into<String>, ty: FieldType, array_len: u8) -> Self {
self.fields.push(OwnedFieldDescriptor {
name: name.into(),
ty,
array_len,
extension: true,
});
self
}
pub fn build(self) -> Result<OwnedMessageDescriptor> {
let Self {
id,
name,
mut fields,
} = self;
for (index, field) in fields.iter().enumerate() {
if fields[index + 1..]
.iter()
.any(|other| other.name == field.name)
{
return Err(MavlinkError::DuplicateField);
}
}
let total: usize = fields
.iter()
.map(|field| {
let elements = if field.array_len == 0 {
1
} else {
field.array_len as usize
};
elements * field.ty.size()
})
.sum();
if total > MAX_PAYLOAD {
return Err(MavlinkError::PayloadTooLong);
}
let base = fields
.iter()
.position(|field| field.extension)
.unwrap_or(fields.len());
fields[..base].sort_by_key(|field| core::cmp::Reverse(field.ty.size()));
let crc_extra = crate::crc::crc_extra_of(
&name,
fields
.iter()
.filter(|field| !field.extension)
.map(|field| (field.ty.wire_name(), field.name.as_str(), field.array_len)),
);
Ok(OwnedMessageDescriptor {
id,
name,
crc_extra,
fields,
})
}
}
#[derive(Clone, Debug, Default)]
pub struct OwnedDialect {
messages: Vec<OwnedMessageDescriptor>,
}
impl OwnedDialect {
pub fn new() -> Self {
Self {
messages: Vec::new(),
}
}
pub fn insert(&mut self, descriptor: OwnedMessageDescriptor) {
let id = descriptor.id();
self.messages.retain(|held| held.id() != id);
self.messages.push(descriptor);
}
pub fn get(&self, msgid: u32) -> Option<&OwnedMessageDescriptor> {
self.messages.iter().find(|held| held.id() == msgid)
}
pub fn by_name(&self, name: &str) -> Option<&OwnedMessageDescriptor> {
self.messages.iter().find(|held| held.name() == name)
}
pub fn crc_extra(&self, msgid: u32) -> Option<u8> {
self.get(msgid)
.map(OwnedMessageDescriptor::crc_extra)
.or_else(|| crate::dialect::crc_extra(msgid))
}
pub fn len(&self) -> usize {
self.messages.len()
}
pub fn is_empty(&self) -> bool {
self.messages.is_empty()
}
}