1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::mem::{transmute, zeroed};
use std::default::Default;
use super::super::{c_char, size_t};
use super::{sd_bus_message_handler_t, sd_bus_property_get_t, sd_bus_property_set_t};

// XXX: check this repr, might vary based on platform type sizes
#[derive(Clone,Copy,Debug)]
#[repr(u32)]
pub enum SdBusVtableType {
    Start = '<' as u32,
    End = '>' as u32,
    Method = 'M' as u32,
    Signal = 'S' as u32,
    Property = 'P' as u32,
    WritableProperty = 'W' as u32,
}

#[derive(Clone, Copy, Debug)]
#[repr(u64)]
pub enum SdBusVtableFlag {
    #[allow(clippy::identity_op)]
    Deprecated = 1 << 0,
    Hidden = 1 << 1,
    Unprivileged = 1 << 2,
    MethodNoReply = 1 << 3,
    PropertyConst = 1 << 4,
    PropertyEmitsChange = 1 << 5,
    PropertyEmitsInvalidation = 1 << 6,
    PropertyExplicit = 1 << 7,
    CapabilityMask = 0xFFFF << 40,
}

#[derive(Clone, Debug)]
#[repr(C)]
pub struct sd_bus_vtable {
    type_and_flags: u64,
    // NOTE: assumes that usize == pointer size == size_t
    union_data: [usize; 5],
}

impl Default for sd_bus_vtable {
    fn default() -> Self {
        unsafe { zeroed() }
    }
}

impl sd_bus_vtable {
    pub fn type_and_flags(typ: u32, flags: u64) -> u64 {
        let mut val = [0u8; 8];
        assert!(typ <= ((1 << 8) - 1));
        assert!(flags <= ((1 << 56) - 1));

        val[0] = typ as u8;
        let flags_raw: [u8; 8] = unsafe { transmute(flags) };
        for i in 0..7 {
            val[i + 1] = flags_raw[i];
        }

        unsafe { transmute(val) }
    }

    // type & flags are stored in a bit field, the ordering of which might change depending on the
    // platform.
    //
    pub fn typ(&self) -> u32 {
        unsafe {
            let raw: *const u8 = &self.type_and_flags as *const _ as *const u8;
            *raw as u32
        }
    }

    pub fn flags(&self) -> u64 {
        // treat the first byte as 0 and the next 7 as their actual values
        let mut val = [0u8; 8];
        unsafe {
            let raw: *const u8 = transmute(&self.type_and_flags);
            for i in 1..8 {
                val[i - 1] = *raw.offset(i as isize);
            }
            transmute(val)
        }
    }
}

#[test]
fn vtable_bitfield() {
    let mut b: sd_bus_vtable = Default::default();

    b.type_and_flags = sd_bus_vtable::type_and_flags(0xAA, 0xBBCCBB);

    assert_eq!(b.typ(), 0xAA);
    assert_eq!(b.flags(), 0xBBCCBB);
}

#[test]
fn size_eq() {
    use std::mem::size_of;
    assert_eq!(size_of::<usize>(), size_of::<size_t>());
    assert_eq!(size_of::<usize>(), size_of::<*const u8>());
}

#[repr(C)]
pub struct sd_bus_table_start {
    pub element_size: size_t,
}

#[repr(C)]
pub struct sd_bus_table_method {
    pub member: *const c_char,
    pub signature: *const c_char,
    pub result: *const c_char,
    pub handler: sd_bus_message_handler_t,
    pub offset: size_t,
}

#[repr(C)]
pub struct sd_bus_table_signal {
    pub member: *const c_char,
    pub signature: *const c_char,
}

#[repr(C)]
pub struct sd_bus_table_property {
    pub member: *const c_char,
    pub signature: *const c_char,
    pub get: sd_bus_property_get_t,
    pub set: sd_bus_property_set_t,
    pub offset: size_t,
}