libsystemd_sys/bus/
vtable.rs

1use super::super::{c_char, size_t};
2use super::{sd_bus_message_handler_t, sd_bus_property_get_t, sd_bus_property_set_t};
3use cfg_if::cfg_if;
4
5// XXX: check this repr, might vary based on platform type sizes
6#[derive(Clone, Copy, Debug)]
7#[repr(u32)]
8pub enum SdBusVtableType {
9    Start = '<' as u32,
10    End = '>' as u32,
11    Method = 'M' as u32,
12    Signal = 'S' as u32,
13    Property = 'P' as u32,
14    WritableProperty = 'W' as u32,
15}
16
17#[derive(Clone, Copy, Debug)]
18#[repr(u64)]
19pub enum SdBusVtableFlag {
20    #[allow(clippy::identity_op)]
21    Deprecated = 1 << 0,
22    Hidden = 1 << 1,
23    Unprivileged = 1 << 2,
24    MethodNoReply = 1 << 3,
25    PropertyConst = 1 << 4,
26    PropertyEmitsChange = 1 << 5,
27    PropertyEmitsInvalidation = 1 << 6,
28    PropertyExplicit = 1 << 7,
29    CapabilityMask = 0xFFFF << 40,
30}
31
32#[derive(Clone, Debug, Default)]
33#[repr(C)]
34pub struct sd_bus_vtable {
35    type_and_flags: u64,
36    // NOTE: assumes that usize == pointer size == size_t
37    union_data: [usize; 5],
38}
39
40// FIXME: all this nasty `target_endian` stuff is because we don't have an abstraction for
41// bitfields. `c2rust-bitfields` only supports little endian. None of the other bitfield crates
42// claim compatibility with C (which is what we require here).
43impl sd_bus_vtable {
44    pub fn type_and_flags(typ: u8, flags: u64) -> u64 {
45        assert!(flags <= ((1 << 56) - 1));
46
47        cfg_if! {
48            if #[cfg(target_endian = "little")] {
49                (flags << 8) | typ as u64
50            } else if #[cfg(target_endian = "big")] {
51                (typ as u64) | (flags << 8)
52            } else {
53                compile_error!("unsupported target_endian")
54            }
55        }
56    }
57
58    pub fn typ(&self) -> u8 {
59        cfg_if! {
60            if #[cfg(target_endian = "little")] {
61                (self.type_and_flags & 0xFF) as u8
62            } else if #[cfg(target_endian = "big")] {
63                (self.type_and_flags >> 56) as u8
64            } else {
65                compile_error!("unsupported target_endian")
66            }
67        }
68    }
69
70    pub fn flags(&self) -> u64 {
71        cfg_if! {
72            if #[cfg(target_endian = "little")] {
73                self.type_and_flags >> 8
74            } else if #[cfg(target_endian = "big")] {
75                self.type_and_flags & 0xFFFFFFFFFFFFFF
76            } else {
77                compile_error!("unsupported target_endian")
78            }
79        }
80    }
81}
82
83#[test]
84fn vtable_bitfield() {
85    let b: sd_bus_vtable = sd_bus_vtable {
86        type_and_flags: sd_bus_vtable::type_and_flags(0xAA, 0xBBCCBB),
87        ..Default::default()
88    };
89
90    assert_eq!(b.typ(), 0xAA);
91    assert_eq!(b.flags(), 0xBBCCBB);
92}
93
94#[test]
95fn size_eq() {
96    use std::mem::size_of;
97    assert_eq!(size_of::<usize>(), size_of::<size_t>());
98    assert_eq!(size_of::<usize>(), size_of::<*const u8>());
99}
100
101#[repr(C)]
102pub struct sd_bus_table_start {
103    pub element_size: size_t,
104}
105
106#[repr(C)]
107pub struct sd_bus_table_method {
108    pub member: *const c_char,
109    pub signature: *const c_char,
110    pub result: *const c_char,
111    pub handler: sd_bus_message_handler_t,
112    pub offset: size_t,
113}
114
115#[repr(C)]
116pub struct sd_bus_table_signal {
117    pub member: *const c_char,
118    pub signature: *const c_char,
119}
120
121#[repr(C)]
122pub struct sd_bus_table_property {
123    pub member: *const c_char,
124    pub signature: *const c_char,
125    pub get: sd_bus_property_get_t,
126    pub set: sd_bus_property_set_t,
127    pub offset: size_t,
128}