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");
     }
 }