1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
use crate::{check_len, Error, Result, TryRead, TryWrite};
use core::str;
/// Context for &str to determine where a &str ends.
///
/// Pattern will **not** be included in the result
///
/// Default to `NULL` delimiter.
///
/// # Example
///
/// ```
/// use byte::*;
/// use byte::ctx::*;
///
/// let bytes: &[u8] = b"hello, world!\0";
///
/// let str: &str = bytes.read(&mut 0).unwrap();
/// assert_eq!(str, "hello, world!");
///
/// let str: &str = bytes.read_with(&mut 0, Str::Len(5)).unwrap();
/// assert_eq!(str, "hello");
///
/// let str: &str = bytes.read_with(&mut 0, Str::Delimiter(b"!"[0])).unwrap();
/// assert_eq!(str, "hello, world");
///
/// let str: &str = bytes.read_with(&mut 0, Str::DelimiterUntil(NULL, 5)).unwrap();
/// assert_eq!(str, "hello");
/// ```
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Str {
/// Take fix-length bytes as str
Len(usize),
/// Take bytes until reaching a delimiter
Delimiter(u8),
/// Take bytes until either delimiter or length reached
DelimiterUntil(u8, usize),
}
impl Default for Str {
#[inline]
fn default() -> Self {
Str::Delimiter(NULL)
}
}
/// Null string delimiter
pub const NULL: u8 = 0;
/// Space string delimiter
pub const SPACE: u8 = 0x20;
/// Return string delimiter
pub const RET: u8 = 0x0a;
/// Tab string delimiter
pub const TAB: u8 = 0x09;
impl<'a> TryRead<'a, Str> for &'a str {
#[inline]
fn try_read(bytes: &'a [u8], ctx: Str) -> Result<(Self, usize)> {
let (bytes, size) = match ctx {
Str::Len(len) => {
let len = check_len(bytes, len)?;
(&bytes[..len], len)
}
Str::Delimiter(delimiter) => {
let position = bytes
.iter()
.position(|c| *c == delimiter)
.ok_or(Error::Incomplete)?;
(&bytes[..position], position + 1)
}
Str::DelimiterUntil(delimiter, len) => {
let position = bytes.iter().take(len).position(|c| *c == delimiter);
match position {
Some(position) => (&bytes[..position], position + 1),
None => {
let len = check_len(bytes, len)?;
(&bytes[..len], len)
}
}
}
};
match str::from_utf8(bytes) {
Ok(str) => Ok((str, size)),
Err(_) => Err(Error::BadInput { err: "UTF8 Error" }),
}
}
}
impl<'a> TryWrite for &'a str {
#[inline]
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> Result<usize> {
let str_bytes = self.as_bytes();
check_len(bytes, str_bytes.len())?;
bytes[..str_bytes.len()].clone_from_slice(str_bytes);
Ok(str_bytes.len())
}
}