Coverage Report

Created: 2025-08-28 06:06

/rust/registry/src/index.crates.io-6f17d22bba15001f/dbus-0.9.7/src/strings.rs
Line
Count
Source (jump to first uncovered line)
1
//! This module contains strings with a specific format, such as a valid
2
//! Interface name, a valid Error name, etc.
3
//!
4
//! (The internal representation of these strings are `Cow<str>`, but with a \0 byte
5
//! at the end to use it libdbus calls without extra allocations. This is usually nothing
6
//! you have to worry about.)
7
8
use std::{str, fmt, ops, default, hash};
9
use std::ffi::{CStr, CString};
10
use std::borrow::{Borrow, Cow};
11
use std::os::raw::c_char;
12
13
#[cfg(not(feature = "no-string-validation"))]
14
use crate::Error;
15
#[cfg(not(feature = "no-string-validation"))]
16
use crate::ffi;
17
18
macro_rules! cstring_wrapper {
19
    ($t: ident, $s: ident) => {
20
21
impl<'m> $t<'m> {
22
    #[cfg(feature = "no-string-validation")]
23
    fn check_valid(_: *const c_char) -> Result<(), String> { Ok(()) }
24
25
    #[cfg(not(feature = "no-string-validation"))]
26
0
    fn check_valid(c: *const c_char) -> Result<(), String> {
27
0
        let mut e = Error::empty();
28
0
        let b = unsafe { ffi::$s(c, e.get_mut()) };
29
0
        if b != 0 { Ok(()) } else { Err(e.message().unwrap().into()) }
30
0
    }
Unexecuted instantiation: <dbus::strings::Signature>::check_valid
Unexecuted instantiation: <dbus::strings::Path>::check_valid
Unexecuted instantiation: <dbus::strings::Member>::check_valid
Unexecuted instantiation: <dbus::strings::Interface>::check_valid
Unexecuted instantiation: <dbus::strings::BusName>::check_valid
Unexecuted instantiation: <dbus::strings::ErrorName>::check_valid
31
32
    /// Creates a new instance of this struct.
33
    ///
34
    /// Note: If the no-string-validation feature is activated, this string
35
    /// will not be checked for conformance with the D-Bus specification.
36
0
    pub fn new<S: Into<String>>(s: S) -> Result<$t<'m>, String> {
37
0
        let mut s = s.into();
38
0
        s.push_str("\0");
39
0
        unsafe { $t::check_valid(CStr::from_bytes_with_nul_unchecked(s.as_bytes()).as_ptr() as *const c_char)?; }
40
0
        Ok(Self(Cow::Owned(s)))
41
0
    }
Unexecuted instantiation: <dbus::strings::Signature>::new::<alloc::string::String>
Unexecuted instantiation: <dbus::strings::Signature>::new::<&str>
Unexecuted instantiation: <dbus::strings::Path>::new::<alloc::string::String>
Unexecuted instantiation: <dbus::strings::Path>::new::<&str>
Unexecuted instantiation: <dbus::strings::Member>::new::<alloc::string::String>
Unexecuted instantiation: <dbus::strings::Member>::new::<&str>
Unexecuted instantiation: <dbus::strings::Interface>::new::<alloc::string::String>
Unexecuted instantiation: <dbus::strings::Interface>::new::<&str>
Unexecuted instantiation: <dbus::strings::BusName>::new::<alloc::string::String>
Unexecuted instantiation: <dbus::strings::BusName>::new::<&str>
Unexecuted instantiation: <dbus::strings::ErrorName>::new::<alloc::string::String>
Unexecuted instantiation: <dbus::strings::ErrorName>::new::<&str>
42
43
    /// Creates a new instance of this struct. If you end it with \0,
44
    /// it can borrow the slice without extra allocation.
45
    ///
46
    /// Note: If the no-string-validation feature is activated, this string
47
    /// will not be checked for conformance with the D-Bus specification.
48
0
    pub fn from_slice(s: &'m str) -> Result<$t<'m>, String> {
49
0
        let ss = s.as_bytes();
50
0
        if ss.len() == 0 || ss[ss.len()-1] != 0 { return $t::new(s) };
51
0
        $t::check_valid(s.as_ptr() as *const c_char).map(|_| {
52
0
            unsafe { Self::from_slice_unchecked(s) }
53
0
        })
Unexecuted instantiation: <dbus::strings::Signature>::from_slice::{closure#0}
Unexecuted instantiation: <dbus::strings::Path>::from_slice::{closure#0}
Unexecuted instantiation: <dbus::strings::Member>::from_slice::{closure#0}
Unexecuted instantiation: <dbus::strings::Interface>::from_slice::{closure#0}
Unexecuted instantiation: <dbus::strings::BusName>::from_slice::{closure#0}
Unexecuted instantiation: <dbus::strings::ErrorName>::from_slice::{closure#0}
54
0
    }
Unexecuted instantiation: <dbus::strings::Signature>::from_slice
Unexecuted instantiation: <dbus::strings::Path>::from_slice
Unexecuted instantiation: <dbus::strings::Member>::from_slice
Unexecuted instantiation: <dbus::strings::Interface>::from_slice
Unexecuted instantiation: <dbus::strings::BusName>::from_slice
Unexecuted instantiation: <dbus::strings::ErrorName>::from_slice
55
56
    /// This function creates a new instance of this struct, without checking.
57
    /// It's up to you to guarantee that s ends with a \0 and is valid.
58
0
    pub unsafe fn from_slice_unchecked(s: &'m str) -> $t<'m> {
59
0
        let ss = s.as_bytes();
60
0
        debug_assert!(ss[ss.len()-1] == 0);
61
0
        $t(Cow::Borrowed(s))
62
0
    }
Unexecuted instantiation: <dbus::strings::ErrorName>::from_slice_unchecked
Unexecuted instantiation: <dbus::strings::BusName>::from_slice_unchecked
Unexecuted instantiation: <dbus::strings::Path>::from_slice_unchecked
Unexecuted instantiation: <dbus::strings::Interface>::from_slice_unchecked
Unexecuted instantiation: <dbus::strings::Member>::from_slice_unchecked
Unexecuted instantiation: <dbus::strings::Signature>::from_slice_unchecked
63
64
    /// View this struct as a CStr.
65
    ///
66
    /// Note: As of dbus 0.9, this is made private to be able to make it easier for a potential
67
    /// native implementation using "str" instead of "cstr".
68
0
    pub (crate) fn as_cstr(&self) -> &CStr {
69
0
        unsafe {
70
0
            CStr::from_bytes_with_nul_unchecked(self.0.as_bytes())
71
0
        }
72
0
    }
Unexecuted instantiation: <dbus::strings::BusName>::as_cstr
Unexecuted instantiation: <dbus::strings::Path>::as_cstr
Unexecuted instantiation: <dbus::strings::Member>::as_cstr
Unexecuted instantiation: <dbus::strings::Interface>::as_cstr
Unexecuted instantiation: <dbus::strings::ErrorName>::as_cstr
Unexecuted instantiation: <dbus::strings::Signature>::as_cstr
73
74
    #[allow(dead_code)]
75
0
    pub (crate) fn as_ptr(&self) -> *const c_char { self.as_cstr().as_ptr() }
Unexecuted instantiation: <dbus::strings::Path>::as_ptr
Unexecuted instantiation: <dbus::strings::Member>::as_ptr
Unexecuted instantiation: <dbus::strings::Interface>::as_ptr
Unexecuted instantiation: <dbus::strings::BusName>::as_ptr
Unexecuted instantiation: <dbus::strings::ErrorName>::as_ptr
Unexecuted instantiation: <dbus::strings::Signature>::as_ptr
76
77
    /// Makes sure this string does not contain borrows.
78
0
    pub fn into_static(self) -> $t<'static> {
79
0
        $t(Cow::Owned(self.0.into_owned()))
80
0
    }
Unexecuted instantiation: <dbus::strings::Signature>::into_static
Unexecuted instantiation: <dbus::strings::Path>::into_static
Unexecuted instantiation: <dbus::strings::Member>::into_static
Unexecuted instantiation: <dbus::strings::Interface>::into_static
Unexecuted instantiation: <dbus::strings::BusName>::into_static
Unexecuted instantiation: <dbus::strings::ErrorName>::into_static
81
82
    /// Converts this struct to a CString.
83
0
    pub fn into_cstring(self) -> CString {
84
0
        // Change this when https://github.com/rust-lang/rust/issues/73179 is on stable.
85
0
        let mut x: Vec<u8> = self.0.into_owned().into();
86
0
        x.pop();
87
0
        CString::new(x).unwrap()
88
0
    }
Unexecuted instantiation: <dbus::strings::Signature>::into_cstring
Unexecuted instantiation: <dbus::strings::Path>::into_cstring
Unexecuted instantiation: <dbus::strings::Member>::into_cstring
Unexecuted instantiation: <dbus::strings::Interface>::into_cstring
Unexecuted instantiation: <dbus::strings::BusName>::into_cstring
Unexecuted instantiation: <dbus::strings::ErrorName>::into_cstring
89
}
90
91
/*
92
/// #Panics
93
///
94
/// If given string is not valid.
95
/// impl<S: Into<Vec<u8>>> From<S> for $t { fn from(s: S) -> $t { $t::new(s).unwrap() } }
96
*/
97
98
/// #Panics
99
///
100
/// If given string is not valid.
101
0
impl<'m> From<String> for $t<'m> { fn from(s: String) -> $t<'m> { $t::new(s).unwrap() } }
Unexecuted instantiation: <dbus::strings::Signature as core::convert::From<alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::Path as core::convert::From<alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::Member as core::convert::From<alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::Interface as core::convert::From<alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::BusName as core::convert::From<alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::ErrorName as core::convert::From<alloc::string::String>>::from
102
103
/// #Panics
104
///
105
/// If given string is not valid.
106
0
impl<'m> From<&'m String> for $t<'m> { fn from(s: &'m String) -> $t<'m> { $t::from_slice(s).unwrap() } }
Unexecuted instantiation: <dbus::strings::Signature as core::convert::From<&alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::Path as core::convert::From<&alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::Member as core::convert::From<&alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::Interface as core::convert::From<&alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::BusName as core::convert::From<&alloc::string::String>>::from
Unexecuted instantiation: <dbus::strings::ErrorName as core::convert::From<&alloc::string::String>>::from
107
108
/// #Panics
109
///
110
/// If given string is not valid.
111
0
impl<'m> From<&'m str> for $t<'m> { fn from(s: &'m str) -> $t<'m> { $t::from_slice(s).unwrap() } }
Unexecuted instantiation: <dbus::strings::Signature as core::convert::From<&str>>::from
Unexecuted instantiation: <dbus::strings::Path as core::convert::From<&str>>::from
Unexecuted instantiation: <dbus::strings::Member as core::convert::From<&str>>::from
Unexecuted instantiation: <dbus::strings::Interface as core::convert::From<&str>>::from
Unexecuted instantiation: <dbus::strings::BusName as core::convert::From<&str>>::from
Unexecuted instantiation: <dbus::strings::ErrorName as core::convert::From<&str>>::from
112
113
/// #Panics
114
///
115
/// If given string is not valid.
116
impl<'m> From<&'m CStr> for $t<'m> {
117
0
    fn from(s: &'m CStr) -> $t<'m> {
118
0
        let x = str::from_utf8(s.to_bytes_with_nul()).unwrap();
119
0
        $t::from_slice(x).unwrap()
120
0
    }
Unexecuted instantiation: <dbus::strings::Signature as core::convert::From<&core::ffi::c_str::CStr>>::from
Unexecuted instantiation: <dbus::strings::Path as core::convert::From<&core::ffi::c_str::CStr>>::from
Unexecuted instantiation: <dbus::strings::Member as core::convert::From<&core::ffi::c_str::CStr>>::from
Unexecuted instantiation: <dbus::strings::Interface as core::convert::From<&core::ffi::c_str::CStr>>::from
Unexecuted instantiation: <dbus::strings::BusName as core::convert::From<&core::ffi::c_str::CStr>>::from
Unexecuted instantiation: <dbus::strings::ErrorName as core::convert::From<&core::ffi::c_str::CStr>>::from
121
}
122
123
0
impl<'m> From<$t<'m>> for CString { fn from(s: $t<'m>) -> CString { s.into_cstring() } }
Unexecuted instantiation: <alloc::ffi::c_str::CString as core::convert::From<dbus::strings::Signature>>::from
Unexecuted instantiation: <alloc::ffi::c_str::CString as core::convert::From<dbus::strings::Path>>::from
Unexecuted instantiation: <alloc::ffi::c_str::CString as core::convert::From<dbus::strings::Member>>::from
Unexecuted instantiation: <alloc::ffi::c_str::CString as core::convert::From<dbus::strings::Interface>>::from
Unexecuted instantiation: <alloc::ffi::c_str::CString as core::convert::From<dbus::strings::BusName>>::from
Unexecuted instantiation: <alloc::ffi::c_str::CString as core::convert::From<dbus::strings::ErrorName>>::from
124
125
126
/// #Panics
127
///
128
/// If given string is not valid.
129
impl<'m> From<Cow<'m, str>> for $t<'m> {
130
0
    fn from(s: Cow<'m, str>) -> $t<'m> {
131
0
        match s {
132
0
            Cow::Borrowed(z) => z.into(),
133
0
            Cow::Owned(z) => z.into(),
134
        }
135
0
    }
Unexecuted instantiation: <dbus::strings::Signature as core::convert::From<alloc::borrow::Cow<str>>>::from
Unexecuted instantiation: <dbus::strings::Path as core::convert::From<alloc::borrow::Cow<str>>>::from
Unexecuted instantiation: <dbus::strings::Member as core::convert::From<alloc::borrow::Cow<str>>>::from
Unexecuted instantiation: <dbus::strings::Interface as core::convert::From<alloc::borrow::Cow<str>>>::from
Unexecuted instantiation: <dbus::strings::BusName as core::convert::From<alloc::borrow::Cow<str>>>::from
Unexecuted instantiation: <dbus::strings::ErrorName as core::convert::From<alloc::borrow::Cow<str>>>::from
136
}
137
138
impl<'inner, 'm: 'inner> From<&'m $t<'inner>> for $t<'m> {
139
0
    fn from(borrow: &'m $t<'inner>) -> $t<'m> {
140
0
        $t(Cow::Borrowed(borrow.0.borrow()))
141
0
    }
Unexecuted instantiation: <dbus::strings::ErrorName as core::convert::From<&dbus::strings::ErrorName>>::from
Unexecuted instantiation: <dbus::strings::Signature as core::convert::From<&dbus::strings::Signature>>::from
Unexecuted instantiation: <dbus::strings::Path as core::convert::From<&dbus::strings::Path>>::from
Unexecuted instantiation: <dbus::strings::Member as core::convert::From<&dbus::strings::Member>>::from
Unexecuted instantiation: <dbus::strings::Interface as core::convert::From<&dbus::strings::Interface>>::from
Unexecuted instantiation: <dbus::strings::BusName as core::convert::From<&dbus::strings::BusName>>::from
142
}
143
144
impl<'m> ops::Deref for $t<'m> {
145
    type Target = str;
146
0
    fn deref(&self) -> &str { self.0.split_at(self.0.len()-1).0 }
Unexecuted instantiation: <dbus::strings::Signature as core::ops::deref::Deref>::deref
Unexecuted instantiation: <dbus::strings::Path as core::ops::deref::Deref>::deref
Unexecuted instantiation: <dbus::strings::Member as core::ops::deref::Deref>::deref
Unexecuted instantiation: <dbus::strings::Interface as core::ops::deref::Deref>::deref
Unexecuted instantiation: <dbus::strings::BusName as core::ops::deref::Deref>::deref
Unexecuted instantiation: <dbus::strings::ErrorName as core::ops::deref::Deref>::deref
147
}
148
149
impl<'m> fmt::Display for $t<'m> {
150
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151
0
        <str as fmt::Display>::fmt(&*self, f)
152
0
    }
Unexecuted instantiation: <dbus::strings::Signature as core::fmt::Display>::fmt
Unexecuted instantiation: <dbus::strings::Path as core::fmt::Display>::fmt
Unexecuted instantiation: <dbus::strings::Member as core::fmt::Display>::fmt
Unexecuted instantiation: <dbus::strings::Interface as core::fmt::Display>::fmt
Unexecuted instantiation: <dbus::strings::BusName as core::fmt::Display>::fmt
Unexecuted instantiation: <dbus::strings::ErrorName as core::fmt::Display>::fmt
153
}
154
155
/*
156
As of dbus 0.9, this has been removed to prepare for a potential native implementation.
157
impl<'m> AsRef<CStr> for $t<'m> {
158
    fn as_ref(&self) -> &CStr { &self.0 }
159
}
160
*/
161
162
impl<'m> hash::Hash for $t<'m> {
163
0
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
164
0
        self.0.hash(state);
165
0
    }
Unexecuted instantiation: <dbus::strings::Signature as core::hash::Hash>::hash::<std::hash::random::DefaultHasher>
Unexecuted instantiation: <dbus::strings::Path as core::hash::Hash>::hash::<std::hash::random::DefaultHasher>
Unexecuted instantiation: <dbus::strings::Member as core::hash::Hash>::hash::<_>
Unexecuted instantiation: <dbus::strings::Interface as core::hash::Hash>::hash::<_>
Unexecuted instantiation: <dbus::strings::BusName as core::hash::Hash>::hash::<_>
Unexecuted instantiation: <dbus::strings::ErrorName as core::hash::Hash>::hash::<_>
166
}
167
168
}}
169
170
/// A wrapper around a string that is guaranteed to be
171
/// a valid (single) D-Bus type signature.
172
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
173
pub struct Signature<'a>(Cow<'a, str>);
174
175
cstring_wrapper!(Signature, dbus_signature_validate_single);
176
177
impl Signature<'static> {
178
    /// Makes a D-Bus signature that corresponds to A.
179
0
    pub fn make<A: super::arg::Arg>() -> Signature<'static> { A::signature() }
180
}
181
182
/// A wrapper around a string that is guaranteed to be
183
/// a valid D-Bus object path.
184
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
185
pub struct Path<'a>(Cow<'a, str>);
186
187
cstring_wrapper!(Path, dbus_validate_path);
188
189
// This is needed so one can make arrays of paths easily
190
impl<'a> default::Default for Path<'a> {
191
0
    fn default() -> Path<'a> { Path(Cow::Borrowed("/\0")) }
192
}
193
194
/// A wrapper around a string that is guaranteed to be
195
/// a valid D-Bus member, i e, a signal or method name.
196
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
197
pub struct Member<'a>(Cow<'a, str>);
198
199
cstring_wrapper!(Member, dbus_validate_member);
200
201
/// A wrapper around a string that is guaranteed to be
202
/// a valid D-Bus interface name.
203
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
204
pub struct Interface<'a>(Cow<'a, str>);
205
206
cstring_wrapper!(Interface, dbus_validate_interface);
207
208
/// A wrapper around a string that is guaranteed to be
209
/// a valid D-Bus bus name.
210
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
211
pub struct BusName<'a>(Cow<'a, str>);
212
213
cstring_wrapper!(BusName, dbus_validate_bus_name);
214
215
/// A wrapper around a string that is guaranteed to be
216
/// a valid D-Bus error name.
217
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
218
pub struct ErrorName<'a>(Cow<'a, str>);
219
220
cstring_wrapper!(ErrorName, dbus_validate_error_name);
221
222
#[test]
223
fn some_path() {
224
    let p1: Path = "/valid".into();
225
    let p2 = Path::new("##invalid##");
226
    assert_eq!(p1, Path(Cow::Borrowed("/valid\0")));
227
    #[cfg(not(feature = "no-string-validation"))]
228
    assert_eq!(p2, Err("Object path was not valid: '##invalid##'".into()));
229
    #[cfg(feature = "no-string-validation")]
230
    assert_eq!(p2, Ok(Path(Cow::Borrowed("##invalid##\0"))));
231
}
232
233
#[test]
234
fn reborrow_path() {
235
    let p1 = Path::from("/valid");
236
    let p2 = p1.clone();
237
    {
238
        let p2_borrow: &Path = &p2;
239
        let p3 = Path::from(p2_borrow);
240
        // Check path created from borrow
241
        assert_eq!(p2, p3);
242
    }
243
    // Check path that was previously borrowed
244
    assert_eq!(p1, p2);
245
}
246
247
#[test]
248
fn make_sig() {
249
    assert_eq!(&*Signature::make::<(&str, u8)>(), "(sy)");
250
}