#[cfg(not(docsrs))]
use std::ffi::OsStr;
#[cfg(unix)]
#[cfg(not(docsrs))]
use std::os::unix::ffi::OsStrExt;
use std::{path, ptr, slice};
use glib::translate::*;
use crate::{prelude::*, SocketAddress, UnixSocketAddress, UnixSocketAddressType};
#[derive(Debug)]
pub enum UnixSocketAddressPath<'a> {
Path(&'a path::Path),
Anonymous,
Abstract(&'a [u8]),
AbstractPadded(&'a [u8]),
}
impl<'a> UnixSocketAddressPath<'a> {
fn to_type(&self) -> UnixSocketAddressType {
use self::UnixSocketAddressPath::*;
match *self {
Path(_) => UnixSocketAddressType::Path,
Anonymous => UnixSocketAddressType::Anonymous,
Abstract(_) => UnixSocketAddressType::Abstract,
AbstractPadded(_) => UnixSocketAddressType::AbstractPadded,
}
}
}
impl UnixSocketAddress {
#[doc(alias = "g_unix_socket_address_new")]
pub fn new(path: &path::Path) -> UnixSocketAddress {
unsafe {
SocketAddress::from_glib_full(ffi::g_unix_socket_address_new(path.to_glib_none().0))
.unsafe_cast()
}
}
#[doc(alias = "g_unix_socket_address_new_with_type")]
pub fn with_type(address_type: UnixSocketAddressPath) -> Self {
use self::UnixSocketAddressPath::*;
let type_ = address_type.to_type();
let new = |ptr, len| unsafe {
SocketAddress::from_glib_full(ffi::g_unix_socket_address_new_with_type(
ptr,
len,
type_.into_glib(),
))
.unsafe_cast()
};
match address_type {
Path(path) => new(path.to_glib_none().0, -1),
Abstract(path) | AbstractPadded(path) => new(
path.to_glib_none().0 as *mut libc::c_char,
path.len() as i32,
),
Anonymous => new(ptr::null_mut(), 0),
}
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::IsA<super::UnixSocketAddress>> Sealed for T {}
}
pub trait UnixSocketAddressExtManual: sealed::Sealed + IsA<UnixSocketAddress> + 'static {
#[doc(alias = "g_unix_socket_address_get_path")]
#[doc(alias = "get_path")]
fn path(&self) -> Option<UnixSocketAddressPath> {
use self::UnixSocketAddressPath::*;
let path = unsafe {
let path = ffi::g_unix_socket_address_get_path(self.as_ref().to_glib_none().0);
if path.is_null() || self.path_len() == 0 {
&[]
} else {
slice::from_raw_parts(path as *const u8, self.path_len())
}
};
match self.address_type() {
UnixSocketAddressType::Anonymous => Some(Anonymous),
#[cfg(not(docsrs))]
UnixSocketAddressType::Path => Some(Path(path::Path::new(OsStr::from_bytes(path)))),
#[cfg(docsrs)]
UnixSocketAddressType::Path => unreachable!(),
UnixSocketAddressType::Abstract => Some(Abstract(path)),
UnixSocketAddressType::AbstractPadded => Some(AbstractPadded(path)),
UnixSocketAddressType::Invalid | UnixSocketAddressType::__Unknown(_) => None,
}
}
}
impl<O: IsA<UnixSocketAddress>> UnixSocketAddressExtManual for O {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_path() {
let mut os_string = std::ffi::OsString::with_capacity(100);
os_string.push("/tmp/foo");
let path = os_string.as_ref();
let addr = UnixSocketAddress::new(path);
assert_eq!(addr.path_len(), 8);
assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
let addr = UnixSocketAddress::with_type(UnixSocketAddressPath::Path(path));
assert_eq!(addr.path_len(), 8);
assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
}
}