storefd/src/notify/types.rs
2024-01-05 22:41:13 +01:00

211 lines
4.8 KiB
Rust

//! 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<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(u64);
impl From<u64> for Microseconds {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<Microseconds> 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<core::num::NonZeroI32> for PollTimeout {
type Error = error::PollTimeoutFromIntError;
fn try_from(value: core::num::NonZeroI32) -> Result<Self, Self::Error> {
if value.is_negative() {
return Err(Self::Error::Negative);
}
Ok(Self(value))
}
}
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)
}
}
#[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")
}
}