use std::{
fmt,
iter::Extend,
os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd},
};
use crate::{ByteStream, ParseError};
#[allow(dead_code)]
#[derive(Debug)]
pub enum Arg<'a> {
Uint32(u32),
Int32(i32),
Uint64(u64),
Int64(i64),
Float(f32),
Fd(BorrowedFd<'a>),
String(&'a str),
NewId(u64),
Id(u64),
}
impl<'a> fmt::Display for Arg<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Uint32(value) => write!(f, "{value}"),
Self::Int32(value) => write!(f, "{value}"),
Self::Uint64(value) => write!(f, "{value}"),
Self::Int64(value) => write!(f, "{value}"),
Self::Float(value) => write!(f, "{value}"),
Self::Fd(value) => write!(f, "fd {}", value.as_raw_fd()),
Self::String(value) => write!(f, "{value:?}"),
Self::NewId(value) => write!(f, "new_id {value:x}"),
Self::Id(value) => write!(f, "id {value:x}"),
}
}
}
impl<'a> Arg<'a> {
pub fn write<T, U>(&self, buf: &mut T, fds: &mut U)
where
T: Extend<u8>,
U: Extend<OwnedFd>,
{
match self {
Arg::Uint32(value) => buf.extend(value.to_ne_bytes()),
Arg::Int32(value) => buf.extend(value.to_ne_bytes()),
Arg::Uint64(value) => buf.extend(value.to_ne_bytes()),
Arg::Int64(value) => buf.extend(value.to_ne_bytes()),
Arg::Float(value) => buf.extend(value.to_ne_bytes()),
Arg::Fd(value) => fds.extend([value.try_clone_to_owned().unwrap()]),
Arg::String(value) => {
let len = value.len() as u32 + 1;
buf.extend(len.to_ne_bytes());
buf.extend(value.as_bytes().iter().copied());
buf.extend([b'\0']);
if len % 4 != 0 {
buf.extend((0..4 - (len % 4)).map(|_| b'\0'));
}
}
Arg::NewId(value) => buf.extend(value.to_ne_bytes()),
Arg::Id(value) => buf.extend(value.to_ne_bytes()),
}
}
}
pub(crate) trait OwnedArg: Sized {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError>;
fn as_arg(&self) -> Arg<'_>;
fn enum_name(&self) -> Option<(&'static str, &'static str)> {
None
}
}
impl OwnedArg for u32 {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
Ok(Self::from_ne_bytes(buf.read()?))
}
fn as_arg(&self) -> Arg<'_> {
Arg::Uint32(*self)
}
}
impl OwnedArg for i32 {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
Ok(Self::from_ne_bytes(buf.read()?))
}
fn as_arg(&self) -> Arg<'_> {
Arg::Int32(*self)
}
}
impl OwnedArg for u64 {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
Ok(Self::from_ne_bytes(buf.read()?))
}
fn as_arg(&self) -> Arg<'_> {
Arg::Uint64(*self)
}
}
impl OwnedArg for i64 {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
Ok(Self::from_ne_bytes(buf.read()?))
}
fn as_arg(&self) -> Arg<'_> {
Arg::Int64(*self)
}
}
impl OwnedArg for f32 {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
Ok(Self::from_ne_bytes(buf.read()?))
}
fn as_arg(&self) -> Arg<'_> {
Arg::Float(*self)
}
}
impl OwnedArg for OwnedFd {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
buf.read_fd()
}
fn as_arg(&self) -> Arg<'_> {
Arg::Fd(self.as_fd())
}
}
impl OwnedArg for String {
fn parse(buf: &mut ByteStream) -> Result<Self, ParseError> {
let mut len = u32::parse(buf)?;
let bytes = buf.read_n(len as usize - 1)?; let string = String::from_utf8(bytes.collect())?;
buf.read_n(1)?.next(); while len % 4 != 0 {
len += 1;
buf.read::<1>()?;
}
Ok(string)
}
fn as_arg(&self) -> Arg<'_> {
Arg::String(self)
}
}
#[cfg(test)]
mod tests {
}