//! Newtypes used by [`NotifyState`](super::NotifyState) use core::fmt::Display; 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 { 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 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 { if value.lines().nth(1).is_some() { return Err(Self::Error::TooManyLines); } Ok(Self(value)) } } impl AsRef 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(u64); impl From for Microseconds { fn from(value: u64) -> Self { Self(value) } } impl From for u64 { fn from(value: Microseconds) -> Self { value.0 } } impl Display for Microseconds { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.0, f) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum BarrierTimeout { Infinite, Immediate, 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(), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PollTimeout(core::num::NonZeroI32); impl TryFrom for PollTimeout { type Error = error::PollTimeoutFromIntError; fn try_from(value: core::num::NonZeroI32) -> Result { if value.is_negative() { return Err(Self::Error::Negative); } Ok(Self(value)) } } impl From 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 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) } } #[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 { 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 for OtherState<'_> { #[inline] fn as_ref(&self) -> &str { self.0 } } impl OtherState<'_> { pub(super) const fn barrier() -> Self { Self("BARRIER=1") } }