2024-01-04 13:48:45 +01:00
|
|
|
//! Newtypes used by [`NotifyState`](super::NotifyState)
|
|
|
|
|
|
|
|
use super::error;
|
|
|
|
|
|
|
|
/// Allowed File descriptor name.
|
|
|
|
///
|
|
|
|
/// A name is allowed when it :
|
|
|
|
///
|
|
|
|
/// * Has less than 255 characters.
|
|
|
|
/// * Is ASCII.
|
|
|
|
/// * Doesn't contains control characters.
|
|
|
|
/// * Doesn't contains a colon (`:`).
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct FdName<'a>(pub(super) &'a str);
|
|
|
|
|
|
|
|
impl<'a> TryFrom<&'a str> for FdName<'a> {
|
|
|
|
type Error = error::FdNameError;
|
|
|
|
|
|
|
|
fn try_from(name: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
if name.len() > 255 {
|
|
|
|
return Err(error::FdNameError::TooLong {
|
|
|
|
length: name.len(),
|
|
|
|
name: name.into(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in name.chars() {
|
|
|
|
if !c.is_ascii() || c.is_ascii_control() {
|
|
|
|
return Err(error::FdNameError::NotAsciiNonControl {
|
|
|
|
disallowed_char: c,
|
|
|
|
name: name.into(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if c == ':' {
|
|
|
|
return Err(error::FdNameError::ContainColon(name.into()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self(name))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for FdName<'_> {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A status line for [`NotifyState::Status`](super::NotifyState::Status).
|
|
|
|
///
|
|
|
|
/// As the name explains it needs to be a single line.
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct StatusLine<'a>(pub(super) &'a str);
|
|
|
|
|
|
|
|
impl<'a> TryFrom<&'a str> for StatusLine<'a> {
|
|
|
|
type Error = error::StatusLineError;
|
|
|
|
|
|
|
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
if value.lines().nth(1).is_some() {
|
|
|
|
return Err(Self::Error::TooManyLines);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self(value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for StatusLine<'_> {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-05 22:33:53 +01:00
|
|
|
/// Semantic type representing a number of microseconds.
|
2024-01-04 13:48:45 +01:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
2024-01-05 22:33:53 +01:00
|
|
|
pub struct Microseconds(pub(super) u64);
|
2024-01-04 13:48:45 +01:00
|
|
|
|
2024-01-05 22:33:53 +01:00
|
|
|
impl From<u64> for Microseconds {
|
2024-01-04 13:48:45 +01:00
|
|
|
fn from(value: u64) -> Self {
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-05 22:33:53 +01:00
|
|
|
impl AsRef<u64> for Microseconds {
|
2024-01-04 13:48:45 +01:00
|
|
|
fn as_ref(&self) -> &u64 {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A D-Bus error-style error code.
|
|
|
|
///
|
|
|
|
/// Right now it doesn't impose any additional constraint on [`str`]
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct BusError<'a>(pub(super) &'a str);
|
|
|
|
|
|
|
|
impl<'a> From<&'a str> for BusError<'a> {
|
|
|
|
fn from(value: &'a str) -> Self {
|
|
|
|
Self(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for BusError<'_> {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
2024-01-04 14:31:02 +01:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct OtherState<'a>(pub(super) &'a str);
|
|
|
|
|
|
|
|
impl<'a> TryFrom<&'a str> for OtherState<'a> {
|
|
|
|
type Error = error::OtherStateError;
|
|
|
|
|
|
|
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
|
|
|
if value.contains('\n') {
|
|
|
|
return Err(Self::Error::TooManyLines);
|
|
|
|
}
|
|
|
|
|
|
|
|
if !value.contains('=') {
|
|
|
|
return Err(Self::Error::NoAssignement);
|
|
|
|
}
|
|
|
|
|
|
|
|
if value == "BARRIER=1" {
|
|
|
|
return Err(Self::Error::DisallowedState(String::from(value)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self(value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for OtherState<'_> {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|