use camino::Utf8Path;
use nom_derive::Parse;
use serde::Serialize;
use crate::common::FileAttributes;
#[cfg(test)]
use proptest::strategy::Strategy;
pub mod kind;
use kind::PacketType;
pub mod init;
use init::Init;
pub mod version;
use version::Version;
pub mod open;
use open::Open;
pub mod close;
use close::Close;
pub mod read;
use read::Read;
pub mod write;
use write::Write;
pub mod lstat;
use lstat::Lstat;
pub mod fstat;
use fstat::Fstat;
pub mod setstat;
use setstat::SetStat;
pub mod fsetstat;
use fsetstat::FSetStat;
pub mod opendir;
use opendir::OpenDir;
pub mod readdir;
use readdir::ReadDir;
pub mod remove;
use remove::Remove;
pub mod mkdir;
use mkdir::MkDir;
pub mod rmdir;
use rmdir::RmDir;
pub mod realpath;
use realpath::RealPath;
pub mod stat;
use stat::Stat;
pub mod rename;
use rename::Rename;
pub mod readlink;
use readlink::ReadLink;
pub mod symlink;
use symlink::Symlink;
pub mod status;
use status::Status;
use status::StatusType;
pub mod handle;
use handle::Handle;
pub mod data;
use data::Data;
pub mod name;
use name::Name;
pub mod attrs;
use attrs::Attrs;
pub mod extended;
use extended::Request as ExtendedRequest;
use extended::Response as ExtendedResponse;
#[derive(Debug, Nom, Serialize)]
#[nom(BigEndian)]
pub struct PacketRaw<'a> {
pub length: u32,
pub kind: PacketType,
#[nom(Take="i.len()")]
pub raw_payload: &'a [u8]
}
#[derive(Clone, Debug, Eq, PartialEq, Nom, Serialize)]
#[nom(BigEndian)]
pub struct PacketHeader {
pub length: u32,
pub kind: PacketType
}
#[derive(Debug, Eq, PartialEq, Nom, Serialize)]
#[nom(BigEndian)]
pub struct Packet {
pub header: PacketHeader,
#[nom(Parse="{ |i| Payload::parse(i, header.kind) }")]
pub payload: Payload
}
#[cfg(test)]
impl proptest::arbitrary::Arbitrary for Packet {
type Parameters = ();
type Strategy = proptest::strategy::BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
Payload::arbitrary_with(()).prop_map(|payload| payload.into_packet()).boxed()
}
}
pub trait PayloadTrait : Serialize + Into<Payload> {
const Type: PacketType;
fn binsize(&self) -> u32;
fn header(&self) -> PacketHeader {
PacketHeader{
length: 1 + self.binsize(),
kind: Self::Type
}
}
fn into_packet(self) -> Packet {
Packet{
header: self.header(),
payload: self.into()
}
}
}
#[derive(Debug, Eq, PartialEq, Nom, Serialize)]
#[nom(Selector = "PacketType")]
#[serde(untagged)]
#[cfg_attr(test, derive(test_strategy::Arbitrary))]
pub enum Payload {
#[nom(Selector = "PacketType::Init")]
Init(Init),
#[nom(Selector = "PacketType::Version")]
Version(Version),
#[nom(Selector = "PacketType::Open")]
Open(Open),
#[nom(Selector = "PacketType::Close")]
Close(Close),
#[nom(Selector = "PacketType::Read")]
Read(Read),
#[nom(Selector = "PacketType::Write")]
Write(Write),
#[nom(Selector = "PacketType::Lstat")]
Lstat(Lstat),
#[nom(Selector = "PacketType::Fstat")]
Fstat(Fstat),
#[nom(Selector = "PacketType::SetStat")]
SetStat(SetStat),
#[nom(Selector = "PacketType::FSetStat")]
FSetStat(FSetStat),
#[nom(Selector = "PacketType::OpenDir")]
OpenDir(OpenDir),
#[nom(Selector = "PacketType::ReadDir")]
ReadDir(ReadDir),
#[nom(Selector = "PacketType::Remove")]
Remove(Remove),
#[nom(Selector = "PacketType::MkDir")]
MkDir(MkDir),
#[nom(Selector = "PacketType::RmDir")]
RmDir(RmDir),
#[nom(Selector = "PacketType::RealPath")]
RealPath(RealPath),
#[nom(Selector = "PacketType::Stat")]
Stat(Stat),
#[nom(Selector = "PacketType::Rename")]
Rename(Rename),
#[nom(Selector = "PacketType::ReadLink")]
ReadLink(ReadLink),
#[nom(Selector = "PacketType::Symlink")]
Symlink(Symlink),
#[nom(Selector = "PacketType::Status")]
Status(Status),
#[nom(Selector = "PacketType::Handle")]
Handle(Handle),
#[nom(Selector = "PacketType::Data")]
Data(Data),
#[nom(Selector = "PacketType::Name")]
Name(Name),
#[nom(Selector = "PacketType::Attrs")]
Attrs(Attrs),
#[nom(Selector = "PacketType::Extended")]
Extended(ExtendedRequest),
#[nom(Selector = "PacketType::ExtendedReply")]
ExtendedReply(ExtendedResponse)
}
impl Payload {
pub fn init(version: u32, extension_data: Vec<u8>) -> Self {
Self::Init(Init{
version,
extension_data
})
}
pub fn version(version: u32, extension_data: Vec<u8>) -> Self {
Self::Version(Version{
version,
extension_data
})
}
pub fn real_path(id: u32, path: impl AsRef<Utf8Path>) -> Self {
Self::RealPath(RealPath{
id,
path: path.as_ref().to_path_buf()
})
}
pub fn status(id: u32, status: StatusType, message: impl AsRef<str>) -> Self {
Self::Status(Status{
id,
status,
message: message.as_ref().to_string(),
language: "en-US".to_string()
})
}
pub fn handle(id: u32) -> Handle {
Handle{
id,
handle: uuid::Uuid::new_v4()
}
}
pub fn name(id: u32) -> Name {
Name{
id,
files: Vec::with_capacity(1)
}
}
pub fn attrs(id: u32) -> Attrs {
Attrs{
id,
attrs: FileAttributes::new()
}
}
pub fn data_with_size(id: u32, size: u32) -> Data {
Data{
id,
data: vec![0; size as usize]
}
}
pub fn into_packet(self) -> Packet {
match self {
Self::Init(p) => p.into_packet(),
Self::Version(p) => p.into_packet(),
Self::Open(p) => p.into_packet(),
Self::Close(p) => p.into_packet(),
Self::Read(p) => p.into_packet(),
Self::Write(p) => p.into_packet(),
Self::Lstat(p) => p.into_packet(),
Self::Fstat(p) => p.into_packet(),
Self::SetStat(p) => p.into_packet(),
Self::FSetStat(p) => p.into_packet(),
Self::OpenDir(p) => p.into_packet(),
Self::ReadDir(p) => p.into_packet(),
Self::Remove(p) => p.into_packet(),
Self::MkDir(p) => p.into_packet(),
Self::RmDir(p) => p.into_packet(),
Self::RealPath(p) => p.into_packet(),
Self::Stat(p) => p.into_packet(),
Self::Rename(p) => p.into_packet(),
Self::ReadLink(p) => p.into_packet(),
Self::Symlink(p) => p.into_packet(),
Self::Status(p) => p.into_packet(),
Self::Handle(p) => p.into_packet(),
Self::Data(p) => p.into_packet(),
Self::Name(p) => p.into_packet(),
Self::Attrs(p) => p.into_packet(),
Self::Extended(p) => p.into_packet(),
Self::ExtendedReply(p) => p.into_packet()
}
}
}