use core::iter::{Chain, Once};
use crate::error::{Error, ErrorCode};
use super::{OnceTLVIter, TLVTag, TLVValue, TLVValueType, TLV};
type TLVResult<'a> = Result<TLV<'a>, Error>;
type ChainedTLVIter<'a, C> = Chain<C, OnceTLVIter<'a>>;
pub trait TLVIter<'a>: Iterator<Item = TLVResult<'a>> + Sized {
fn flatten(value: Result<Self, Error>) -> EitherIter<Self, Once<TLVResult<'a>>> {
match value {
Ok(value) => EitherIter::First(value),
Err(err) => EitherIter::Second(core::iter::once(Err(err))),
}
}
fn tlv(self, tag: TLVTag, value: TLVValue<'a>) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::new(tag, value).into_tlv_iter())
}
fn i8(self, tag: TLVTag, data: i8) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::i8(tag, data).into_tlv_iter())
}
fn u8(self, tag: TLVTag, data: u8) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::u8(tag, data).into_tlv_iter())
}
fn i16(self, tag: TLVTag, data: i16) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::i16(tag, data).into_tlv_iter())
}
fn u16(self, tag: TLVTag, data: u16) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::u16(tag, data).into_tlv_iter())
}
fn i32(self, tag: TLVTag, data: i32) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::i32(tag, data).into_tlv_iter())
}
fn u32(self, tag: TLVTag, data: u32) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::u32(tag, data).into_tlv_iter())
}
fn i64(self, tag: TLVTag, data: i64) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::i64(tag, data).into_tlv_iter())
}
fn u64(self, tag: TLVTag, data: u64) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::u64(tag, data).into_tlv_iter())
}
fn f32(self, tag: TLVTag, data: f32) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::f32(tag, data).into_tlv_iter())
}
fn f64(self, tag: TLVTag, data: f64) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::f64(tag, data).into_tlv_iter())
}
fn str(self, tag: TLVTag, data: &'a [u8]) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::str(tag, data).into_tlv_iter())
}
fn utf8(self, tag: TLVTag, data: &'a str) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::utf8(tag, data).into_tlv_iter())
}
fn start_struct(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::structure(tag).into_tlv_iter())
}
fn start_array(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::array(tag).into_tlv_iter())
}
fn start_list(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::list(tag).into_tlv_iter())
}
fn start_container(self, tag: TLVTag, container_type: TLVValueType) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
match container_type {
TLVValueType::Struct => self.start_struct(tag),
TLVValueType::Array => self.start_array(tag),
TLVValueType::List => self.start_list(tag),
_ => self.chain(core::iter::once(Err(ErrorCode::TLVTypeMismatch.into()))),
}
}
fn end_container(self) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::end_container().into_tlv_iter())
}
fn null(self, tag: TLVTag) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::null(tag).into_tlv_iter())
}
fn bool(self, tag: TLVTag, data: bool) -> ChainedTLVIter<'a, Self>
where
Self: 'a,
{
self.chain(TLV::bool(tag, data).into_tlv_iter())
}
}
impl<'a, T> TLVIter<'a> for T where T: Iterator<Item = TLVResult<'a>> {}
#[derive(Clone)]
pub enum EitherIter<F, S> {
First(F),
Second(S),
}
impl<F, S> Iterator for EitherIter<F, S>
where
F: Iterator,
S: Iterator<Item = F::Item>,
{
type Item = <F as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::First(i) => i.next(),
Self::Second(i) => i.next(),
}
}
}
#[derive(Clone)]
pub enum Either3Iter<F, S, T> {
First(F),
Second(S),
Third(T),
}
impl<F, S, T> Iterator for Either3Iter<F, S, T>
where
F: Iterator,
S: Iterator<Item = F::Item>,
T: Iterator<Item = F::Item>,
{
type Item = <F as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::First(i) => i.next(),
Self::Second(i) => i.next(),
Self::Third(i) => i.next(),
}
}
}
#[derive(Clone)]
pub enum Either4Iter<F, S, T, U> {
First(F),
Second(S),
Third(T),
Fourth(U),
}
impl<F, S, T, U> Iterator for Either4Iter<F, S, T, U>
where
F: Iterator,
S: Iterator<Item = F::Item>,
T: Iterator<Item = F::Item>,
U: Iterator<Item = F::Item>,
{
type Item = <F as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::First(i) => i.next(),
Self::Second(i) => i.next(),
Self::Third(i) => i.next(),
Self::Fourth(i) => i.next(),
}
}
}
#[derive(Clone)]
pub enum Either5Iter<F, S, T, U, I> {
First(F),
Second(S),
Third(T),
Fourth(U),
Fifth(I),
}
impl<F, S, T, U, I> Iterator for Either5Iter<F, S, T, U, I>
where
F: Iterator,
S: Iterator<Item = F::Item>,
T: Iterator<Item = F::Item>,
U: Iterator<Item = F::Item>,
I: Iterator<Item = F::Item>,
{
type Item = <F as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::First(i) => i.next(),
Self::Second(i) => i.next(),
Self::Third(i) => i.next(),
Self::Fourth(i) => i.next(),
Self::Fifth(i) => i.next(),
}
}
}
#[derive(Clone)]
pub enum Either6Iter<F, S, T, U, I, X> {
First(F),
Second(S),
Third(T),
Fourth(U),
Fifth(I),
Sixth(X),
}
impl<F, S, T, U, I, X> Iterator for Either6Iter<F, S, T, U, I, X>
where
F: Iterator,
S: Iterator<Item = F::Item>,
T: Iterator<Item = F::Item>,
U: Iterator<Item = F::Item>,
I: Iterator<Item = F::Item>,
X: Iterator<Item = F::Item>,
{
type Item = <F as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::First(i) => i.next(),
Self::Second(i) => i.next(),
Self::Third(i) => i.next(),
Self::Fourth(i) => i.next(),
Self::Fifth(i) => i.next(),
Self::Sixth(i) => i.next(),
}
}
}
#[cfg(test)]
mod tests {
use core::{f32, iter::empty};
use crate::tlv::TLV;
use super::{TLVIter, TLVResult, TLVTag};
fn expect<'a, I>(iter: I, expected: &[u8])
where
I: Iterator<Item = TLVResult<'a>>,
{
let mut iter = iter.map(|r| r.unwrap()).flat_map(TLV::into_bytes_iter);
let mut expected = expected.iter().copied();
loop {
match (iter.next(), expected.next()) {
(Some(a), Some(b)) => assert_eq!(a, b),
(None, None) => break,
(Some(_), None) => panic!("Iterator has more bytes than expected"),
(None, Some(_)) => panic!("Iterator has fewer bytes than expected"),
}
}
}
#[test]
fn test_write_success() {
expect(
empty()
.start_struct(TLVTag::Anonymous)
.u8(TLVTag::Anonymous, 12)
.u8(TLVTag::Context(1), 13)
.u16(TLVTag::Anonymous, 0x1212)
.u16(TLVTag::Context(2), 0x1313)
.start_array(TLVTag::Context(3))
.bool(TLVTag::Anonymous, true)
.end_container()
.end_container(),
&[
21, 4, 12, 36, 1, 13, 5, 0x12, 0x012, 37, 2, 0x13, 0x13, 54, 3, 9, 24, 24,
],
);
}
#[test]
fn test_put_str8() {
expect(
empty()
.u8(TLVTag::Context(1), 13)
.str(TLVTag::Anonymous, &[10, 11, 12, 13, 14])
.u16(TLVTag::Context(2), 0x1313)
.str(TLVTag::Context(3), &[20, 21, 22]),
&[
36, 1, 13, 16, 5, 10, 11, 12, 13, 14, 37, 2, 0x13, 0x13, 48, 3, 3, 20, 21, 22,
],
);
}
#[test]
fn test_matter_spec_examples() {
expect(empty().bool(TLVTag::Anonymous, false), &[0x08]);
expect(empty().bool(TLVTag::Anonymous, true), &[0x09]);
expect(empty().i8(TLVTag::Anonymous, 42), &[0x00, 0x2a]);
expect(empty().i8(TLVTag::Anonymous, -17), &[0x00, 0xef]);
expect(empty().u8(TLVTag::Anonymous, 42), &[0x04, 0x2a]);
expect(empty().i16(TLVTag::Anonymous, 422), &[0x01, 0xa6, 0x01]);
expect(
empty().i64(TLVTag::Anonymous, -170000),
&[0x02, 0xf0, 0x67, 0xfd, 0xff],
);
expect(
empty().i64(TLVTag::Anonymous, 40000000000),
&[0x03, 0x00, 0x90, 0x2f, 0x50, 0x09, 0x00, 0x00, 0x00],
);
expect(
empty().utf8(TLVTag::Anonymous, "Hello!"),
&[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21],
);
expect(
empty().utf8(TLVTag::Anonymous, "Tschüs"),
&[0x0c, 0x07, 0x54, 0x73, 0x63, 0x68, 0xc3, 0xbc, 0x73],
);
expect(
empty().str(TLVTag::Anonymous, &[0x00, 0x01, 0x02, 0x03, 0x04]),
&[0x10, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04],
);
expect(empty().null(TLVTag::Anonymous), &[0x14]);
expect(
empty().f32(TLVTag::Anonymous, 0.0),
&[0x0a, 0x00, 0x00, 0x00, 0x00],
);
expect(
empty().f32(TLVTag::Anonymous, 1.0 / 3.0),
&[0x0a, 0xab, 0xaa, 0xaa, 0x3e],
);
expect(
empty().f32(TLVTag::Anonymous, 17.9),
&[0x0a, 0x33, 0x33, 0x8f, 0x41],
);
expect(
empty().f32(TLVTag::Anonymous, f32::INFINITY),
&[0x0a, 0x00, 0x00, 0x80, 0x7f],
);
expect(
empty().f32(TLVTag::Anonymous, f32::NEG_INFINITY),
&[0x0a, 0x00, 0x00, 0x80, 0xff],
);
expect(
empty().f64(TLVTag::Anonymous, 0.0),
&[0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
);
expect(
empty().f64(TLVTag::Anonymous, 1.0 / 3.0),
&[0x0b, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f],
);
expect(
empty().f64(TLVTag::Anonymous, 17.9),
&[0x0b, 0x66, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x31, 0x40],
);
expect(
empty().f64(TLVTag::Anonymous, f64::INFINITY),
&[0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f],
);
expect(
empty().f64(TLVTag::Anonymous, f64::NEG_INFINITY),
&[0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff],
);
expect(
empty().start_struct(TLVTag::Anonymous).end_container(),
&[0x15, 0x18],
);
expect(
empty().start_array(TLVTag::Anonymous).end_container(),
&[0x16, 0x18],
);
expect(
empty().start_list(TLVTag::Anonymous).end_container(),
&[0x17, 0x18],
);
expect(
empty()
.start_struct(TLVTag::Anonymous)
.i8(TLVTag::Context(0), 42)
.i32(TLVTag::Context(1), -17)
.end_container(),
&[0x15, 0x20, 0x00, 0x2a, 0x20, 0x01, 0xef, 0x18],
);
expect(
empty()
.start_array(TLVTag::Anonymous)
.i8(TLVTag::Anonymous, 0)
.i8(TLVTag::Anonymous, 1)
.i8(TLVTag::Anonymous, 2)
.i8(TLVTag::Anonymous, 3)
.i8(TLVTag::Anonymous, 4)
.end_container(),
&[
0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x18,
],
);
expect(
empty()
.start_list(TLVTag::Anonymous)
.i64(TLVTag::Anonymous, 1)
.i16(TLVTag::Context(0), 42)
.i8(TLVTag::Anonymous, 2)
.i8(TLVTag::Anonymous, 3)
.i32(TLVTag::Context(0), -17)
.end_container(),
&[
0x17, 0x00, 0x01, 0x20, 0x00, 0x2a, 0x00, 0x02, 0x00, 0x03, 0x20, 0x00, 0xef, 0x18,
],
);
expect(
empty()
.start_array(TLVTag::Anonymous)
.i64(TLVTag::Anonymous, 42)
.i64(TLVTag::Anonymous, -170000)
.start_struct(TLVTag::Anonymous)
.end_container()
.f32(TLVTag::Anonymous, 17.9)
.utf8(TLVTag::Anonymous, "Hello!")
.end_container(),
&[
0x16, 0x00, 0x2a, 0x02, 0xf0, 0x67, 0xfd, 0xff, 0x15, 0x18, 0x0a, 0x33, 0x33, 0x8f,
0x41, 0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x18,
],
);
expect(empty().u64(TLVTag::Anonymous, 42), &[0x04, 0x2a]);
expect(empty().u16(TLVTag::Context(1), 42), &[0x24, 0x01, 0x2a]);
expect(
empty().u16(TLVTag::CommonPrf16(1), 42),
&[0x44, 0x01, 0x00, 0x2a],
);
expect(
empty().u16(TLVTag::CommonPrf32(100000), 42),
&[0x64, 0xa0, 0x86, 0x01, 0x00, 0x2a],
);
expect(
empty().u16(
TLVTag::FullQual48 {
vendor_id: 65521,
profile: 57069,
tag: 1,
},
42,
),
&[0xc4, 0xf1, 0xff, 0xed, 0xde, 0x01, 0x00, 0x2a],
);
expect(
empty().u16(
TLVTag::FullQual64 {
vendor_id: 65521,
profile: 57069,
tag: 2857762541,
},
42,
),
&[0xe4, 0xf1, 0xff, 0xed, 0xde, 0xed, 0xfe, 0x55, 0xaa, 0x2a],
);
expect(
empty()
.start_struct(TLVTag::FullQual48 {
vendor_id: 65521,
profile: 57069,
tag: 1,
})
.u64(
TLVTag::FullQual48 {
vendor_id: 65521,
profile: 57069,
tag: 43605,
},
42,
)
.end_container(),
&[
0xd5, 0xf1, 0xff, 0xed, 0xde, 0x01, 0x00, 0xc4, 0xf1, 0xff, 0xed, 0xde, 0x55, 0xaa,
0x2a, 0x18,
],
);
}
}