use crate::prelude::*;
use winnow::token::take;
#[inline(always)]
pub fn to_string_utf8(len: usize) -> impl Fn(&mut &[u8]) -> crate::Result<String> {
move |input| {
take(len)
.map(|slice| String::from_utf8_lossy(slice).to_string())
.parse_next(input)
}
}
#[inline(always)]
pub fn to_string_utf8_strict(len: usize) -> impl Fn(&mut &[u8]) -> crate::Result<String> {
move |input| {
let checkpoint = input.checkpoint();
match String::from_utf8(take(len).parse_next(input)?.to_vec()) {
Ok(s) => Ok(s),
Err(_) => Err(winnow::error::ContextError::new().add_context(
input,
&checkpoint,
winnow::error::StrContext::Label(
"Unable to decode string using `String::from_utf8`",
),
)),
}
}
}
#[inline(always)]
pub fn to_string_utf16_le(len: usize) -> impl Fn(&mut &[u8]) -> crate::Result<String> {
move |input| {
let checkpoint = input.checkpoint();
if !len.is_multiple_of(2) {
return Err(winnow::error::ContextError::new().add_context(
input,
&checkpoint,
winnow::error::StrContext::Label("Invalid UTF-16 slice length"),
));
}
take(len)
.map(|slice: &[u8]| {
let utf16: Vec<u16> = slice
.chunks_exact(2)
.map(|chunk| {
#[allow(
clippy::unwrap_used,
reason = "safe to unwrap, since `chunks_exact` returns exactly 2 bytes"
)]
let array: [u8; 2] = chunk.try_into().unwrap();
u16::from_le_bytes(array)
})
.collect();
String::from_utf16_lossy(&utf16)
})
.parse_next(input)
}
}
#[inline(always)]
pub fn to_string_utf16_be(len: usize) -> impl Fn(&mut &[u8]) -> crate::Result<String> {
move |input| {
let checkpoint = input.checkpoint();
if !len.is_multiple_of(2) {
return Err(winnow::error::ContextError::new().add_context(
input,
&checkpoint,
winnow::error::StrContext::Label("Invalid UTF-16 slice length"),
));
}
take(len)
.map(|slice: &[u8]| {
let utf16: Vec<u16> = slice
.chunks_exact(2)
.map(|chunk| {
#[allow(
clippy::unwrap_used,
reason = "safe to unwrap, since `chunks_exact` returns exactly 2 bytes"
)]
let array: [u8; 2] = chunk.try_into().unwrap();
u16::from_be_bytes(array)
})
.collect();
String::from_utf16_lossy(&utf16)
})
.parse_next(input)
}
}
#[inline(always)]
#[cfg(feature = "ascii")]
pub fn to_string_ascii(len: usize) -> impl Fn(&mut &[u8]) -> crate::Result<String> {
move |input| {
let checkpoint = input.checkpoint();
match ascii::AsciiString::from_ascii(take(len).parse_next(input)?) {
Ok(s) => Ok(s.to_string()),
Err(_) => Err(winnow::error::ContextError::new().add_context(
input,
&checkpoint,
winnow::error::StrContext::Label(
"Unable to decode string using `ascii::AsciiString::from_ascii`",
),
)),
}
}
}