use crate::{Error, MAX_MESSAGES, Message, Result, compat::Vec};
#[cfg(feature = "heapless")]
use heapless::index_map::FnvIndexMap;
#[derive(Debug, Clone, PartialEq)]
pub struct Messages {
messages: Vec<Message, { MAX_MESSAGES }>,
#[cfg(feature = "heapless")]
id_index: Option<FnvIndexMap<u32, usize, { MAX_MESSAGES }>>,
#[cfg(all(feature = "alloc", not(feature = "heapless")))]
sorted_indices: Option<alloc::vec::Vec<(u32, usize)>>, }
impl Messages {
#[allow(dead_code)]
pub(crate) fn new(messages: &[Message]) -> Result<Self> {
if let Some(err) = crate::error::check_max_limit(
messages.len(),
MAX_MESSAGES,
Error::message(Error::NODES_TOO_MANY),
) {
return Err(err);
}
let messages_vec: Vec<Message, { MAX_MESSAGES }> = messages.iter().cloned().collect();
Self::from_vec(messages_vec)
}
pub(crate) fn from_vec(messages: Vec<Message, { MAX_MESSAGES }>) -> Result<Self> {
if let Some(err) = crate::error::check_max_limit(
messages.len(),
MAX_MESSAGES,
Error::message(Error::NODES_TOO_MANY),
) {
return Err(err);
}
#[cfg(feature = "heapless")]
let id_index = Self::build_heapless_index(&messages);
#[cfg(all(feature = "alloc", not(feature = "heapless")))]
let sorted_indices = Self::build_sorted_index(&messages);
Ok(Self {
messages,
#[cfg(feature = "heapless")]
id_index,
#[cfg(all(feature = "alloc", not(feature = "heapless")))]
sorted_indices,
})
}
#[cfg(feature = "heapless")]
fn build_heapless_index(
messages: &[Message],
) -> Option<FnvIndexMap<u32, usize, { MAX_MESSAGES }>> {
let mut index = FnvIndexMap::new();
for (idx, msg) in messages.iter().enumerate() {
if index.insert(msg.id_with_flag(), idx).is_err() {
return None;
}
}
Some(index)
}
#[cfg(all(feature = "alloc", not(feature = "heapless")))]
fn build_sorted_index(messages: &[Message]) -> Option<alloc::vec::Vec<(u32, usize)>> {
let mut indices = alloc::vec::Vec::with_capacity(messages.len());
for (idx, msg) in messages.iter().enumerate() {
indices.push((msg.id_with_flag(), idx));
}
indices.sort_by_key(|&(id, _)| id);
Some(indices)
}
#[inline]
#[must_use = "iterator is lazy and does nothing unless consumed"]
pub fn iter(&self) -> impl Iterator<Item = &Message> + '_ {
self.messages.iter()
}
#[inline]
#[must_use = "return value should be used"]
pub fn len(&self) -> usize {
self.messages.len()
}
#[inline]
#[must_use = "return value should be used"]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use = "return value should be used"]
pub fn at(&self, index: usize) -> Option<&Message> {
self.messages.get(index)
}
#[must_use = "return value should be used"]
pub fn find(&self, name: &str) -> Option<&Message> {
self.iter().find(|m| m.name() == name)
}
#[inline]
#[must_use = "return value should be used"]
pub fn find_by_id(&self, id: u32) -> Option<&Message> {
#[cfg(feature = "heapless")]
{
if let Some(ref index) = self.id_index {
if let Some(&idx) = index.get(&id) {
return self.messages.get(idx);
}
return None;
}
}
#[cfg(all(feature = "alloc", not(feature = "heapless")))]
{
if let Some(ref sorted) = self.sorted_indices {
if let Ok(pos) = sorted.binary_search_by_key(&id, |&(msg_id, _)| msg_id) {
let &(_, idx) = sorted.get(pos)?;
return self.messages.get(idx);
}
return None;
}
}
self.messages.iter().find(|m| m.id_with_flag() == id)
}
}