217 lines
5.4 KiB
Rust
217 lines
5.4 KiB
Rust
//! Newtypes used by [`NotifyState`](super::NotifyState)
|
|
|
|
use core::{fmt::Display, time::Duration};
|
|
|
|
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>(&'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
|
|
}
|
|
}
|
|
|
|
impl Display for FdName<'_> {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
Display::fmt(self.0, f)
|
|
}
|
|
}
|
|
|
|
/// 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>(&'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
|
|
}
|
|
}
|
|
|
|
impl Display for StatusLine<'_> {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
Display::fmt(self.0, f)
|
|
}
|
|
}
|
|
|
|
/// Semantic type representing a number of microseconds.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct Microseconds(Duration);
|
|
|
|
impl TryFrom<Duration> for Microseconds {
|
|
type Error = error::MicrosecondsFromDurationError;
|
|
|
|
fn try_from(value: Duration) -> Result<Self, Self::Error> {
|
|
if value.as_micros() == 0 {
|
|
return Err(Self::Error::NoMicroseconds);
|
|
}
|
|
Ok(Self(value))
|
|
}
|
|
}
|
|
|
|
impl Display for Microseconds {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.0.as_micros())
|
|
}
|
|
}
|
|
|
|
/// Timeout for the [`Notifier::barrier()`](super::Notifier::barrier).
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum BarrierTimeout {
|
|
/// Will block indefinitely.
|
|
Infinite,
|
|
/// Will not block at all and return immediately even if no event has happened.
|
|
Immediate,
|
|
/// Will block for a number of milliseconds.
|
|
NonZero(PollTimeout),
|
|
}
|
|
|
|
impl BarrierTimeout {
|
|
pub(crate) const fn to_raw(self) -> i32 {
|
|
match self {
|
|
Self::Immediate => 0_i32,
|
|
Self::Infinite => -1_i32,
|
|
Self::NonZero(PollTimeout(timeout)) => timeout.get(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Variant of [`BarrierTimeout`] for positive timeout.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct PollTimeout(core::num::NonZeroI32);
|
|
|
|
impl TryFrom<core::num::NonZeroI32> for PollTimeout {
|
|
type Error = error::PollTimeoutFromIntError;
|
|
|
|
fn try_from(milliseconds: core::num::NonZeroI32) -> Result<Self, Self::Error> {
|
|
if milliseconds.is_negative() {
|
|
return Err(Self::Error::Negative);
|
|
}
|
|
Ok(Self(milliseconds))
|
|
}
|
|
}
|
|
|
|
impl From<PollTimeout> for core::num::NonZeroI32 {
|
|
#[inline]
|
|
fn from(value: PollTimeout) -> Self {
|
|
value.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>(&'a str);
|
|
|
|
impl<'a> From<&'a str> for BusError<'a> {
|
|
fn from(value: &'a str) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
|
|
impl AsRef<str> for BusError<'_> {
|
|
#[inline]
|
|
fn as_ref(&self) -> &str {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl Display for BusError<'_> {
|
|
#[inline]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
Display::fmt(self.0, f)
|
|
}
|
|
}
|
|
|
|
/// An arbitrary custom state other than `BARRIER=1`.
|
|
///
|
|
/// `BARRIER=1` is blocked as it result in special expectations by the protocol.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct OtherState<'a>(&'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<'_> {
|
|
#[inline]
|
|
fn as_ref(&self) -> &str {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl OtherState<'_> {
|
|
pub(super) const fn barrier() -> Self {
|
|
Self("BARRIER=1")
|
|
}
|
|
}
|