use crate::signature;
use crate::wire::errors::UnmarshalError;
use crate::wire::marshal::traits::SignatureBuffer;
use crate::wire::unmarshal;
use crate::wire::unmarshal::UnmarshalContext;
use crate::wire::util;
use crate::ByteOrder;
use crate::Signature;
use crate::Unmarshal;
use std::borrow::Cow;
impl<'buf, 'fds, E1> Unmarshal<'buf, 'fds> for (E1,)
where
E1: Unmarshal<'buf, 'fds> + Sized,
{
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let padding = ctx.align_to(8)?;
let (bytes, val1) = E1::unmarshal(ctx)?;
Ok((bytes + padding, (val1,)))
}
}
impl<'buf, 'fds, E1, E2> Unmarshal<'buf, 'fds> for (E1, E2)
where
E1: Unmarshal<'buf, 'fds> + Sized,
E2: Unmarshal<'buf, 'fds> + Sized,
{
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let start_offset = ctx.offset;
ctx.align_to(8)?;
let (_bytes, val1) = E1::unmarshal(ctx)?;
ctx.align_to(E2::alignment())?;
let (_bytes, val2) = E2::unmarshal(ctx)?;
let total_bytes = ctx.offset - start_offset;
Ok((total_bytes, (val1, val2)))
}
}
impl<'buf, 'fds, E1, E2, E3> Unmarshal<'buf, 'fds> for (E1, E2, E3)
where
E1: Unmarshal<'buf, 'fds> + Sized,
E2: Unmarshal<'buf, 'fds> + Sized,
E3: Unmarshal<'buf, 'fds> + Sized,
{
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let start_offset = ctx.offset;
ctx.align_to(8)?;
let (_bytes, val1) = E1::unmarshal(ctx)?;
ctx.align_to(E2::alignment())?;
let (_bytes, val2) = E2::unmarshal(ctx)?;
ctx.align_to(E3::alignment())?;
let (_bytes, val3) = E3::unmarshal(ctx)?;
let total_bytes = ctx.offset - start_offset;
Ok((total_bytes, (val1, val2, val3)))
}
}
impl<'buf, 'fds, E1, E2, E3, E4> Unmarshal<'buf, 'fds> for (E1, E2, E3, E4)
where
E1: Unmarshal<'buf, 'fds> + Sized,
E2: Unmarshal<'buf, 'fds> + Sized,
E3: Unmarshal<'buf, 'fds> + Sized,
E4: Unmarshal<'buf, 'fds> + Sized,
{
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let start_offset = ctx.offset;
ctx.align_to(8)?;
let (_bytes, val1) = E1::unmarshal(ctx)?;
ctx.align_to(E2::alignment())?;
let (_bytes, val2) = E2::unmarshal(ctx)?;
ctx.align_to(E3::alignment())?;
let (_bytes, val3) = E3::unmarshal(ctx)?;
ctx.align_to(E4::alignment())?;
let (_bytes, val4) = E4::unmarshal(ctx)?;
let total_bytes = ctx.offset - start_offset;
Ok((total_bytes, (val1, val2, val3, val4)))
}
}
impl<E: Signature> Signature for Vec<E> {
fn signature() -> crate::signature::Type {
crate::signature::Type::Container(crate::signature::Container::Array(Box::new(
E::signature(),
)))
}
#[inline]
fn alignment() -> usize {
<[E]>::alignment()
}
#[inline]
fn sig_str(s_buf: &mut SignatureBuffer) {
<[E]>::sig_str(s_buf)
}
fn has_sig(sig: &str) -> bool {
<[E]>::has_sig(sig)
}
}
impl<E: Signature + Clone> Signature for Cow<'_, [E]> {
fn signature() -> crate::signature::Type {
let e_type = Box::new(E::signature());
crate::signature::Type::Container(crate::signature::Container::Array(e_type))
}
#[inline]
fn alignment() -> usize {
<[E]>::alignment()
}
#[inline]
fn sig_str(s_buf: &mut SignatureBuffer) {
<[E]>::sig_str(s_buf)
}
fn has_sig(sig: &str) -> bool {
<[E]>::has_sig(sig)
}
}
impl<'buf, 'fds> Unmarshal<'buf, 'fds> for &'buf [u8] {
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let padding = ctx.align_to(Self::alignment())?;
let (_, bytes_in_array) = u32::unmarshal(ctx)?;
let elements = &ctx.buf[ctx.offset..ctx.offset + bytes_in_array as usize];
ctx.offset += bytes_in_array as usize;
let total_bytes_used = padding + 4 + bytes_in_array as usize;
Ok((total_bytes_used, elements))
}
}
unsafe fn unmarshal_slice<'a, 'buf, 'fds, E>(
ctx: &'a mut UnmarshalContext<'fds, 'buf>,
) -> unmarshal::UnmarshalResult<&'a [E]>
where
E: Unmarshal<'buf, 'fds>, {
let start_offset = ctx.offset;
ctx.align_to(4)?;
let (_, bytes_in_array) = u32::unmarshal(ctx)?;
let bytes_in_array = bytes_in_array as usize;
let alignment = E::alignment();
ctx.align_to(alignment)?;
if bytes_in_array % alignment != 0 {
return Err(UnmarshalError::NotAllBytesUsed);
}
let elem_cnt = bytes_in_array / alignment;
let ptr = &ctx.buf[ctx.offset..] as *const [u8] as *const E;
let slice = std::slice::from_raw_parts(ptr, elem_cnt);
ctx.offset += bytes_in_array;
Ok((ctx.offset - start_offset, slice))
}
impl<'buf, 'fds, E: Unmarshal<'buf, 'fds> + Clone> Unmarshal<'buf, 'fds> for Cow<'buf, [E]> {
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
unsafe {
if E::valid_slice(ctx.byteorder) {
let (used, src): (_, &[E]) = unmarshal_slice(ctx)?;
let l_expand: &'buf [E] = std::mem::transmute(src);
return Ok((used, Cow::Borrowed(l_expand)));
}
}
Vec::unmarshal(ctx).map(|o| (o.0, Cow::Owned(o.1)))
}
}
impl<'buf, 'fds, E: Unmarshal<'buf, 'fds>> Unmarshal<'buf, 'fds> for Vec<E> {
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
unsafe {
if E::valid_slice(ctx.byteorder) {
let (used, src) = unmarshal_slice::<E>(ctx)?;
let mut ret = Vec::with_capacity(src.len());
let dst = ret.as_mut_ptr();
std::ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len());
ret.set_len(src.len());
return Ok((used, ret));
}
}
let start_offset = ctx.offset;
ctx.align_to(4)?;
let (_, bytes_in_array) = u32::unmarshal(ctx)?;
ctx.align_to(E::alignment())?;
let mut elements = Vec::new();
let mut bytes_used_counter = 0;
while bytes_used_counter < bytes_in_array as usize {
if ctx.offset >= ctx.buf.len() {
return Err(UnmarshalError::NotEnoughBytes);
}
let elem_padding = util::align_offset(E::alignment(), ctx.buf, ctx.offset)?;
bytes_used_counter += elem_padding;
ctx.offset += elem_padding;
let (bytes_used, element) = E::unmarshal(ctx)?;
elements.push(element);
bytes_used_counter += bytes_used;
}
let total_bytes_used = ctx.offset - start_offset;
Ok((total_bytes_used, elements))
}
}
impl<'buf, 'fds, K: Unmarshal<'buf, 'fds> + std::hash::Hash + Eq, V: Unmarshal<'buf, 'fds>>
Unmarshal<'buf, 'fds> for std::collections::HashMap<K, V>
{
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let start_offset = ctx.offset;
ctx.align_to(4)?;
let (_, bytes_in_array) = u32::unmarshal(ctx)?;
ctx.align_to(8)?;
let mut map = std::collections::HashMap::new();
let mut bytes_used_counter = 0;
while bytes_used_counter < bytes_in_array as usize {
if ctx.offset >= ctx.buf.len() {
return Err(UnmarshalError::NotEnoughBytes);
}
let elem_padding = util::align_offset(8, ctx.buf, ctx.offset)?;
bytes_used_counter += elem_padding;
ctx.offset += elem_padding;
let (key_bytes_used, key) = K::unmarshal(ctx)?;
bytes_used_counter += key_bytes_used;
let val_padding = util::align_offset(V::alignment(), ctx.buf, ctx.offset)?;
bytes_used_counter += val_padding;
ctx.offset += val_padding;
let (val_bytes_used, val) = V::unmarshal(ctx)?;
bytes_used_counter += val_bytes_used;
map.insert(key, val);
}
let total_bytes_used = ctx.offset - start_offset;
Ok((total_bytes_used, map))
}
}
#[derive(Debug)]
pub struct Variant<'fds, 'buf> {
pub(crate) sig: signature::Type,
pub(crate) byteorder: ByteOrder,
pub(crate) offset: usize,
pub(crate) buf: &'buf [u8],
pub(crate) fds: &'fds [crate::wire::UnixFd],
}
impl<'buf, 'fds> Variant<'fds, 'buf> {
pub fn get_value_sig(&self) -> &signature::Type {
&self.sig
}
pub fn get<T: Unmarshal<'buf, 'fds>>(&self) -> Result<T, UnmarshalError> {
if self.sig != T::signature() {
return Err(UnmarshalError::WrongSignature);
}
let mut ctx = UnmarshalContext {
byteorder: self.byteorder,
offset: self.offset,
buf: self.buf,
fds: self.fds,
};
T::unmarshal(&mut ctx).map(|r| r.1)
}
}
impl Signature for Variant<'_, '_> {
fn signature() -> signature::Type {
signature::Type::Container(signature::Container::Variant)
}
fn alignment() -> usize {
Variant::signature().get_alignment()
}
#[inline]
fn sig_str(s_buf: &mut SignatureBuffer) {
s_buf.push_static("v");
}
fn has_sig(sig: &str) -> bool {
sig.starts_with('v')
}
}
impl<'buf, 'fds> Unmarshal<'buf, 'fds> for Variant<'fds, 'buf> {
fn unmarshal(ctx: &mut UnmarshalContext<'fds, 'buf>) -> unmarshal::UnmarshalResult<Self> {
let start_offset = ctx.offset;
let (sig_bytes, desc) = util::unmarshal_signature(&ctx.buf[ctx.offset..])?;
ctx.offset += sig_bytes;
let mut sigs = match signature::Type::parse_description(desc) {
Ok(sigs) => sigs,
Err(_) => return Err(UnmarshalError::WrongSignature),
};
if sigs.len() != 1 {
return Err(UnmarshalError::WrongSignature);
}
let sig = sigs.remove(0);
ctx.align_to(sig.get_alignment())?;
let start_loc = ctx.offset;
let val_bytes = crate::wire::validate_raw::validate_marshalled(
ctx.byteorder,
ctx.offset,
ctx.buf,
&sig,
)
.map_err(|e| e.1)?;
ctx.offset += val_bytes;
let total_bytes = ctx.offset - start_offset;
Ok((
total_bytes,
Variant {
sig,
buf: &ctx.buf[..ctx.offset],
offset: start_loc,
byteorder: ctx.byteorder,
fds: ctx.fds,
},
))
}
}