use camino::{Utf8Path, Utf8PathBuf};
use nom::Err::Failure;
use nom::error::Error as NomError;
use nom::error::ErrorKind as NomErrorKind;
use nom::error::FromExternalError;
use nom::IResult;
use nom::number::complete::be_u32;
use nom::bytes::complete::take;
use serde::ser::SerializeTuple;
use serde::Serialize;
use serde::Serializer;
use uuid::Uuid;
#[cfg(test)]
use proptest::strategy::Strategy;
pub fn vec_u8_as_slice<S: Serializer>(elements: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error> {
let mut tuple = serializer.serialize_tuple(elements.len())?;
for e in elements {
tuple.serialize_element(e)?;
}
tuple.end()
}
pub fn vec_with_u32_length<S: Serializer, T: Serialize>(elements: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error> {
let mut seq = serializer.serialize_tuple(elements.len() + 1)?;
seq.serialize_element(&(elements.len() as u32))?;
for e in elements {
seq.serialize_element(e)?;
}
seq.end()
}
pub fn path_with_u32_length<S: Serializer>(s: &Utf8Path, serializer: S) -> Result<S::Ok, S::Error> {
str_with_u32_length(s.as_str(), serializer)
}
pub fn str_with_u32_length<S: Serializer>(s: &str, serializer: S) -> Result<S::Ok, S::Error> {
let slice = s.as_bytes();
let mut seq = serializer.serialize_tuple(slice.len() + 1)?;
seq.serialize_element(&(slice.len() as u32))?;
for c in slice {
seq.serialize_element(c)?;
}
seq.end()
}
pub fn serialize_uuid<S: Serializer>(uuid: &Uuid, serializer: S) -> Result<S::Ok, S::Error> {
str_with_u32_length(&uuid.to_string(), serializer)
}
#[inline]
pub fn parse_u8_vec(i: &[u8]) -> IResult<&[u8], Vec<u8>> {
let (i, len) = be_u32(i)?;
if(i.len() < len as usize) {
return Ok((i, Vec::new()));
}
let (i, slice) = take(len)(i)?;
Ok((i, Vec::from(slice)))
}
#[inline]
pub fn parse_vec<'a, T: nom_derive::Parse<&'a [u8]>>(i: &'a [u8]) -> IResult<&'a [u8], Vec<T>> {
let (mut i, len) = be_u32(i)?;
let mut s;
let mut vec = Vec::with_capacity(len as usize);
for _ in 0..len {
(i, s) = T::parse(i)?;
vec.push(s)
}
Ok((i, vec))
}
pub fn parse_str(i: &[u8]) -> IResult<&[u8], &str> {
let (i, len) = be_u32(i)?;
let (i, string) = take(len)(i)?;
Ok((i, std::str::from_utf8(string).map_err(|e| Failure(NomError::from_external_error(i, NomErrorKind::Char, e)))?))
}
#[inline]
pub fn parse_string(i: &[u8]) -> IResult<&[u8], String> {
let (i, string) = parse_str(i)?;
Ok((i, string.to_string()))
}
#[inline]
pub fn parse_path(i: &[u8]) -> IResult<&[u8], Utf8PathBuf> {
let (i, string) = parse_str(i)?;
Ok((i, string.into()))
}
#[inline]
pub fn parse_uuid(i: &[u8]) -> IResult<&[u8], Uuid> {
let (i, s) = parse_str(i)?;
Ok((i, Uuid::parse_str(s).map_err(|e| Failure(NomError::from_external_error(i, NomErrorKind::Char, e)))?))
}
#[cfg(test)]
pub(crate) fn arbitrary_uuid() -> impl Strategy<Value = Uuid> {
proptest::prelude::any::<u128>().prop_map(Uuid::from_u128)
}