[go: up one dir, main page]

gio/
unix_socket_address.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(not(docsrs))]
4use std::ffi::OsStr;
5#[cfg(unix)]
6#[cfg(not(docsrs))]
7use std::os::unix::ffi::OsStrExt;
8use std::{path, ptr, slice};
9
10use glib::translate::*;
11
12use crate::{ffi, prelude::*, SocketAddress, UnixSocketAddress, UnixSocketAddressType};
13
14#[derive(Debug)]
15pub enum UnixSocketAddressPath<'a> {
16    Path(&'a path::Path),
17    Anonymous,
18    Abstract(&'a [u8]),
19    AbstractPadded(&'a [u8]),
20}
21
22impl UnixSocketAddressPath<'_> {
23    fn to_type(&self) -> UnixSocketAddressType {
24        use self::UnixSocketAddressPath::*;
25
26        match *self {
27            Path(_) => UnixSocketAddressType::Path,
28            Anonymous => UnixSocketAddressType::Anonymous,
29            Abstract(_) => UnixSocketAddressType::Abstract,
30            AbstractPadded(_) => UnixSocketAddressType::AbstractPadded,
31        }
32    }
33}
34
35impl UnixSocketAddress {
36    #[doc(alias = "g_unix_socket_address_new")]
37    pub fn new(path: &path::Path) -> UnixSocketAddress {
38        unsafe {
39            SocketAddress::from_glib_full(ffi::g_unix_socket_address_new(path.to_glib_none().0))
40                .unsafe_cast()
41        }
42    }
43
44    #[doc(alias = "g_unix_socket_address_new_with_type")]
45    pub fn with_type(address_type: UnixSocketAddressPath) -> Self {
46        use self::UnixSocketAddressPath::*;
47
48        let type_ = address_type.to_type();
49        let new = |ptr, len| unsafe {
50            SocketAddress::from_glib_full(ffi::g_unix_socket_address_new_with_type(
51                ptr,
52                len,
53                type_.into_glib(),
54            ))
55            .unsafe_cast()
56        };
57        match address_type {
58            Path(path) => new(path.to_glib_none().0, -1),
59            Abstract(path) | AbstractPadded(path) => new(
60                path.to_glib_none().0 as *mut libc::c_char,
61                path.len() as i32,
62            ),
63            Anonymous => new(ptr::null_mut(), 0),
64        }
65    }
66}
67
68mod sealed {
69    pub trait Sealed {}
70    impl<T: super::IsA<super::UnixSocketAddress>> Sealed for T {}
71}
72
73pub trait UnixSocketAddressExtManual: sealed::Sealed + IsA<UnixSocketAddress> + 'static {
74    #[doc(alias = "g_unix_socket_address_get_path")]
75    #[doc(alias = "get_path")]
76    fn path(&self) -> Option<UnixSocketAddressPath> {
77        use self::UnixSocketAddressPath::*;
78
79        let path = unsafe {
80            let path = ffi::g_unix_socket_address_get_path(self.as_ref().to_glib_none().0);
81            if path.is_null() || self.path_len() == 0 {
82                &[]
83            } else {
84                slice::from_raw_parts(path as *const u8, self.path_len())
85            }
86        };
87        match self.address_type() {
88            UnixSocketAddressType::Anonymous => Some(Anonymous),
89            #[cfg(not(docsrs))]
90            UnixSocketAddressType::Path => Some(Path(path::Path::new(OsStr::from_bytes(path)))),
91            #[cfg(docsrs)]
92            UnixSocketAddressType::Path => unreachable!(),
93            UnixSocketAddressType::Abstract => Some(Abstract(path)),
94            UnixSocketAddressType::AbstractPadded => Some(AbstractPadded(path)),
95            UnixSocketAddressType::Invalid | UnixSocketAddressType::__Unknown(_) => None,
96        }
97    }
98}
99
100impl<O: IsA<UnixSocketAddress>> UnixSocketAddressExtManual for O {}
101
102#[cfg(test)]
103mod test {
104    use super::*;
105
106    // Check the actual path and len are correct and are not the underlying OsString
107    #[test]
108    fn check_path() {
109        let mut os_string = std::ffi::OsString::with_capacity(100);
110        os_string.push("/tmp/foo");
111        let path = os_string.as_ref();
112
113        let addr = UnixSocketAddress::new(path);
114        assert_eq!(addr.path_len(), 8);
115        assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
116
117        let addr = UnixSocketAddress::with_type(UnixSocketAddressPath::Path(path));
118        assert_eq!(addr.path_len(), 8);
119        assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
120    }
121}