extern crate alloc;
use alloc::vec::Vec;
use crate::error::{Error, Result};
use crate::local_set::{ItemLengthMode, LocalSet, LocalSetItem, StructuralSetKind};
use crate::types::UlBytes;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct InterchangeObjectFields {
pub instance_uid: UlBytes,
pub generation_uid: Option<UlBytes>,
pub object_class: Option<UlBytes>,
}
pub const TAG_INSTANCE_UID: u16 = 0x3C0A;
pub const TAG_GENERATION_UID: u16 = 0x0102;
pub const TAG_OBJECT_CLASS: u16 = 0x0101;
impl InterchangeObjectFields {
pub fn decode(items: &[LocalSetItem<'_>], set_name: &'static str) -> Result<Self> {
let instance_uid =
get_required_fixed::<16>(items, TAG_INSTANCE_UID, "Instance UID", set_name)?;
let generation_uid = get_optional_fixed::<16>(items, TAG_GENERATION_UID, "Generation UID")?;
let object_class = get_optional_fixed::<16>(items, TAG_OBJECT_CLASS, "Object Class")?;
Ok(Self {
instance_uid,
generation_uid,
object_class,
})
}
pub fn encode_into(&self, out: &mut Vec<LocalSetOwnedItem>) {
out.push(LocalSetOwnedItem::fixed(
TAG_INSTANCE_UID,
self.instance_uid,
));
if let Some(g) = self.generation_uid {
out.push(LocalSetOwnedItem::fixed(TAG_GENERATION_UID, g));
}
if let Some(o) = self.object_class {
out.push(LocalSetOwnedItem::fixed(TAG_OBJECT_CLASS, o));
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LocalSetOwnedItem {
pub tag: u16,
pub value: Vec<u8>,
}
impl LocalSetOwnedItem {
#[must_use]
pub fn fixed<const N: usize>(tag: u16, value: [u8; N]) -> Self {
LocalSetOwnedItem {
tag,
value: value.to_vec(),
}
}
#[must_use]
pub fn owned(tag: u16, value: Vec<u8>) -> Self {
LocalSetOwnedItem { tag, value }
}
}
pub fn get_required_fixed<const N: usize>(
items: &[LocalSetItem<'_>],
tag: u16,
name: &'static str,
set_name: &'static str,
) -> Result<[u8; N]> {
let value = items.iter().find(|i| i.tag == tag).map(|i| i.value).ok_or(
Error::MissingRequiredProperty {
tag,
name,
set: set_name,
},
)?;
<[u8; N]>::try_from(value).map_err(|_| Error::InvalidPropertyLength {
tag,
name,
found: value.len(),
expected: N,
})
}
pub fn get_optional_fixed<const N: usize>(
items: &[LocalSetItem<'_>],
tag: u16,
name: &'static str,
) -> Result<Option<[u8; N]>> {
match items.iter().find(|i| i.tag == tag) {
None => Ok(None),
Some(i) => {
<[u8; N]>::try_from(i.value)
.map(Some)
.map_err(|_| Error::InvalidPropertyLength {
tag,
name,
found: i.value.len(),
expected: N,
})
}
}
}
pub fn get_required_raw<'a>(
items: &[LocalSetItem<'a>],
tag: u16,
name: &'static str,
set_name: &'static str,
) -> Result<&'a [u8]> {
items
.iter()
.find(|i| i.tag == tag)
.map(|i| i.value)
.ok_or(Error::MissingRequiredProperty {
tag,
name,
set: set_name,
})
}
pub fn get_optional_raw<'a>(items: &[LocalSetItem<'a>], tag: u16) -> Option<&'a [u8]> {
items.iter().find(|i| i.tag == tag).map(|i| i.value)
}
pub fn collect_dark(items: &[LocalSetItem<'_>], known_tags: &[u16]) -> Vec<(u16, Vec<u8>)> {
items
.iter()
.filter(|i| !known_tags.contains(&i.tag))
.map(|i| (i.tag, i.value.to_vec()))
.collect()
}
pub fn finish_owned_set(
kind: StructuralSetKind,
mut owned_items: Vec<LocalSetOwnedItem>,
dark: &[(u16, Vec<u8>)],
) -> (UlBytes, Vec<LocalSetOwnedItem>) {
for (tag, value) in dark {
owned_items.push(LocalSetOwnedItem {
tag: *tag,
value: value.clone(),
});
}
let mode = if owned_items.iter().any(|i| i.value.len() > 0xFFFF) {
ItemLengthMode::Ber
} else {
ItemLengthMode::TwoByte
};
(LocalSet::build_key(kind, mode), owned_items)
}
pub fn serialize_owned_set(
key: UlBytes,
owned_items: &[LocalSetOwnedItem],
buf: &mut [u8],
) -> Result<usize> {
use broadcast_common::Serialize;
let items = owned_items
.iter()
.map(|i| LocalSetItem {
tag: i.tag,
value: i.value.as_slice(),
})
.collect();
let set = LocalSet { key, items };
set.serialize_into(buf)
}
#[must_use]
pub fn owned_set_serialized_len(key: UlBytes, owned_items: &[LocalSetOwnedItem]) -> usize {
use broadcast_common::Serialize;
let items = owned_items
.iter()
.map(|i| LocalSetItem {
tag: i.tag,
value: i.value.as_slice(),
})
.collect();
LocalSet { key, items }.serialized_len()
}