use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[non_exhaustive]
pub enum Source {
#[default]
Structural,
Context,
Heuristic,
}
impl fmt::Display for Source {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Source::Structural => write!(f, "structural"),
Source::Context => write!(f, "context"),
Source::Heuristic => write!(f, "heuristic"),
}
}
}
macro_rules! define_properties {
($( $(#[$meta:meta])* $variant:ident => $name:expr ),* $(,)?) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[non_exhaustive]
pub enum Property {
$( $(#[$meta])* $variant ),*
}
impl Property {
pub fn from_name(name: &str) -> Option<Self> {
match name {
$( $name => Some(Self::$variant), )*
_ => None,
}
}
}
impl fmt::Display for Property {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
$( Self::$variant => $name, )*
};
write!(f, "{s}")
}
}
}
}
define_properties! {
Title => "title",
AlternativeTitle => "alternative_title",
Year => "year",
Season => "season",
Episode => "episode",
AbsoluteEpisode => "absolute_episode",
EpisodeTitle => "episode_title",
VideoCodec => "video_codec",
VideoProfile => "video_profile",
AudioCodec => "audio_codec",
AudioProfile => "audio_profile",
AudioChannels => "audio_channels",
Source => "source",
ScreenSize => "screen_size",
FrameRate => "frame_rate",
ColorDepth => "color_depth",
Container => "container",
ReleaseGroup => "release_group",
StreamingService => "streaming_service",
Language => "language",
SubtitleLanguage => "subtitle_language",
Country => "country",
Edition => "edition",
Date => "date",
Other => "other",
Size => "size",
Cd => "cd",
Bonus => "bonus",
BonusTitle => "bonus_title",
Film => "film",
FilmTitle => "film_title",
Part => "part",
Crc => "crc32",
Uuid => "uuid",
CdCount => "cd_count",
Disc => "disc",
Website => "website",
EpisodeDetails => "episode_details",
EpisodeFormat => "episode_format",
Week => "week",
AspectRatio => "aspect_ratio",
ProperCount => "proper_count",
MediaType => "type",
Version => "version",
EpisodeCount => "episode_count",
SeasonCount => "season_count",
VideoApi => "video_api",
Mimetype => "mimetype",
AudioBitRate => "audio_bit_rate",
VideoBitRate => "video_bit_rate",
}
#[derive(Debug, Clone)]
pub struct MatchSpan {
pub start: usize,
pub end: usize,
pub property: Property,
pub value: String,
pub is_extension: bool,
pub is_path_based: bool,
pub priority: i32,
pub reclaimable: bool,
pub source: Source,
}
impl MatchSpan {
pub fn new(start: usize, end: usize, property: Property, value: impl Into<String>) -> Self {
Self {
start,
end,
property,
value: value.into(),
is_extension: false,
is_path_based: false,
priority: 0,
reclaimable: false,
source: Source::default(),
}
}
#[must_use]
pub fn with_extension(mut self) -> Self {
self.is_extension = true;
self
}
#[must_use]
pub fn with_path_based(mut self) -> Self {
self.is_path_based = true;
self
}
#[must_use]
pub fn with_priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
#[must_use]
pub fn with_reclaimable(mut self) -> Self {
self.reclaimable = true;
self
}
#[must_use]
pub fn with_source(mut self, source: Source) -> Self {
self.source = source;
self
}
pub fn overlaps(&self, other: &Self) -> bool {
self.start < other.end && other.start < self.end
}
pub fn len(&self) -> usize {
self.end - self.start
}
}
impl Property {
pub fn is_numeric(&self) -> bool {
matches!(
self,
Self::Year
| Self::Season
| Self::Episode
| Self::AbsoluteEpisode
| Self::Part
| Self::Bonus
| Self::Film
| Self::Cd
| Self::CdCount
| Self::Disc
| Self::Week
| Self::EpisodeCount
| Self::SeasonCount
| Self::ProperCount
| Self::Version
)
}
}