use crate::ffi_result;
use ffi::{c_char, c_int, c_void, pid_t};
use foreign_types::{foreign_type, ForeignType, ForeignTypeRef};
use std::ffi::CStr;
use std::marker::PhantomData;
use std::mem::{forget, MaybeUninit};
use std::ops::Deref;
use std::os::unix::io::AsRawFd;
use std::ptr;
use std::result;
use std::time::Duration;
use std::{fmt, str};
use super::usec_from_duration;
use utf8_cstr::Utf8CStr;
pub mod types;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub struct ObjectPath {
inner: CStr,
}
impl ObjectPath {
pub fn from_bytes(b: &[u8]) -> result::Result<&ObjectPath, &'static str> {
if b.is_empty() {
return Err("Path must have at least 1 character ('/')");
}
if b[0] != b'/' {
return Err("Path must begin with '/'");
}
for w in b.windows(2) {
let prev = w[0];
let c = w[1];
match c {
b'/' => {
if prev == b'/' {
return Err("Path must not have 2 '/' next to each other");
}
}
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'_' => {
}
b'\0' => {
if prev == b'/' && b.len() != 2 {
return Err("Path must not end in '/' unless it is the root path");
}
return Ok(unsafe { ObjectPath::from_bytes_unchecked(b) });
}
_ => {
return Err("Invalid character in path, only '[A-Z][a-z][0-9]_/' allowed");
}
}
}
Err("Path must be terminated in a '\\0' byte (for use by sd-bus)")
}
#[inline]
pub unsafe fn from_bytes_unchecked(b: &[u8]) -> &ObjectPath {
&*(b as *const [u8] as *const ObjectPath)
}
#[inline]
pub unsafe fn from_ptr_unchecked<'b>(b: *const c_char) -> &'b ObjectPath {
Self::from_bytes_unchecked(CStr::from_ptr(b).to_bytes())
}
}
impl Deref for ObjectPath {
type Target = CStr;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[test]
fn t_path() {
ObjectPath::from_bytes(b"/\0").unwrap();
ObjectPath::from_bytes(b"\0").err().unwrap();
ObjectPath::from_bytes(b"/").err().unwrap();
ObjectPath::from_bytes(b"/h\0").unwrap();
ObjectPath::from_bytes(b"/hello\0").unwrap();
ObjectPath::from_bytes(b"/hello/\0").err().unwrap();
ObjectPath::from_bytes(b"/hello/goodbye/013/4/HA\0").unwrap();
ObjectPath::from_bytes(b"/hello/goodbye/013/4?/HA\0")
.err()
.unwrap();
}
#[derive(Debug)]
pub struct InterfaceName {
inner: CStr,
}
impl InterfaceName {
pub fn from_bytes(b: &[u8]) -> result::Result<&InterfaceName, &'static str> {
if b.is_empty() {
return Err("Name must have more than 0 characters");
}
match b[0] {
b'.' => return Err("Name must not begin with '.'"),
b'A'..=b'Z' | b'a'..=b'z' | b'_' => {
}
_ => return Err("Name must only begin with '[A-Z][a-z]_'"),
}
let mut periods = 0;
for w in b.windows(2) {
let prev = w[0];
let c = w[1];
match c {
b'.' => {
if prev == b'.' {
return Err("Name must not have 2 '.' next to each other");
}
periods += 1;
}
b'A'..=b'Z' | b'a'..=b'z' | b'_' => {
}
b'0'..=b'9' => {
if prev == b'.' {
return Err("Name element must not start with '[0-9]'");
}
}
b'\0' => {
if prev == b'.' && b.len() != 1 {
return Err("Name must not end in '.'");
}
if periods < 1 {
return Err("Name must have at least 2 elements");
}
return Ok(unsafe { InterfaceName::from_bytes_unchecked(b) });
}
_ => {
return Err(
"Invalid character in interface name, only '[A-Z][a-z][0-9]_\\.' \
allowed",
);
}
}
}
Err("Name must be terminated in a '\\0' byte (for use by sd-bus)")
}
#[inline]
pub unsafe fn from_bytes_unchecked(b: &[u8]) -> &InterfaceName {
&*(b as *const [u8] as *const InterfaceName)
}
#[inline]
pub unsafe fn from_ptr_unchecked<'a>(b: *const c_char) -> &'a Self {
Self::from_bytes_unchecked(CStr::from_ptr(b).to_bytes_with_nul())
}
}
impl Deref for InterfaceName {
type Target = CStr;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[test]
fn t_interface() {
InterfaceName::from_bytes(b"12\0").err().unwrap();
InterfaceName::from_bytes(b"a\0").err().unwrap();
InterfaceName::from_bytes(b"a.b\0").unwrap();
InterfaceName::from_bytes(b"a.b.3\0").err().unwrap();
InterfaceName::from_bytes(b"A.Z.xar.yfds.d3490\0").unwrap();
InterfaceName::from_bytes(b"a.b.c\0").unwrap();
InterfaceName::from_bytes(b"a.b.c?\0").err().unwrap();
}
#[derive(Debug)]
pub struct BusName {
inner: CStr,
}
impl BusName {
pub fn from_bytes(b: &[u8]) -> result::Result<&Self, &'static str> {
if b.is_empty() {
return Err("Name must have more than 0 characters");
}
if b.len() > 256 {
return Err("Must be shorter than 255 characters");
}
let mut is_unique = false;
match b[0] {
b'.' => return Err("Name must not begin with '.'"),
b'A'..=b'Z' | b'a'..=b'z' | b'_' | b'-' => {
}
b':' => {
is_unique = true;
}
_ => return Err("Name must only begin with '[A-Z][a-z]_'"),
}
let mut periods = 0;
for w in b.windows(2) {
let prev = w[0];
let c = w[1];
match c {
b'.' => {
if prev == b'.' || prev == b':' {
return Err("Elements may not be empty");
}
periods += 1;
}
b'A'..=b'Z' | b'a'..=b'z' | b'_' | b'-' => {
}
b'0'..=b'9' => {
if prev == b'.' && !is_unique {
return Err("Name element must not start with '[0-9]'");
}
}
b'\0' => {
if prev == b'.' && b.len() != 1 {
return Err("Name must not end in '.'");
}
if periods < 1 {
return Err("Name must have at least 2 elements");
}
return Ok(unsafe { BusName::from_bytes_unchecked(b) });
}
_ => {
return Err(
"Invalid character in bus name, only '[A-Z][a-z][0-9]_\\.' allowed",
);
}
}
}
Err("Name must be terminated in a '\\0' byte (for use by sd-bus)")
}
#[inline]
pub unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self {
&*(b as *const [u8] as *const BusName)
}
#[inline]
pub unsafe fn from_ptr_unchecked<'a>(b: *const c_char) -> &'a Self {
Self::from_bytes_unchecked(CStr::from_ptr(b).to_bytes())
}
}
impl Deref for BusName {
type Target = CStr;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[test]
fn t_busname() {
BusName::from_bytes(b"a.b\0").unwrap();
BusName::from_bytes(b"a.b").err().unwrap();
BusName::from_bytes(b"a\0").err().unwrap();
BusName::from_bytes(b"a.b?\0").err().unwrap();
BusName::from_bytes(b"a.b-c.a0\0").unwrap();
BusName::from_bytes(b"a.b-c.0a\0").err().unwrap();
BusName::from_bytes(b":a.b-c\0").unwrap();
BusName::from_bytes(b":a.b-c.1\0").unwrap();
}
#[derive(Debug)]
pub struct MemberName {
inner: CStr,
}
impl MemberName {
pub fn from_bytes(b: &[u8]) -> result::Result<&Self, &'static str> {
if b.len() < 2 {
return Err("Name must have more than 0 characters");
}
if b.len() > 256 {
return Err("Must be shorter than 255 characters");
}
match b[0] {
b'A'..=b'Z' | b'a'..=b'z' | b'_' => {
}
_ => return Err("Must begin with '[A-Z][a-z]_'"),
}
for c in b {
match *c {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'_' => {
}
b'\0' => return Ok(unsafe { Self::from_bytes_unchecked(b) }),
_ => {
return Err(
"Invalid character in member name, only '[A-Z][a-z][0-9]_' allowed",
);
}
}
}
Err("Name must be terminated in a '\\0' byte (for use by sd-bus)")
}
#[inline]
pub unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self {
&*(b as *const [u8] as *const MemberName)
}
#[inline]
pub unsafe fn from_ptr_unchecked<'a>(b: *const c_char) -> &'a Self {
Self::from_bytes_unchecked(CStr::from_ptr(b).to_bytes())
}
}
impl Deref for MemberName {
type Target = CStr;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[test]
fn t_member_name() {
MemberName::from_bytes(b"abc13\0").unwrap();
MemberName::from_bytes(b"abc.13\0").err().unwrap();
MemberName::from_bytes(b"1234abc\0").err().unwrap();
MemberName::from_bytes(b"abc").err().unwrap();
MemberName::from_bytes(b"\0").err().unwrap();
MemberName::from_bytes(b"a\0").unwrap();
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum MessageType {
MethodCall,
MethodReturn,
MethodError,
Signal,
}
impl MessageType {
pub fn from_raw(raw: u8) -> Self {
match raw as c_int {
ffi::bus::SD_BUS_MESSAGE_METHOD_CALL => MessageType::MethodCall,
ffi::bus::SD_BUS_MESSAGE_METHOD_RETURN => MessageType::MethodReturn,
ffi::bus::SD_BUS_MESSAGE_METHOD_ERROR => MessageType::MethodError,
ffi::bus::SD_BUS_MESSAGE_SIGNAL => MessageType::Signal,
_ => panic!(),
}
}
}
#[repr(C)]
pub struct RawError {
inner: ffi::bus::sd_bus_error,
}
impl RawError {
pub unsafe fn from_ptr<'a>(ptr: *const ffi::bus::sd_bus_error) -> &'a Self {
&*(ptr as *const _ as *const RawError)
}
}
pub struct Error {
raw: RawError,
name_len: usize,
message_len: usize,
}
impl Error {
unsafe fn from_raw(raw: RawError) -> Error {
let n = CStr::from_ptr(raw.inner.name).to_bytes_with_nul().len();
let m = if raw.inner.message.is_null() {
0
} else {
CStr::from_ptr(raw.inner.message).to_bytes_with_nul().len()
};
Error {
raw,
name_len: n,
message_len: m,
}
}
pub fn new(name: &Utf8CStr, message: Option<&Utf8CStr>) -> Error {
let v = RawError::with(name, message);
Error {
raw: v,
name_len: name.len() + 1,
message_len: message.map_or(0, |x| x.len() + 1),
}
}
pub fn name(&self) -> &Utf8CStr {
unsafe { Utf8CStr::from_raw_parts(self.raw.inner.name, self.name_len) }
}
pub fn message(&self) -> Option<&Utf8CStr> {
let p = self.raw.inner.message;
if p.is_null() {
None
} else {
Some(unsafe { Utf8CStr::from_raw_parts(self.raw.inner.message, self.message_len) })
}
}
fn as_ptr(&self) -> *const ffi::bus::sd_bus_error {
self.raw.as_ptr()
}
unsafe fn move_into(self, dest: *mut ffi::bus::sd_bus_error) {
let x = ::std::ptr::read(&self.raw.inner);
forget(self);
*dest = x;
}
}
impl ::std::error::Error for Error {
fn description(&self) -> &str {
match self.message() {
Some(m) => m.as_ref(),
None => self.name().as_ref(),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Error")
.field("name", &self.name())
.field("message", &self.message())
.field("need_free", &self.raw.inner.need_free)
.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.message() {
Some(m) => write!(fmt, "Dbus Error: {}: {}", self.name(), m),
None => write!(fmt, "Dbus Error: {}", self.name()),
}
}
}
impl Default for RawError {
#[inline]
fn default() -> Self {
RawError {
inner: ffi::bus::sd_bus_error {
name: ptr::null(),
message: ptr::null(),
need_free: 0,
},
}
}
}
impl From<ffi::bus::sd_bus_error> for RawError {
fn from(inner: ffi::bus::sd_bus_error) -> Self {
Self { inner }
}
}
impl RawError {
#[inline]
fn new() -> Self {
Default::default()
}
fn into_result(self) -> Result<()> {
if self.is_set() {
Err(unsafe { Error::from_raw(self) })
} else {
Ok(())
}
}
fn with(name: &Utf8CStr, message: Option<&Utf8CStr>) -> Self {
let mut v: Self = Default::default();
v.set(name, message);
v
}
fn set(&mut self, name: &Utf8CStr, message: Option<&Utf8CStr>) {
unsafe {
ffi::bus::sd_bus_error_set(
&mut self.inner,
name.as_ptr(),
message.map_or(ptr::null(), |x| x.as_ptr()),
);
}
}
#[inline]
fn is_set(&self) -> bool {
!self.inner.name.is_null()
}
#[inline]
fn as_mut_ptr(&mut self) -> *mut ffi::bus::sd_bus_error {
&mut self.inner
}
#[inline]
fn as_ptr(&self) -> *const ffi::bus::sd_bus_error {
&self.inner
}
#[inline]
pub fn name(&self) -> Option<&InterfaceName> {
if self.is_set() {
Some(unsafe { InterfaceName::from_ptr_unchecked(self.inner.name) })
} else {
None
}
}
#[inline]
pub fn message(&self) -> Option<&Utf8CStr> {
if self.is_set() {
Some(unsafe { Utf8CStr::from_ptr_unchecked(self.inner.name) })
} else {
None
}
}
#[allow(dead_code)]
#[inline]
pub fn errno(&self) -> Option<c_int> {
if self.is_set() {
Some(unsafe { ffi::bus::sd_bus_error_get_errno(self.as_ptr()) })
} else {
None
}
}
}
impl Drop for RawError {
#[inline]
fn drop(&mut self) {
unsafe { ffi::bus::sd_bus_error_free(&mut self.inner) };
}
}
impl Clone for RawError {
#[inline]
fn clone(&self) -> RawError {
let mut e = MaybeUninit::<ffi::bus::sd_bus_error>::uninit();
unsafe { ffi::bus::sd_bus_error_copy(e.as_mut_ptr(), &self.inner) };
let e = unsafe { e.assume_init() };
e.into()
}
}
impl fmt::Debug for RawError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("RawError")
.field("name", &self.name())
.field("message", &self.message())
.field("need_free", &self.inner.need_free)
.finish()
}
}
impl fmt::Display for RawError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("RawError")
.field("name", &self.name())
.field("message", &self.message())
.field("need_free", &self.inner.need_free)
.finish()
}
}
#[test]
fn t_raw_error() {
let name = Utf8CStr::from_bytes(b"name\0").unwrap();
let message = Utf8CStr::from_bytes(b"error\0").unwrap();
RawError::new().set(name, Some(message))
}
extern "C" fn raw_message_handler<F>(
msg: *mut ffi::bus::sd_bus_message,
userdata: *mut c_void,
ret_error: *mut ffi::bus::sd_bus_error,
) -> c_int
where
F: Fn(&mut MessageRef) -> Result<()>,
{
let m: Box<F> = unsafe { Box::from_raw(userdata as *mut F) };
let e = m(unsafe { MessageRef::from_ptr_mut(msg) });
match e {
Err(e) => {
unsafe { e.move_into(ret_error) }
0
}
Ok(_) => {
0
}
}
}
extern "C" fn raw_destroy_cb_message_handler<F>(userdata: *mut c_void)
where
F: Fn(&mut MessageRef) -> Result<()>,
{
let _: Box<F> = unsafe { Box::from_raw(userdata as *mut F) };
}
foreign_type! {
pub unsafe type Bus {
type CType = ffi::bus::sd_bus;
fn drop = ffi::bus::sd_bus_unref;
fn clone = ffi::bus::sd_bus_ref;
}
}
impl Bus {
#[allow(clippy::should_implement_trait)]
#[inline]
pub fn default() -> crate::Result<Bus> {
let mut b = MaybeUninit::uninit();
ffi_result(unsafe { ffi::bus::sd_bus_default(b.as_mut_ptr()) })?;
Ok(unsafe { Bus::from_ptr(b.assume_init()) })
}
#[inline]
pub fn default_user() -> crate::Result<Bus> {
let mut b = MaybeUninit::uninit();
ffi_result(unsafe { ffi::bus::sd_bus_default_user(b.as_mut_ptr()) })?;
Ok(unsafe { Bus::from_ptr(b.assume_init()) })
}
#[inline]
pub fn default_system() -> super::Result<Bus> {
let mut b = MaybeUninit::uninit();
ffi_result(unsafe { ffi::bus::sd_bus_default_system(b.as_mut_ptr()) })?;
Ok(unsafe { Bus::from_ptr(b.assume_init()) })
}
}
impl fmt::Debug for BusRef {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BusRef")
.field("unique_name", &self.unique_name())
.field("bus_id", &self.bus_id())
.field("scope", &self.scope())
.field("tid", &self.tid())
.field("description", &self.description())
.field("address", &self.address())
.field("fd", &self.fd())
.field("events", &self.events())
.field("n_queued_read", &self.n_queued_read())
.field("n_queued_write", &self.n_queued_write())
.field("method_call_timeout", &self.method_call_timeout())
.finish()
}
}
impl BusRef {
#[inline]
pub fn fd(&self) -> super::Result<c_int> {
ffi_result(unsafe { ffi::bus::sd_bus_get_fd(self.as_ptr()) })
}
#[inline]
pub fn events(&self) -> super::Result<c_int> {
ffi_result(unsafe { ffi::bus::sd_bus_get_events(self.as_ptr()) })
}
#[inline]
pub fn timeout(&self) -> super::Result<u64> {
let mut b = MaybeUninit::uninit();
ffi_result(unsafe { ffi::bus::sd_bus_get_timeout(self.as_ptr(), b.as_mut_ptr()) })?;
let b = unsafe { b.assume_init() };
Ok(b)
}
#[inline]
pub fn process(&mut self) -> super::Result<Option<Option<Message>>> {
let mut b = MaybeUninit::uninit();
let r = ffi_result(unsafe { ffi::bus::sd_bus_process(self.as_ptr(), b.as_mut_ptr()) })?;
if r > 0 {
let b = unsafe { b.assume_init() };
if b.is_null() {
Ok(Some(None))
} else {
Ok(Some(Some(unsafe { Message::from_ptr(b) })))
}
} else {
Ok(None)
}
}
#[inline]
pub fn process_priority(
&mut self,
max_priority: i64,
) -> super::Result<Option<Option<Message>>> {
let mut b = MaybeUninit::uninit();
let r = ffi_result(unsafe {
ffi::bus::sd_bus_process_priority(self.as_ptr(), max_priority, b.as_mut_ptr())
})?;
if r > 0 {
let b = unsafe { b.assume_init() };
if b.is_null() {
Ok(Some(None))
} else {
Ok(Some(Some(unsafe { Message::from_ptr(b) })))
}
} else {
Ok(None)
}
}
#[inline]
pub fn wait(&mut self, timeout: Option<Duration>) -> super::Result<bool> {
Ok(ffi_result(unsafe {
ffi::bus::sd_bus_wait(
self.as_ptr(),
timeout.map(usec_from_duration).unwrap_or(u64::MAX),
)
})? > 0)
}
#[inline]
pub fn unique_name(&self) -> super::Result<&BusName> {
let mut e = MaybeUninit::uninit();
ffi_result(unsafe { ffi::bus::sd_bus_get_unique_name(self.as_ptr(), e.as_mut_ptr()) })?;
let e = unsafe { e.assume_init() };
Ok(unsafe { BusName::from_ptr_unchecked(e) })
}
pub fn scope(&self) -> super::Result<&CStr> {
let mut ret = ptr::null();
ffi_result(unsafe { ffi::bus::sd_bus_get_scope(self.as_ptr(), &mut ret) })?;
Ok(unsafe { CStr::from_ptr(ret) })
}
pub fn tid(&self) -> super::Result<pid_t> {
let mut ret = 0;
ffi_result(unsafe { ffi::bus::sd_bus_get_tid(self.as_ptr(), &mut ret) })?;
Ok(ret)
}
pub fn description(&self) -> super::Result<&CStr> {
let mut ret = ptr::null();
ffi_result(unsafe { ffi::bus::sd_bus_get_description(self.as_ptr(), &mut ret) })?;
Ok(unsafe { CStr::from_ptr(ret) })
}
pub fn address(&self) -> super::Result<&CStr> {
let mut ret = ptr::null();
ffi_result(unsafe { ffi::bus::sd_bus_get_address(self.as_ptr(), &mut ret) })?;
Ok(unsafe { CStr::from_ptr(ret) })
}
pub fn n_queued_write(&self) -> super::Result<u64> {
let mut ret = Default::default();
ffi_result(unsafe { ffi::bus::sd_bus_get_n_queued_write(self.as_ptr(), &mut ret) })?;
Ok(ret)
}
pub fn n_queued_read(&self) -> super::Result<u64> {
let mut ret = Default::default();
ffi_result(unsafe { ffi::bus::sd_bus_get_n_queued_read(self.as_ptr(), &mut ret) })?;
Ok(ret)
}
pub fn method_call_timeout(&self) -> super::Result<u64> {
let mut ret = Default::default();
ffi_result(unsafe { ffi::bus::sd_bus_get_method_call_timeout(self.as_ptr(), &mut ret) })?;
Ok(ret)
}
pub fn bus_id(&self) -> super::Result<super::id128::Id128> {
let mut id: super::id128::Id128 = Default::default();
crate::ffi_result(unsafe { ffi::bus::sd_bus_get_bus_id(self.as_ptr(), id.as_raw_mut()) })?;
Ok(id)
}
#[inline]
pub fn new_signal(
&mut self,
path: &ObjectPath,
interface: &InterfaceName,
member: &MemberName,
) -> super::Result<Message> {
let mut m = MaybeUninit::uninit();
ffi_result(unsafe {
ffi::bus::sd_bus_message_new_signal(
self.as_ptr(),
m.as_mut_ptr(),
path.as_ptr() as *const _,
interface.as_ptr() as *const _,
member.as_ptr() as *const _,
)
})?;
let m = unsafe { m.assume_init() };
Ok(unsafe { Message::from_ptr(m) })
}
#[inline]
pub fn new_method_call(
&mut self,
dest: &BusName,
path: &ObjectPath,
interface: &InterfaceName,
member: &MemberName,
) -> super::Result<Message> {
let mut m = MaybeUninit::uninit();
ffi_result(unsafe {
ffi::bus::sd_bus_message_new_method_call(
self.as_ptr(),
m.as_mut_ptr(),
dest as *const _ as *const _,
path as *const _ as *const _,
interface as *const _ as *const _,
member as *const _ as *const _,
)
})?;
let m = unsafe { m.assume_init() };
Ok(unsafe { Message::from_ptr(m) })
}
#[inline]
pub fn request_name(&mut self, name: &BusName, flags: u64) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_request_name(self.as_ptr(), name as *const _ as *const _, flags)
})?;
Ok(())
}
#[inline]
pub fn request_name_async<F>(
&mut self,
name: &BusName,
flags: u64,
callback: F,
) -> super::Result<()>
where
F: Fn(&mut MessageRef) -> Result<()> + Send + Sync + 'static,
{
let f: extern "C" fn(
*mut ffi::bus::sd_bus_message,
*mut c_void,
*mut ffi::bus::sd_bus_error,
) -> c_int = raw_message_handler::<F>;
let d: extern "C" fn(*mut c_void) = raw_destroy_cb_message_handler::<F>;
let mut slot = ptr::null_mut();
let b = Box::into_raw(Box::new(callback));
match unsafe {
crate::ffi_result(ffi::bus::sd_bus_request_name_async(
self.as_ptr(),
&mut slot,
name as *const _ as *const _,
flags,
Some(f),
b as *mut c_void,
))
} {
Err(e) => {
let _ = unsafe { Box::from_raw(b) };
Err(e)
}
Ok(_) => {
unsafe {
ffi::bus::sd_bus_slot_set_destroy_callback(slot, Some(d));
ffi::bus::sd_bus_slot_set_floating(slot, 1);
}
Ok(())
}
}
}
#[inline]
pub fn release_name(&self, name: &BusName) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_release_name(self.as_ptr(), name as *const _ as *const _)
})?;
Ok(())
}
#[inline]
pub fn add_object<F>(&self, path: &ObjectPath, callback: F) -> super::Result<()>
where
F: Fn(&mut MessageRef) -> Result<()> + Send + Sync + 'static,
{
let f: extern "C" fn(
*mut ffi::bus::sd_bus_message,
*mut c_void,
*mut ffi::bus::sd_bus_error,
) -> c_int = raw_message_handler::<F>;
let d: extern "C" fn(*mut c_void) = raw_destroy_cb_message_handler::<F>;
let mut slot = ptr::null_mut();
let b = Box::into_raw(Box::new(callback));
match crate::ffi_result(unsafe {
ffi::bus::sd_bus_add_object(
self.as_ptr(),
&mut slot,
path as *const _ as *const _,
Some(f),
b as *mut c_void,
)
}) {
Err(e) => {
let _ = unsafe { Box::from_raw(b) };
Err(e)
}
Ok(_) => {
unsafe {
ffi::bus::sd_bus_slot_set_destroy_callback(slot, Some(d));
ffi::bus::sd_bus_slot_set_floating(slot, 1);
}
Ok(())
}
}
}
#[inline]
pub fn add_object_manager(&self, path: &ObjectPath) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_add_object_manager(
self.as_ptr(),
ptr::null_mut(),
path as *const _ as *const _,
)
})?;
Ok(())
}
}
impl AsRawFd for BusRef {
#[inline]
fn as_raw_fd(&self) -> c_int {
self.fd().unwrap()
}
}
foreign_type! {
pub unsafe type Message {
type CType = ffi::bus::sd_bus_message;
fn drop = ffi::bus::sd_bus_message_unref;
fn clone = ffi::bus::sd_bus_message_ref;
}
}
pub struct MessageIter<'a> {
raw: *mut ffi::bus::sd_bus_message,
life: PhantomData<&'a MessageRef>,
}
impl fmt::Debug for MessageRef {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Message")
.field("type", &self.type_())
.field("signature", &self.signature())
.field("path", &self.path())
.field("member", &self.member())
.field("interface", &self.interface())
.field("sender", &self.sender())
.field("destination", &self.destination())
.finish()
}
}
impl MessageRef {
#[inline]
pub fn bus(&self) -> &BusRef {
unsafe { BusRef::from_ptr(ffi::bus::sd_bus_message_get_bus(self.as_ptr() as *mut _)) }
}
#[inline]
pub fn set_destination(&mut self, dest: &BusName) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_message_set_destination(self.as_ptr(), dest as *const _ as *const _)
})?;
Ok(())
}
#[inline]
pub fn set_auto_start(&mut self, yes: bool) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_message_set_auto_start(self.as_ptr(), yes as c_int)
})?;
Ok(())
}
pub fn type_(&self) -> MessageType {
let mut t = 0;
crate::ffi_result(unsafe { ffi::bus::sd_bus_message_get_type(self.as_ptr(), &mut t) })
.unwrap();
MessageType::from_raw(t)
}
pub fn path(&self) -> Option<&CStr> {
let p = unsafe { ffi::bus::sd_bus_message_get_path(self.as_ptr()) };
if p.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(p) })
}
}
pub fn interface(&self) -> Option<&CStr> {
let p = unsafe { ffi::bus::sd_bus_message_get_interface(self.as_ptr()) };
if p.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(p) })
}
}
pub fn member(&self) -> Option<&CStr> {
let p = unsafe { ffi::bus::sd_bus_message_get_member(self.as_ptr()) };
if p.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(p) })
}
}
pub fn sender(&self) -> &CStr {
let p = unsafe { ffi::bus::sd_bus_message_get_sender(self.as_ptr()) };
assert!(!p.is_null());
unsafe { CStr::from_ptr(p) }
}
pub fn destination(&self) -> &CStr {
let p = unsafe { ffi::bus::sd_bus_message_get_destination(self.as_ptr()) };
assert!(!p.is_null());
unsafe { CStr::from_ptr(p) }
}
pub fn signature(&self) -> &CStr {
let p = unsafe { ffi::bus::sd_bus_message_get_signature(self.as_ptr(), 1) };
assert!(!p.is_null());
unsafe { CStr::from_ptr(p) }
}
pub fn is_empty(&self) -> bool {
crate::ffi_result(unsafe { ffi::bus::sd_bus_message_is_empty(self.as_ptr()) }).unwrap() != 0
}
pub fn error(&self) -> &RawError {
unsafe { RawError::from_ptr(ffi::bus::sd_bus_message_get_error(self.as_ptr())) }
}
pub fn errno(&self) -> c_int {
unsafe { ffi::bus::sd_bus_message_get_errno(self.as_ptr()) }
}
pub fn monotonic_usec(&self) -> super::Result<u64> {
let mut usec = 0;
crate::ffi_result(unsafe {
ffi::bus::sd_bus_message_get_monotonic_usec(self.as_ptr(), &mut usec)
})?;
Ok(usec)
}
pub fn realtime_usec(&self) -> super::Result<u64> {
let mut usec = 0;
crate::ffi_result(unsafe {
ffi::bus::sd_bus_message_get_realtime_usec(self.as_ptr(), &mut usec)
})?;
Ok(usec)
}
pub fn seqnum(&self) -> super::Result<u64> {
let mut seqnum = 0;
crate::ffi_result(unsafe {
ffi::bus::sd_bus_message_get_seqnum(self.as_ptr(), &mut seqnum)
})?;
Ok(seqnum)
}
#[inline]
pub fn send(&mut self) -> super::Result<u64> {
let mut m = MaybeUninit::uninit();
ffi_result(unsafe {
ffi::bus::sd_bus_send(ptr::null_mut(), self.as_ptr(), m.as_mut_ptr())
})?;
let m = unsafe { m.assume_init() };
Ok(m)
}
#[inline]
pub fn send_no_reply(&mut self) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_send(ptr::null_mut(), self.as_ptr(), ptr::null_mut())
})?;
Ok(())
}
#[inline]
pub fn send_to(&mut self, dest: &BusName) -> super::Result<u64> {
let mut c = MaybeUninit::uninit();
ffi_result(unsafe {
ffi::bus::sd_bus_send_to(
ptr::null_mut(),
self.as_ptr(),
dest as *const _ as *const _,
c.as_mut_ptr(),
)
})?;
let c = unsafe { c.assume_init() };
Ok(c)
}
#[inline]
pub fn send_to_no_reply(&mut self, dest: &BusName) -> super::Result<()> {
ffi_result(unsafe {
ffi::bus::sd_bus_send_to(
ptr::null_mut(),
self.as_ptr(),
dest as *const _ as *const _,
ptr::null_mut(),
)
})?;
Ok(())
}
#[inline]
pub fn call(&mut self, usec: u64) -> Result<Message> {
let mut r = MaybeUninit::uninit();
let mut e = RawError::new();
unsafe {
ffi::bus::sd_bus_call(
ptr::null_mut(),
self.as_ptr(),
usec,
e.as_mut_ptr(),
r.as_mut_ptr(),
);
}
e.into_result()
.map(|_| unsafe { Message::from_ptr(r.assume_init()) })
}
#[inline]
pub fn call_async<F>(&mut self, callback: F, usec: u64) -> super::Result<()>
where
F: Fn(&mut MessageRef) -> Result<()> + 'static + Sync + Send,
{
let f: extern "C" fn(
*mut ffi::bus::sd_bus_message,
*mut c_void,
*mut ffi::bus::sd_bus_error,
) -> c_int = raw_message_handler::<F>;
let d: extern "C" fn(*mut c_void) = raw_destroy_cb_message_handler::<F>;
let b = Box::into_raw(Box::new(callback));
let mut slot = ptr::null_mut();
match crate::ffi_result(unsafe {
ffi::bus::sd_bus_call_async(
ptr::null_mut(),
&mut slot,
self.as_ptr(),
Some(f),
b as *mut c_void,
usec,
)
}) {
Err(e) => {
let _ = unsafe { Box::from_raw(b) };
Err(e)
}
Ok(_) => {
unsafe {
ffi::bus::sd_bus_slot_set_destroy_callback(slot, Some(d));
ffi::bus::sd_bus_slot_set_floating(slot, 1);
}
Ok(())
}
}
}
#[inline]
pub fn new_method_error(&mut self, error: &Error) -> crate::Result<Message> {
let mut m = MaybeUninit::uninit();
ffi_result(unsafe {
ffi::bus::sd_bus_message_new_method_error(self.as_ptr(), m.as_mut_ptr(), error.as_ptr())
})?;
Ok(unsafe { Message::from_ptr(m.assume_init()) })
}
#[inline]
pub fn new_method_return(&mut self) -> crate::Result<Message> {
let mut m = MaybeUninit::uninit();
ffi_result(unsafe {
ffi::bus::sd_bus_message_new_method_return(self.as_ptr(), m.as_mut_ptr())
})?;
Ok(unsafe { Message::from_ptr(m.assume_init()) })
}
#[inline]
pub unsafe fn append_basic_raw(
&mut self,
dbus_type: u8,
v: *const c_void,
) -> crate::Result<()> {
crate::ffi_result(ffi::bus::sd_bus_message_append_basic(
self.as_ptr(),
dbus_type as c_char,
v,
))?;
Ok(())
}
#[inline]
pub fn append<V: types::ToSdBusMessage>(&mut self, v: V) -> crate::Result<()> {
v.to_message(self)
}
#[inline]
pub fn iter(&mut self) -> crate::Result<MessageIter<'_>> {
ffi_result(unsafe {
ffi::bus::sd_bus_message_peek_type(self.as_ptr(), ptr::null_mut(), ptr::null_mut())
})?;
Ok(MessageIter {
raw: self.as_ptr(),
life: PhantomData,
})
}
}
impl<'a> MessageIter<'a> {
#[inline]
fn as_mut_ptr(&mut self) -> *mut ffi::bus::sd_bus_message {
self.raw
}
#[inline]
pub unsafe fn read_basic_raw<R, T, F: FnOnce(R) -> T>(
&mut self,
dbus_type: u8,
cons: F,
) -> crate::Result<Option<T>>
where
T: 'a,
{
let mut v = MaybeUninit::<R>::uninit();
match crate::ffi_result(ffi::bus::sd_bus_message_read_basic(
self.as_mut_ptr(),
dbus_type as c_char,
v.as_mut_ptr() as *mut _,
)) {
Ok(1) => Ok(Some(cons(v.assume_init()))),
Ok(_) => Ok(None),
Err(e) => Err(e),
}
}
#[inline]
pub fn peek_type(&mut self) -> crate::Result<(c_char, &str)> {
let mut t = MaybeUninit::<c_char>::uninit();
let mut cont = MaybeUninit::<*const c_char>::uninit();
crate::ffi_result(unsafe {
ffi::bus::sd_bus_message_peek_type(self.as_mut_ptr(), t.as_mut_ptr(), cont.as_mut_ptr())
})?;
let cont = unsafe { cont.assume_init() };
let s = if cont.is_null() {
""
} else {
unsafe { str::from_utf8_unchecked(CStr::from_ptr(cont).to_bytes()) }
};
let t = unsafe { t.assume_init() };
Ok((t, s))
}
#[allow(clippy::should_implement_trait)]
pub fn next<V: types::FromSdBusMessage<'a>>(&'a mut self) -> crate::Result<Option<V>> {
V::from_message(self)
}
}