1extern crate alloc;
14
15use alloc::vec::Vec;
16
17use crate::error::{Error, Result};
18use crate::local_set::{ItemLengthMode, LocalSet, LocalSetItem, StructuralSetKind};
19use crate::types::UlBytes;
20
21#[derive(Debug, Clone, PartialEq, Eq, Default)]
24pub struct InterchangeObjectFields {
25 pub instance_uid: UlBytes,
27 pub generation_uid: Option<UlBytes>,
30 pub object_class: Option<UlBytes>,
32}
33
34pub const TAG_INSTANCE_UID: u16 = 0x3C0A;
36pub const TAG_GENERATION_UID: u16 = 0x0102;
38pub const TAG_OBJECT_CLASS: u16 = 0x0101;
40
41impl InterchangeObjectFields {
42 pub fn decode(items: &[LocalSetItem<'_>], set_name: &'static str) -> Result<Self> {
46 let instance_uid =
47 get_required_fixed::<16>(items, TAG_INSTANCE_UID, "Instance UID", set_name)?;
48 let generation_uid = get_optional_fixed::<16>(items, TAG_GENERATION_UID, "Generation UID")?;
49 let object_class = get_optional_fixed::<16>(items, TAG_OBJECT_CLASS, "Object Class")?;
50 Ok(Self {
51 instance_uid,
52 generation_uid,
53 object_class,
54 })
55 }
56
57 pub fn encode_into(&self, out: &mut Vec<LocalSetOwnedItem>) {
59 out.push(LocalSetOwnedItem::fixed(
60 TAG_INSTANCE_UID,
61 self.instance_uid,
62 ));
63 if let Some(g) = self.generation_uid {
64 out.push(LocalSetOwnedItem::fixed(TAG_GENERATION_UID, g));
65 }
66 if let Some(o) = self.object_class {
67 out.push(LocalSetOwnedItem::fixed(TAG_OBJECT_CLASS, o));
68 }
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
76pub struct LocalSetOwnedItem {
77 pub tag: u16,
79 pub value: Vec<u8>,
81}
82
83impl LocalSetOwnedItem {
84 #[must_use]
86 pub fn fixed<const N: usize>(tag: u16, value: [u8; N]) -> Self {
87 LocalSetOwnedItem {
88 tag,
89 value: value.to_vec(),
90 }
91 }
92
93 #[must_use]
95 pub fn owned(tag: u16, value: Vec<u8>) -> Self {
96 LocalSetOwnedItem { tag, value }
97 }
98}
99
100pub fn get_required_fixed<const N: usize>(
102 items: &[LocalSetItem<'_>],
103 tag: u16,
104 name: &'static str,
105 set_name: &'static str,
106) -> Result<[u8; N]> {
107 let value = items.iter().find(|i| i.tag == tag).map(|i| i.value).ok_or(
108 Error::MissingRequiredProperty {
109 tag,
110 name,
111 set: set_name,
112 },
113 )?;
114 <[u8; N]>::try_from(value).map_err(|_| Error::InvalidPropertyLength {
115 tag,
116 name,
117 found: value.len(),
118 expected: N,
119 })
120}
121
122pub fn get_optional_fixed<const N: usize>(
125 items: &[LocalSetItem<'_>],
126 tag: u16,
127 name: &'static str,
128) -> Result<Option<[u8; N]>> {
129 match items.iter().find(|i| i.tag == tag) {
130 None => Ok(None),
131 Some(i) => {
132 <[u8; N]>::try_from(i.value)
133 .map(Some)
134 .map_err(|_| Error::InvalidPropertyLength {
135 tag,
136 name,
137 found: i.value.len(),
138 expected: N,
139 })
140 }
141 }
142}
143
144pub fn get_required_raw<'a>(
147 items: &[LocalSetItem<'a>],
148 tag: u16,
149 name: &'static str,
150 set_name: &'static str,
151) -> Result<&'a [u8]> {
152 items
153 .iter()
154 .find(|i| i.tag == tag)
155 .map(|i| i.value)
156 .ok_or(Error::MissingRequiredProperty {
157 tag,
158 name,
159 set: set_name,
160 })
161}
162
163pub fn get_optional_raw<'a>(items: &[LocalSetItem<'a>], tag: u16) -> Option<&'a [u8]> {
165 items.iter().find(|i| i.tag == tag).map(|i| i.value)
166}
167
168pub fn collect_dark(items: &[LocalSetItem<'_>], known_tags: &[u16]) -> Vec<(u16, Vec<u8>)> {
173 items
174 .iter()
175 .filter(|i| !known_tags.contains(&i.tag))
176 .map(|i| (i.tag, i.value.to_vec()))
177 .collect()
178}
179
180pub fn finish_owned_set(
186 kind: StructuralSetKind,
187 mut owned_items: Vec<LocalSetOwnedItem>,
188 dark: &[(u16, Vec<u8>)],
189) -> (UlBytes, Vec<LocalSetOwnedItem>) {
190 for (tag, value) in dark {
191 owned_items.push(LocalSetOwnedItem {
192 tag: *tag,
193 value: value.clone(),
194 });
195 }
196 let mode = if owned_items.iter().any(|i| i.value.len() > 0xFFFF) {
197 ItemLengthMode::Ber
198 } else {
199 ItemLengthMode::TwoByte
200 };
201 (LocalSet::build_key(kind, mode), owned_items)
202}
203
204pub fn serialize_owned_set(
207 key: UlBytes,
208 owned_items: &[LocalSetOwnedItem],
209 buf: &mut [u8],
210) -> Result<usize> {
211 use broadcast_common::Serialize;
212 let items = owned_items
213 .iter()
214 .map(|i| LocalSetItem {
215 tag: i.tag,
216 value: i.value.as_slice(),
217 })
218 .collect();
219 let set = LocalSet { key, items };
220 set.serialize_into(buf)
221}
222
223#[must_use]
225pub fn owned_set_serialized_len(key: UlBytes, owned_items: &[LocalSetOwnedItem]) -> usize {
226 use broadcast_common::Serialize;
227 let items = owned_items
228 .iter()
229 .map(|i| LocalSetItem {
230 tag: i.tag,
231 value: i.value.as_slice(),
232 })
233 .collect();
234 LocalSet { key, items }.serialized_len()
235}