use camino::Utf8PathBuf;
use nom::IResult;
use nom::number::streaming::be_u32;
use nom::number::streaming::le_u32;
use crate::common::FileAttributes;
use super::kind::PacketType;
use super::PayloadTrait;
#[derive(Debug, Eq, PartialEq, Nom, Serialize)]
#[nom(BigEndian)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
pub struct Open {
pub id: u32,
#[nom(Parse(crate::util::parse_path))]
#[serde(serialize_with = "crate::util::path_with_u32_length")]
pub path: Utf8PathBuf,
pub pflags: OpenFlags,
pub attrs: FileAttributes
}
impl PayloadTrait for Open {
const Type: PacketType = PacketType::Open;
fn binsize(&self) -> u32 {
4 + (4 + self.path.as_str().len() as u32) + 4 + self.attrs.binsize()
}
}
impl From<Open> for super::Payload {
fn from(p: Open) -> Self {
Self::Open(p)
}
}
bitflags::bitflags! {
#[derive(Default, Serialize)]
pub struct OpenFlags: u32 {
const Read = 0x01;
const Write = 0x02;
const Append = 0x04;
const Create = 0x08;
const Truncate = 0x10;
const Exclude = 0x20;
}
}
#[cfg(test)]
impl proptest::bits::BitSetLike for OpenFlags {
fn new_bitset(_max: usize) -> Self {
Self::empty()
}
fn len(&self) -> usize {
7
}
fn test(&self, i: usize) -> bool {
(self.bits() & 2 << i) != 0
}
fn set(&mut self, i: usize) {
self.insert(Self::from_bits_truncate(2 << i))
}
fn clear(&mut self, i: usize) {
self.remove(Self::from_bits_truncate(2 << i))
}
}
#[cfg(test)]
impl proptest::prelude::Arbitrary for OpenFlags {
type Parameters = ();
type Strategy = proptest::bits::BitSetStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
proptest::bits::BitSetStrategy::masked(Self::from_bits_truncate(0x3f))
}
}
impl<I: nom_derive::InputSlice> nom_derive::Parse<I> for OpenFlags {
fn parse_be(i: I) -> IResult<I, Self> {
let (i, flags) = be_u32(i)?;
let this = Self::from_bits_truncate(flags);
Ok((i, this))
}
fn parse_le(i: I) -> IResult<I, Self> {
let (i, flags) = le_u32(i)?;
let this = Self::from_bits_truncate(flags);
Ok((i, this))
}
fn parse(i: I) -> IResult<I, Self> {
Self::parse_be(i)
}
}
#[cfg(test)]
mod tests {
use test_strategy::proptest;
use crate::parser::encode;
use crate::parser::Parser;
use super::*;
#[proptest]
fn roundtrip_whole(input: Open) {
let mut stream = Parser::default();
let packet = input.into_packet();
stream.write(&encode(&packet)).unwrap();
assert_eq!(stream.get_packet(), Ok(Some(packet)));
assert_eq!(stream.get_packet(), Ok(None));
}
}