use crate::wire::marshal::MarshalContext;
mod base;
mod container;
pub use base::*;
pub use container::*;
pub trait Marshal: Signature {
fn marshal(&self, ctx: &mut MarshalContext) -> Result<(), crate::wire::errors::MarshalError>;
fn marshal_as_variant(
&self,
ctx: &mut MarshalContext,
) -> Result<(), crate::wire::errors::MarshalError> {
let mut sig = SignatureBuffer::new();
Self::sig_str(&mut sig);
if sig.len() > 255 {
let sig_err = crate::signature::Error::SignatureTooLong;
return Err(sig_err.into());
}
debug_assert!(crate::params::validation::validate_signature(&sig).is_ok());
crate::wire::util::write_signature(&sig, ctx.buf);
self.marshal(ctx)
}
}
#[derive(Debug)]
pub struct SignatureBuffer(Cow<'static, str>);
impl SignatureBuffer {
#[inline]
pub fn new() -> Self {
Self(Cow::Borrowed(""))
}
#[inline]
pub fn push_static(&mut self, sig: &'static str) {
match &mut self.0 {
Cow::Borrowed("") => self.0 = Cow::Borrowed(sig),
Cow::Owned(s) if s.capacity() == 0 => self.0 = Cow::Borrowed(sig),
cow => cow.to_mut().push_str(sig),
}
}
#[inline]
pub fn push_str(&mut self, sig: &str) {
self.0.to_mut().push_str(sig);
}
#[inline]
pub fn to_string_mut(&mut self) -> &mut String {
self.0.to_mut()
}
#[inline]
pub fn clear(&mut self) {
match &mut self.0 {
Cow::Borrowed(_) => *self = Self::new(),
Cow::Owned(s) => s.clear(),
}
}
#[inline]
pub fn from_string(sig: String) -> Self {
Self(Cow::Owned(sig))
}
#[inline]
pub fn as_str(&self) -> &str {
&self.0
}
pub fn truncate(&mut self, new_len: usize) -> Result<(), crate::params::validation::Error> {
if new_len > 0 {
crate::params::validate_signature(&self.0.as_ref()[0..new_len])?;
}
self.0.to_mut().truncate(new_len);
Ok(())
}
}
impl std::ops::Deref for SignatureBuffer {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl AsRef<str> for SignatureBuffer {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Default for SignatureBuffer {
#[inline]
fn default() -> Self {
Self::new()
}
}
use std::borrow::Cow;
pub trait Signature {
fn signature() -> crate::signature::Type;
fn alignment() -> usize;
#[inline]
unsafe fn valid_slice(_bo: crate::ByteOrder) -> bool {
false
}
fn sig_str(s_buf: &mut SignatureBuffer) {
let s_buf = s_buf.to_string_mut();
let typ = Self::signature();
typ.to_str(s_buf);
}
fn has_sig(sig: &str) -> bool {
let mut s_buf = SignatureBuffer::new();
Self::sig_str(&mut s_buf);
sig == s_buf.as_str()
}
}
impl<S: Signature> Signature for &S {
fn signature() -> crate::signature::Type {
S::signature()
}
fn alignment() -> usize {
S::alignment()
}
fn sig_str(s_buf: &mut SignatureBuffer) {
S::sig_str(s_buf)
}
fn has_sig(sig: &str) -> bool {
S::has_sig(sig)
}
}
impl<P: Marshal> Marshal for &P {
fn marshal(&self, ctx: &mut MarshalContext) -> Result<(), crate::wire::errors::MarshalError> {
(*self).marshal(ctx)
}
}
#[cfg(test)]
mod test {
use crate::wire::marshal::MarshalContext;
use crate::wire::ObjectPath;
use crate::wire::SignatureWrapper;
#[test]
fn test_trait_signature_creation() {
let mut msg = crate::message_builder::MarshalledMessage::new();
let body = &mut msg.body;
body.push_param("a").unwrap();
body.push_param(ObjectPath::new("/a/b").unwrap()).unwrap();
body.push_param(SignatureWrapper::new("(a{su})").unwrap())
.unwrap();
let fd = crate::wire::UnixFd::new(nix::unistd::dup(1).unwrap());
body.push_param(&fd).unwrap();
body.push_param(true).unwrap();
body.push_param(0u8).unwrap();
body.push_param(0u16).unwrap();
body.push_param(0u32).unwrap();
body.push_param(0u64).unwrap();
body.push_param(0i16).unwrap();
body.push_param(0i32).unwrap();
body.push_param(0i64).unwrap();
body.push_param(&[0u8][..]).unwrap();
let map: std::collections::HashMap<String, (u64, u32, u16, u8)> =
std::collections::HashMap::new();
body.push_param(&map).unwrap();
assert_eq!("soghbyqutnixaya{s(tuqy)}", msg.get_sig());
}
#[test]
fn test_empty_array_padding() {
use crate::wire::marshal::container::marshal_container_param;
let mut msg = crate::message_builder::MarshalledMessage::new();
let body = &mut msg.body;
let empty = vec![0u64; 0];
body.push_param(&empty[..]).unwrap();
let empty = crate::params::Container::make_array_with_sig(
crate::signature::Type::Base(crate::signature::Base::Uint64),
empty.into_iter(),
)
.unwrap();
let mut fds = Vec::new();
let mut buf = Vec::new();
let mut ctx = MarshalContext {
fds: &mut fds,
buf: &mut buf,
byteorder: crate::ByteOrder::LittleEndian,
};
marshal_container_param(&empty, &mut ctx).unwrap();
assert_eq!(msg.get_buf(), &[0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(buf.as_slice(), &[0, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn test_variant_marshalling() {
let mut msg = crate::message_builder::MarshalledMessage::new();
let body = &mut msg.body;
let original = (100u64, "ABCD", true);
body.push_variant(original).unwrap();
assert_eq!(
msg.get_buf(),
&[
5, b'(', b't', b's', b'b', b')', b'\0', 0, 100, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
b'A', b'B', b'C', b'D', b'\0', 0, 0, 0, 1, 0, 0, 0
]
)
}
}