use crate::descriptors::{descriptor_body, write_descriptor_header};
use crate::error::{Error, Result};
use alloc::vec::Vec;
use broadcast_common::{Parse, Serialize};
pub const TAG: u8 = 0x12;
const HEADER_LEN: usize = 2;
const LEN_FIELD: usize = 1;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct ProviderExport<'a> {
pub provider_name: &'a [u8],
pub provider_class_name: &'a [u8],
}
impl<'a> ProviderExport<'a> {
#[must_use]
pub const fn new(provider_name: &'a [u8], provider_class_name: &'a [u8]) -> Self {
Self {
provider_name,
provider_class_name,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct ProviderExportDescriptor<'a> {
pub providers: Vec<ProviderExport<'a>>,
}
impl<'a> ProviderExportDescriptor<'a> {
#[must_use]
pub fn new(providers: Vec<ProviderExport<'a>>) -> Self {
Self { providers }
}
}
fn take_field<'a>(rest: &'a [u8], reason: &'static str) -> Result<(&'a [u8], &'a [u8])> {
let (&n, tail) = rest
.split_first()
.ok_or(Error::InvalidDescriptor { tag: TAG, reason })?;
let n = usize::from(n);
if tail.len() < n {
return Err(Error::InvalidDescriptor { tag: TAG, reason });
}
Ok(tail.split_at(n))
}
impl<'a> Parse<'a> for ProviderExportDescriptor<'a> {
type Error = crate::error::Error;
fn parse(bytes: &'a [u8]) -> Result<Self> {
let mut rest = descriptor_body(
bytes,
TAG,
"ProviderExportDescriptor",
"unexpected tag for provider_export_descriptor",
)?;
let mut providers = Vec::new();
while !rest.is_empty() {
let (provider_name, tail) = take_field(
rest,
"provider_export_descriptor provider_name overruns body",
)?;
let (provider_class_name, tail) = take_field(
tail,
"provider_export_descriptor provider_class_name missing or overruns body",
)?;
providers.push(ProviderExport {
provider_name,
provider_class_name,
});
rest = tail;
}
Ok(Self { providers })
}
}
impl Serialize for ProviderExportDescriptor<'_> {
type Error = crate::error::Error;
fn serialized_len(&self) -> usize {
HEADER_LEN
+ self
.providers
.iter()
.map(|p| {
LEN_FIELD + p.provider_name.len() + LEN_FIELD + p.provider_class_name.len()
})
.sum::<usize>()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
let len = self.serialized_len();
if buf.len() < len {
return Err(Error::OutputBufferTooSmall {
need: len,
have: buf.len(),
});
}
write_descriptor_header(buf, TAG, len - HEADER_LEN)?;
let mut pos = HEADER_LEN;
for p in &self.providers {
for (field, what) in [
(p.provider_name, "provider_name_length"),
(p.provider_class_name, "provider_class_name_length"),
] {
buf[pos] = broadcast_common::len::fit_u8(field.len(), what)?;
pos += LEN_FIELD;
buf[pos..pos + field.len()].copy_from_slice(field);
pos += field.len();
}
}
Ok(len)
}
}
impl<'a> crate::traits::DescriptorDef<'a> for ProviderExportDescriptor<'a> {
const TAG: u8 = TAG;
const NAME: &'static str = "PROVIDER_EXPORT";
}
#[cfg(test)]
mod tests {
use super::*;
const BYTES: [u8; 16] = [
TAG, 14, 3, b'a', b'b', b'c', 5, b'C', b'l', b'a', b's', b's', 0, 2, b'p', b'Q',
];
#[test]
fn parse_and_round_trip() {
let d = ProviderExportDescriptor::parse(&BYTES).unwrap();
assert_eq!(d.providers.len(), 2);
assert_eq!(d.providers[0].provider_name, b"abc");
assert_eq!(d.providers[0].provider_class_name, b"Class");
assert_eq!(d.providers[1].provider_name, b"");
assert_eq!(d.providers[1].provider_class_name, b"pQ");
let mut out = vec![0u8; d.serialized_len()];
d.serialize_into(&mut out).unwrap();
assert_eq!(out, BYTES);
}
#[test]
fn empty_loop_and_errors() {
assert!(
ProviderExportDescriptor::parse(&[TAG, 0])
.unwrap()
.providers
.is_empty()
);
assert!(ProviderExportDescriptor::parse(&[TAG, 2, 1, b'a']).is_err());
assert!(ProviderExportDescriptor::parse(&[TAG, 4, 1, b'a', 3, b'x']).is_err());
assert!(ProviderExportDescriptor::parse(&[0x13, 0]).is_err());
let long = vec![0u8; 256];
let d = ProviderExportDescriptor::new(vec![ProviderExport::new(b"a", &long)]);
let mut out = vec![0u8; d.serialized_len()];
assert!(d.serialize_into(&mut out).is_err());
}
}