use std::mem::transmute;
use std::hash::Hash;
use std::collections::HashMap;
use dbus_serialize::types::{Value,BasicValue,Path,Signature,Struct,Variant};
pub trait Marshal {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize;
fn get_type(&self) -> String;
}
pub trait BasicMarshal : Marshal { }
pub fn pad_to_multiple (buf: &mut Vec<u8>, len: usize) -> () {
let pad = (len - (buf.len() % len)) % len;
for _ in 0..pad {
buf.push(0);
}
}
fn marshal_int (x: u64, len: usize, buf: &mut Vec<u8>) -> usize {
pad_to_multiple(buf, len);
assert!(len <= 8);
let bytes : [u8; 8] = unsafe { transmute(x.to_le()) };
for i in 0..len {
buf.push(bytes[i]);
}
len
}
fn marshal_double (x: f64, buf: &mut Vec<u8>) -> usize {
let len = 8;
pad_to_multiple(buf, len);
let bytes : [u8; 8] = unsafe { transmute(x) };
for i in 0..len {
buf.push(bytes[i]);
}
len
}
fn marshal_string (x: String, buf: &mut Vec<u8>) -> usize {
let bytes = x.into_bytes();
let len = bytes.len() as u32;
let total_len = len.dbus_encode(buf);
for i in 0..len {
buf.push(bytes[i as usize]);
}
buf.push(0);
total_len + (len as usize) + 1
}
fn marshal_signature (x: String, buf: &mut Vec<u8>) -> usize {
let bytes = x.into_bytes();
let len = bytes.len() as u8;
let total_len = len.dbus_encode(buf);
for i in 0..len {
buf.push(bytes[i as usize]);
}
buf.push(0);
total_len + (len as usize) + 1
}
impl Marshal for u8 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
buf.push(*self);
1
}
fn get_type (&self) -> String {
"y".to_owned()
}
}
impl BasicMarshal for u8 { }
impl Marshal for bool {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
let val = match *self {
true => 1,
false => 0
};
marshal_int(val, 4, buf)
}
fn get_type (&self) -> String {
"b".to_owned()
}
}
impl BasicMarshal for bool { }
impl Marshal for i16 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_int(*self as u64, 2, buf)
}
fn get_type (&self) -> String {
"n".to_owned()
}
}
impl BasicMarshal for i16 { }
impl Marshal for u16 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_int(*self as u64, 2, buf)
}
fn get_type (&self) -> String {
"q".to_owned()
}
}
impl BasicMarshal for u16 { }
impl Marshal for i32 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_int(*self as u64, 4, buf)
}
fn get_type (&self) -> String {
"i".to_owned()
}
}
impl BasicMarshal for i32 { }
impl Marshal for u32 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_int(*self as u64, 4, buf)
}
fn get_type (&self) -> String {
"u".to_owned()
}
}
impl BasicMarshal for u32 { }
impl Marshal for i64 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_int(*self as u64, 8, buf)
}
fn get_type (&self) -> String {
"x".to_owned()
}
}
impl BasicMarshal for i64 { }
impl Marshal for u64 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_int(*self as u64, 8, buf)
}
fn get_type (&self) -> String {
"t".to_owned()
}
}
impl BasicMarshal for u64 { }
impl Marshal for f64 {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_double(*self, buf)
}
fn get_type (&self) -> String {
"d".to_owned()
}
}
impl BasicMarshal for f64 { }
impl<'a> Marshal for &'a str {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_string((*self).to_owned(), buf)
}
fn get_type (&self) -> String {
"s".to_owned()
}
}
impl<'a> Marshal for String {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_string(self.to_owned(), buf)
}
fn get_type (&self) -> String {
"s".to_owned()
}
}
impl<'a> BasicMarshal for &'a str { }
impl Marshal for Path {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_string(self.0.to_owned(), buf)
}
fn get_type (&self) -> String {
"o".to_owned()
}
}
impl BasicMarshal for Path { }
impl Marshal for Signature {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
marshal_signature(self.0.to_owned(), buf)
}
fn get_type (&self) -> String {
"o".to_owned()
}
}
impl BasicMarshal for Signature { }
impl Marshal for Struct {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
pad_to_multiple(buf, 8);
let start_len = buf.len();
for i in &self.objects {
i.dbus_encode(buf);
}
buf.len() - start_len
}
fn get_type(&self) -> String {
self.signature.0.to_owned()
}
}
impl<T: Marshal> Marshal for Vec<T> {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
let mut array_len = 0 as u32;
array_len.dbus_encode(buf);
let start_len = buf.len();
let len_idx = start_len - 4;
for x in self {
x.dbus_encode(buf);
}
array_len = (buf.len() - start_len) as u32;
let mut len_buf = Vec::new();
array_len.dbus_encode(&mut len_buf);
for i in 0..4 {
buf[len_idx+i] = len_buf[i];
}
(array_len as usize) + 4
}
fn get_type(&self) -> String {
"a".to_owned() + &(self.iter().next().unwrap().get_type())
}
}
struct DictEntry<K,V> {
key: K,
value: V
}
impl<K,V> Marshal for DictEntry<K, V>
where K: Clone + Hash + Eq + BasicMarshal,
V: Marshal {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
pad_to_multiple(buf, 8);
let start_len = buf.len();
self.key.dbus_encode(buf);
self.value.dbus_encode(buf);
buf.len() - start_len
}
fn get_type(&self) -> String {
"{".to_owned() + &self.key.get_type() + &self.value.get_type() + "}"
}
}
impl<K,V> Marshal for HashMap<K, V>
where K: Clone + Hash + Eq + BasicMarshal,
V: Clone + Marshal {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
let mut array = Vec::new();
for (key, value) in self {
array.push(DictEntry{key: key.clone(), value: value.clone()});
}
array.dbus_encode(buf)
}
fn get_type(&self) -> String {
"a".to_owned() + "{" + &self.keys().next().unwrap().get_type() + &self.values().next().unwrap().get_type() + "}"
}
}
impl Marshal for Variant {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
let len = self.signature.dbus_encode(buf);
let old_len = buf.len();
self.object.dbus_encode(buf);
len + buf.len() - old_len
}
fn get_type(&self) -> String {
"v".to_owned()
}
}
impl Marshal for BasicValue {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
match *self {
BasicValue::Byte(ref x) => x.dbus_encode(buf),
BasicValue::Boolean(ref x) => x.dbus_encode(buf),
BasicValue::Int16(ref x) => x.dbus_encode(buf),
BasicValue::Uint16(ref x) => x.dbus_encode(buf),
BasicValue::Int32(ref x) => x.dbus_encode(buf),
BasicValue::Uint32(ref x) => x.dbus_encode(buf),
BasicValue::Int64(ref x) => x.dbus_encode(buf),
BasicValue::Uint64(ref x) => x.dbus_encode(buf),
BasicValue::String(ref x) => x.dbus_encode(buf),
BasicValue::ObjectPath(ref x) => x.dbus_encode(buf),
BasicValue::Signature(ref x) => x.dbus_encode(buf),
}
}
fn get_type(&self) -> String {
self.get_signature().to_owned()
}
}
impl BasicMarshal for BasicValue { }
impl Marshal for Value {
fn dbus_encode(&self, buf: &mut Vec<u8>) -> usize {
match *self {
Value::BasicValue(ref x) => x.dbus_encode(buf),
Value::Double(ref x) => x.dbus_encode(buf),
Value::Array(ref x) => x.objects.dbus_encode(buf),
Value::Variant(ref x) => x.dbus_encode(buf),
Value::Struct(ref x) => x.dbus_encode(buf),
Value::Dictionary(ref x) => x.map.dbus_encode(buf)
}
}
fn get_type(&self) -> String {
self.get_signature().to_owned()
}
}
#[test]
fn test_ints () {
let x: u32 = 1;
let x_bytes = vec![0, 0, 0, 0, 1, 0, 0, 0];
let mut buf = vec![0];
let len = x.dbus_encode(&mut buf);
assert_eq!(len, 4);
assert_eq!(buf, x_bytes);
assert_eq!("u", x.get_type());
}
#[test]
fn test_string () {
let x = "abc123";
let x_bytes = vec![6, 0, 0, 0, 'a' as u8, 'b' as u8, 'c' as u8, '1' as u8, '2' as u8, '3' as u8, 0];
let mut x_buf = Vec::new();
let len = x.dbus_encode(&mut x_buf);
assert_eq!(len, x_bytes.len());
assert_eq!(x_buf, x_bytes);
}
#[test]
fn test_array () {
let empty_array : Vec<u8> = Vec::new();
let mut bytes = vec![0, 0, 0, 0];
let mut buf = Vec::new();
let len = empty_array.dbus_encode(&mut buf);
assert_eq!(buf, bytes);
assert_eq!(len, buf.len());
let array : Vec<u32> = vec![1, 2, 3];
bytes = vec![12, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0];
buf = Vec::new();
array.dbus_encode(&mut buf);
assert_eq!(buf, bytes);
}
#[test]
fn test_variant () {
let v = Variant{
object: Box::new(Value::BasicValue(BasicValue::Uint32(42))),
signature: Signature("u".to_owned())
};
assert_eq!(v.get_type(), "v");
let v_bytes = vec![1, 'u' as u8, 0, 0, 42, 0, 0, 0];
let mut buf = Vec::new();
let len = v.dbus_encode(&mut buf);
assert_eq!(len, 8);
assert_eq!(buf, v_bytes);
}