diff options
Diffstat (limited to 'pw_tokenizer/rust/pw_tokenizer/internal.rs')
-rw-r--r-- | pw_tokenizer/rust/pw_tokenizer/internal.rs | 79 |
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", + ); + } +} |