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
68pub trait UnixSocketAddressExtManual: IsA<UnixSocketAddress> + 'static {
69    #[doc(alias = "g_unix_socket_address_get_path")]
70    #[doc(alias = "get_path")]
71    fn path(&self) -> Option<UnixSocketAddressPath<'_>> {
72        use self::UnixSocketAddressPath::*;
73
74        let path = unsafe {
75            let path = ffi::g_unix_socket_address_get_path(self.as_ref().to_glib_none().0);
76            if path.is_null() || self.path_len() == 0 {
77                &[]
78            } else {
79                slice::from_raw_parts(path as *const u8, self.path_len())
80            }
81        };
82        match self.address_type() {
83            UnixSocketAddressType::Anonymous => Some(Anonymous),
84            #[cfg(not(docsrs))]
85            UnixSocketAddressType::Path => Some(Path(path::Path::new(OsStr::from_bytes(path)))),
86            #[cfg(docsrs)]
87            UnixSocketAddressType::Path => unreachable!(),
88            UnixSocketAddressType::Abstract => Some(Abstract(path)),
89            UnixSocketAddressType::AbstractPadded => Some(AbstractPadded(path)),
90            UnixSocketAddressType::Invalid | UnixSocketAddressType::__Unknown(_) => None,
91        }
92    }
93}
94
95impl<O: IsA<UnixSocketAddress>> UnixSocketAddressExtManual for O {}
96
97#[cfg(test)]
98mod test {
99    use super::*;
100
101    // Check the actual path and len are correct and are not the underlying OsString
102    #[test]
103    fn check_path() {
104        let mut os_string = std::ffi::OsString::with_capacity(100);
105        os_string.push("/tmp/foo");
106        let path = os_string.as_ref();
107
108        let addr = UnixSocketAddress::new(path);
109        assert_eq!(addr.path_len(), 8);
110        assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
111
112        let addr = UnixSocketAddress::with_type(UnixSocketAddressPath::Path(path));
113        assert_eq!(addr.path_len(), 8);
114        assert_eq!(addr.path_as_array().unwrap().as_ref(), b"/tmp/foo");
115    }
116}