aboutsummaryrefslogtreecommitdiff
path: root/pw_tokenizer/rust/pw_tokenizer/internal.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pw_tokenizer/rust/pw_tokenizer/internal.rs')
-rw-r--r--pw_tokenizer/rust/pw_tokenizer/internal.rs79
1 files changed, 79 insertions, 0 deletions
diff --git a/pw_tokenizer/rust/pw_tokenizer/internal.rs b/pw_tokenizer/rust/pw_tokenizer/internal.rs
new file mode 100644
index 000000000..4b798b973
--- /dev/null
+++ b/pw_tokenizer/rust/pw_tokenizer/internal.rs
@@ -0,0 +1,79 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+use core::cmp::min;
+
+use pw_status::Result;
+use pw_stream::{Cursor, Write};
+
+pub fn encode_string(cursor: &mut Cursor<&mut [u8]>, value: &str) -> Result<()> {
+ const MAX_STRING_LENGTH: usize = 0x7f;
+
+ let string_bytes = value.as_bytes();
+
+ // Limit the encoding to the lesser of 127 or the available space in the buffer.
+ let max_len = min(MAX_STRING_LENGTH, cursor.remaining() - 1);
+ let overflow = max_len < string_bytes.len();
+ let len = min(max_len, string_bytes.len());
+
+ // First byte of an encoded string is it's length.
+ let mut header = len as u8;
+
+ // The high bit of the first byte is used to indicate if the string was
+ // truncated.
+ if overflow {
+ header |= 0x80;
+ }
+ cursor.write_all(&[header as u8])?;
+
+ cursor.write_all(&string_bytes[..len])
+}
+
+#[cfg(test)]
+mod test {
+ use pw_stream::{Cursor, Seek};
+
+ use super::encode_string;
+
+ fn do_string_encode_test<const BUFFER_LEN: usize>(value: &str, expected: &[u8]) {
+ let mut buffer = [0u8; BUFFER_LEN];
+ let mut cursor = Cursor::new(&mut buffer[..]);
+ encode_string(&mut cursor, value).unwrap();
+
+ let len = cursor.stream_position().unwrap() as usize;
+ let buffer = cursor.into_inner();
+
+ assert_eq!(len, expected.len());
+ assert_eq!(&buffer[..len], expected);
+ }
+
+ #[test]
+ fn test_string_encode() {
+ do_string_encode_test::<64>("test", b"\x04test");
+ do_string_encode_test::<4>("test", b"\x83tes");
+ do_string_encode_test::<1>("test", b"\x80");
+
+ // Truncates when the string does not fit.
+ do_string_encode_test::<64>(
+ "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttest",
+ b"\xbftesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttes",
+ );
+
+ // Truncates when string is over 127 bytes.
+ do_string_encode_test::<1024>(
+ "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest",
+ b"\xfftesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttes",
+ );
+ }
+}