use std::borrow::{Borrow, Cow};
use std::{cmp::Ordering, ops::Bound};
use derive_more::{AsRef, Deref, Display, From, Into};
use enum_as_inner::EnumAsInner;
use smol_str::SmolStr;
use strum::EnumDiscriminants;
mod atomic;
pub use self::atomic::{AtomicValue, SharedAtomicValue, WeakAtomicValue};
mod ramping;
pub use self::ramping::{RampingF32, RampingMode, RampingProfile};
mod registry;
pub use self::registry::{
RegisteredId, Registration, RegistrationError, RegistrationStatus, Registry, RegistryEntryRef,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
Input,
Output,
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, EnumAsInner, EnumDiscriminants, From)]
#[strum_discriminants(name(ValueType))]
pub enum Value {
Bool(bool),
I32(i32),
U32(u32),
F32(f32),
}
#[derive(
Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Display, From, Into, AsRef, Deref,
)]
pub struct Name(SmolStr);
impl Name {
#[must_use]
pub const fn new(inner: SmolStr) -> Self {
Self(inner)
}
}
impl From<&str> for Name {
fn from(from: &str) -> Self {
Self(from.into())
}
}
impl From<Cow<'_, str>> for Name {
fn from(from: Cow<'_, str>) -> Self {
Self(from.into())
}
}
impl From<String> for Name {
fn from(from: String) -> Self {
Self(from.into())
}
}
impl AsRef<str> for Name {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Borrow<str> for Name {
fn borrow(&self) -> &str {
self.0.borrow()
}
}
#[derive(
Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Display, From, Into, AsRef, Deref,
)]
pub struct Unit(SmolStr);
impl Unit {
#[must_use]
pub const fn new(inner: SmolStr) -> Self {
Self(inner)
}
}
impl From<&str> for Unit {
fn from(from: &str) -> Self {
Self(from.into())
}
}
impl From<Cow<'_, str>> for Unit {
fn from(from: Cow<'_, str>) -> Self {
Self(from.into())
}
}
impl From<String> for Unit {
fn from(from: String) -> Self {
Self(from.into())
}
}
impl AsRef<str> for Unit {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Borrow<str> for Unit {
fn borrow(&self) -> &str {
self.0.borrow()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Descriptor {
pub name: Name,
pub unit: Option<Unit>,
pub direction: Direction,
pub value: ValueDescriptor,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ValueDescriptor {
pub default: Value,
pub range: ValueRangeDescriptor,
}
impl ValueDescriptor {
#[must_use]
pub const fn default(default: Value) -> Self {
Self {
default,
range: ValueRangeDescriptor::unbounded(),
}
}
#[must_use]
pub fn value_type(&self) -> ValueType {
self.default.into()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ValueRangeDescriptor {
pub min: Bound<Value>,
pub max: Bound<Value>,
}
impl ValueRangeDescriptor {
#[must_use]
pub const fn unbounded() -> Self {
Self {
min: Bound::Unbounded,
max: Bound::Unbounded,
}
}
#[must_use]
pub fn value_type(&self) -> Option<ValueType> {
match self {
Self {
min: Bound::Unbounded,
max: Bound::Unbounded,
} => None,
Self {
min: Bound::Included(min) | Bound::Excluded(min),
max: Bound::Unbounded,
} => Some(min.into()),
Self {
min: Bound::Unbounded,
max: Bound::Included(max) | Bound::Excluded(max),
} => Some(max.into()),
Self {
min: Bound::Included(min) | Bound::Excluded(min),
max: Bound::Included(max) | Bound::Excluded(max),
} => {
debug_assert_eq!(ValueType::from(min), ValueType::from(max));
Some(min.into())
}
}
}
#[must_use]
pub fn contains_value(&self, value: Value) -> Option<bool> {
let Self { min, max } = self;
match min {
Bound::Unbounded => (),
Bound::Included(min_inclusive) => match value.partial_cmp(min_inclusive)? {
Ordering::Equal | Ordering::Greater => (),
Ordering::Less => return Some(false),
},
Bound::Excluded(min_exclusive) => match value.partial_cmp(min_exclusive)? {
Ordering::Greater => (),
Ordering::Less | Ordering::Equal => return Some(false),
},
}
match max {
Bound::Unbounded => (),
Bound::Included(max_inclusive) => match value.partial_cmp(max_inclusive)? {
Ordering::Less | Ordering::Equal => (),
Ordering::Greater => return Some(false),
},
Bound::Excluded(max_exclusive) => match value.partial_cmp(max_exclusive)? {
Ordering::Less => (),
Ordering::Equal | Ordering::Greater => return Some(false),
},
}
Some(true)
}
}
impl Default for ValueRangeDescriptor {
fn default() -> Self {
Self::unbounded()
}
}
#[derive(
Debug, Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Display, From, Into, AsRef, Deref,
)]
pub struct Address(SmolStr);
impl Address {
#[must_use]
pub const fn new(inner: SmolStr) -> Self {
Self(inner)
}
}
impl From<&str> for Address {
fn from(from: &str) -> Self {
Self(from.into())
}
}
impl From<Cow<'_, str>> for Address {
fn from(from: Cow<'_, str>) -> Self {
Self(from.into())
}
}
impl From<String> for Address {
fn from(from: String) -> Self {
Self(from.into())
}
}
impl AsRef<str> for Address {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl Borrow<str> for Address {
fn borrow(&self) -> &str {
self.0.borrow()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_value_descriptor() {
assert_eq!(
ValueDescriptor::default(Value::Bool(true)),
ValueDescriptor {
default: Value::Bool(true),
range: Default::default(),
}
);
}
#[test]
fn default_value_range_is_unbounded() {
assert_eq!(
ValueRangeDescriptor::default(),
ValueRangeDescriptor::unbounded()
);
}
}