use crate::with::{OurCborLen, OurDecode, OurEncode};
use minicbor::{Decode, Decoder, Encode, Encoder, decode, encode, encode::Write};
impl<'b, C> OurDecode<'b, C> for cboritem::CborItem<'b> {
fn decode(d: &mut Decoder<'b>, _ctx: &mut C) -> Result<Self, decode::Error> {
let startpos = d.position();
d.skip()?;
let endpos = d.position();
Ok(unsafe { cboritem::CborItem::new(&d.input()[startpos..endpos]) })
}
}
impl<C> OurEncode<C> for cboritem::CborItem<'_> {
fn encode<W: Write>(
&self,
e: &mut Encoder<W>,
_: &mut C,
) -> Result<(), encode::Error<W::Error>> {
e.writer_mut()
.write_all(self)
.map_err(encode::Error::write)?;
Ok(())
}
}
impl<C> OurCborLen<C> for cboritem::CborItem<'_> {
fn cbor_len(&self, _: &mut C) -> usize {
self.len()
}
}
#[derive(Debug)]
pub struct WithOpaque<'a, T> {
pub opaque: cboritem::CborItem<'a>,
pub parsed: T,
}
impl<'b, C, T> Decode<'b, C> for WithOpaque<'b, T>
where
T: Decode<'b, C>,
{
fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Self, decode::Error> {
let startpos = d.position();
let parsed = d.decode_with(ctx)?;
let endpos = d.position();
let opaque = unsafe { cboritem::CborItem::new(&d.input()[startpos..endpos]) };
Ok(WithOpaque { opaque, parsed })
}
}
impl<C, T> Encode<C> for WithOpaque<'_, T> {
fn encode<W: Write>(
&self,
e: &mut Encoder<W>,
_: &mut C,
) -> Result<(), encode::Error<W::Error>> {
e.writer_mut()
.write_all(&self.opaque)
.map_err(encode::Error::write)?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::WithOpaque;
use cboritem::CborItem;
use minicbor::{Decode, Encode};
#[derive(Decode, Debug)]
struct UsedInWrapper<'a> {
#[n(0)]
number: u32,
#[b(1)]
text: &'a str,
}
#[derive(Decode, Encode, Debug)]
struct OpaqueItems<'a> {
#[cbor(b(0), with = "crate")]
item_a: CborItem<'a>,
#[cbor(b(1), with = "crate")]
item_b: CborItem<'a>,
#[b(2)]
item_c: Option<WithOpaque<'a, UsedInWrapper<'a>>>,
}
const EXAMPLE: &[u8] = &[
0x83, 0x00, 0x82, 0x01, 0x02, 0x82, 0x18, 0x2a, 0x62, 0x68, 0x69,
];
#[test]
fn decode_cboritem() {
let decoded: OpaqueItems = minicbor::decode(EXAMPLE).unwrap();
let _item_a: usize = minicbor::decode(&decoded.item_a).unwrap();
let item_b: Result<&str, _> = minicbor::decode(&decoded.item_b);
item_b.unwrap_err();
let item_c = decoded.item_c.unwrap();
assert!((item_c.parsed.number, item_c.parsed.text) == (42, "hi"));
assert!(matches!(&*item_c.opaque, &[0x82, .., 0x68, 0x69]));
}
#[test]
fn encode_cboritem() {
let data = [0x82, 0x00, 0x82, 0x01, 0x02];
let decoded: OpaqueItems = minicbor::decode(data.as_ref()).unwrap();
let mut buf = [0u8; 20];
let mut buf = minicbor::encode::write::Cursor::new(buf.as_mut());
let mut swapped = minicbor::Encoder::new(&mut buf);
swapped
.encode(OpaqueItems {
item_a: decoded.item_b,
item_b: decoded.item_a,
item_c: Some(WithOpaque {
opaque: cbor_macro::cbor!([9, ""]),
parsed: UsedInWrapper {
number: 99,
text: "actually the number is 9 and the byte string is empty",
},
}),
})
.unwrap();
assert_eq!(
&[0x83, 0x82, 0x01, 0x02, 0x00, 0x82, 0x09, 0x60],
&buf.get_ref()[..buf.position()]
);
}
#[test]
fn debug() {
extern crate std;
let decoded: OpaqueItems = minicbor::decode(EXAMPLE).unwrap();
assert_eq!(
std::format!("{decoded:#?}"),
"\
OpaqueItems {
item_a: 00,
item_b: 82 01 02,
item_c: Some(
WithOpaque {
opaque: 82 18 2a 62 68 69,
parsed: UsedInWrapper {
number: 42,
text: \"hi\",
},
},
),
}"
);
}
}