rust/bt-common: Add LtvValue::encode_all Encodes multiple LtvValue items. Change-Id: If675fa08fc2ac3a0e131e2faf13c6c062bf5c59e Reviewed-on: https://bluetooth-review.git.corp.google.com/c/bluetooth/+/1980 Reviewed-by: Ani Ramakrishnan <aniramakri@google.com>
diff --git a/rust/bt-common/src/core/ltv.rs b/rust/bt-common/src/core/ltv.rs index d8923e2..6a1083a 100644 --- a/rust/bt-common/src/core/ltv.rs +++ b/rust/bt-common/src/core/ltv.rs
@@ -73,6 +73,21 @@ } } } + + /// Encode a collection of LtValue structures into a buffer. + /// Even if the encoding fails, `buf` may still be modified by + /// previous encoding successes. + fn encode_all( + iter: impl Iterator<Item = Self>, + buf: &mut [u8], + ) -> Result<(), crate::packet_encoding::Error> { + let mut idx = 0; + for item in iter { + item.encode(&mut buf[idx..])?; + idx += item.encoded_len(); + } + Ok(()) + } } #[derive(Error, Debug, PartialEq)] @@ -246,6 +261,9 @@ } fn encode_value(&self, buf: &mut [u8]) -> Result<(), crate::packet_encoding::Error> { + if buf.len() < self.value_encoded_len() as usize { + return Err(crate::packet_encoding::Error::BufferTooSmall); + } match self { TestValues::TwoBytes(x) => { [buf[0], buf[1]] = x.to_be_bytes(); @@ -253,7 +271,9 @@ TestValues::TwoBytesLittleEndian(x) => { [buf[0], buf[1]] = x.to_le_bytes(); } - TestValues::OneByte(x) => buf[0] = *x, + TestValues::OneByte(x) => { + buf[0] = *x; + } TestValues::UnicodeString(s) => { buf.copy_from_slice(s.as_bytes()); } @@ -283,6 +303,26 @@ assert_eq!(decoded[1], Err(Error::UnrecognizedType("TestValues".to_owned(), 6))); } + #[test] + fn encode_twobytes() { + let value = TestValues::TwoBytes(0x0A0B); + let mut buf = [0; 4]; + value.encode(&mut buf[..]).expect("should succeed"); + assert_eq!(buf, [0x03, 0x02, 0x0A, 0x0B]); + } + + #[test] + fn encode_all() { + let value1 = TestValues::OneByte(0x0A); + let value2 = TestValues::UnicodeString("Bluetooth".to_string()); + let mut buf = [0; 14]; + LtValue::encode_all(vec![value1, value2].into_iter(), &mut buf).expect("should succeed"); + assert_eq!( + buf, + [0x02, 0x01, 0x0a, 0x0a, 0x04, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68] + ); + } + #[track_caller] fn u8char(c: char) -> u8 { c.try_into().unwrap() @@ -335,11 +375,16 @@ #[test] fn encode_with_error() { - let mut buf = [0; 10]; let value = TestValues::AlwaysError; + let mut buf = [0; 10]; assert!(matches!( value.encode(&mut buf), Err(crate::packet_encoding::Error::InvalidParameter(_)), )); + + let value1 = TestValues::TwoBytes(0x0A0B); + let value2 = TestValues::OneByte(0x0A); + let mut buf = [0; 2]; // not enough buffer space. + LtValue::encode_all(vec![value1, value2].into_iter(), &mut buf).expect_err("should fail"); } }