You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
obws/src/requests/ids.rs

181 lines
5.2 KiB
Rust

use std::fmt::{self, Display};
use serde::{ser::SerializeStruct, Serialize};
use uuid::Uuid;
macro_rules! item_id {
($ident:ident, $name:literal, $name_field:literal, $uuid_field:literal) => {
#[doc = concat!("Identifier of the", $name, ".")]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub enum $ident<'a> {
#[doc = concat!("Name of the ", $name, ".")]
Name(&'a str),
#[doc = concat!("UUID of the ", $name, ".")]
Uuid(Uuid),
}
impl $ident<'_> {
/// If the identifier is a name, returns the associated value.
///
/// Will return [`None`] if this identifier is not a name.
pub fn as_name(&self) -> Option<&str> {
match *self {
Self::Name(name) => Some(name),
Self::Uuid(_) => None,
}
}
/// If the identifier is a UUID, returns the associated value.
///
/// Will return [`None`] if this identifier is not a UUID.
pub fn as_uuid(&self) -> Option<Uuid> {
match *self {
Self::Name(_) => None,
Self::Uuid(uuid) => Some(uuid),
}
}
}
impl Default for $ident<'_> {
fn default() -> Self {
Self::Name("")
}
}
impl Display for $ident<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Name(name) => name.fmt(f),
Self::Uuid(uuid) => uuid.fmt(f),
}
}
}
impl PartialEq<str> for $ident<'_> {
fn eq(&self, other: &str) -> bool {
match *self {
Self::Name(name) => name == other,
Self::Uuid(_) => false,
}
}
}
impl PartialEq<Uuid> for $ident<'_> {
fn eq(&self, other: &Uuid) -> bool {
match *self {
Self::Name(_) => false,
Self::Uuid(uuid) => uuid == *other,
}
}
}
impl PartialEq<$ident<'_>> for String {
fn eq(&self, other: &$ident<'_>) -> bool {
other == self.as_str()
}
}
impl PartialEq<$ident<'_>> for &str {
fn eq(&self, other: &$ident<'_>) -> bool {
other == *self
}
}
impl PartialEq<$ident<'_>> for Uuid {
fn eq(&self, other: &$ident<'_>) -> bool {
other == self
}
}
impl<'a> From<&'a str> for $ident<'a> {
fn from(value: &'a str) -> Self {
Self::Name(value)
}
}
impl From<Uuid> for $ident<'_> {
fn from(value: Uuid) -> Self {
Self::Uuid(value)
}
}
impl Serialize for $ident<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct(stringify!($ident), 1)?;
match *self {
Self::Name(name) => {
state.serialize_field($name_field, name)?;
}
Self::Uuid(uuid) => {
state.serialize_field($uuid_field, &uuid)?;
}
}
state.end()
}
}
};
}
item_id!(InputId, "input", "inputName", "inputUuid");
item_id!(SceneId, "scene", "sceneName", "sceneUuid");
item_id!(SourceId, "source", "sourceName", "sourceUuid");
item_id!(
TransitionId,
"transition",
"transitionName",
"transitionUuid"
);
item_id!(
DestinationSceneId,
"destination scene",
"destinationSceneName",
"destinationSceneUuid"
);
macro_rules! convert {
($source:ident, $target:ident) => {
impl<'a> From<$source<'a>> for $target<'a> {
fn from(value: $source<'a>) -> Self {
match value {
$source::Name(name) => Self::Name(name),
$source::Uuid(uuid) => Self::Uuid(uuid),
}
}
}
impl<'a> From<$target<'a>> for $source<'a> {
fn from(value: $target<'a>) -> Self {
match value {
$target::Name(name) => Self::Name(name),
$target::Uuid(uuid) => Self::Uuid(uuid),
}
}
}
};
}
convert!(SceneId, DestinationSceneId);
impl<'a> InputId<'a> {
/// Convert the input identifier into a source identifier.
///
/// This is a one-way operation, as there is no way of telling whether a source ID is an actual
/// input.
pub fn as_source(self) -> SourceId<'a> {
match self {
Self::Name(name) => SourceId::Name(name),
Self::Uuid(uuid) => SourceId::Uuid(uuid),
}
}
}
impl<'a> From<InputId<'a>> for SourceId<'a> {
fn from(value: InputId<'a>) -> Self {
value.as_source()
}
}