use crate::providers::{
avif::Avif, gif::Gif, heic::Heic, jpeg::Jpeg, mov::Mov, mp4::Mp4, png::Png, webp::Webp,
};
#[doc(hidden)]
#[diagnostic::on_unimplemented(
message = "Please add this type to the `generate!()` macro in the `raves_metadata/src/magic_number.rs` file."
)]
pub trait _MagicNumberMarker {
#[doc(hidden)]
fn _do_not_implement_this_manually(self);
}
macro_rules! generate {
( $(
// name of the provider (must be the same as the provider_ty)
$variant:ident => {
// the actual type we map to
provider_ty: $provider_ty:ty
},
)+) => {
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Hash)]
pub enum MagicNumber {
$($variant,)+
}
#[repr(u16)]
#[derive(Clone, Debug)]
pub enum AnyProvider {
$($variant(
Result<
$provider_ty,
<$provider_ty as $crate::MetadataProvider>::ConstructionError
>),
)+
}
impl MagicNumber {
#[inline(always)]
pub fn new(input: &impl AsRef<[u8]>) -> Option<Self> {
get(input)
}
}
impl AnyProvider {
#[inline(always)]
pub fn new(input: &impl AsRef<[u8]>) -> Option<Self> {
parse(input)
}
pub fn magic_number(&self) -> MagicNumber {
match self {
$(Self::$variant(..) => MagicNumber::$variant,)+
}
}
pub fn exif(&self) -> Option<Result<std::sync::Arc<parking_lot::RwLock<crate::Exif>>, crate::ExifFatalError>> {
match self {
$(
Self::$variant(maybe_inner) => {
let Ok(inner) = maybe_inner else {
::log::error!("The inner provider is an error, not `Ok`. Cannot get metadata.");
return None;
};
<$provider_ty as $crate::MetadataProvider>::exif(inner)
},
)+
}
}
pub fn iptc(&self) -> Option<Result<std::sync::Arc<parking_lot::RwLock<crate::Iptc>>, crate::IptcError>> {
match self {
$(
Self::$variant(maybe_inner) => {
let Ok(inner) = maybe_inner else {
::log::error!("The inner provider is an error, not `Ok`. Cannot get metadata.");
return None;
};
<$provider_ty as $crate::MetadataProvider>::iptc(inner)
},
)+
}
}
pub fn xmp(&self) -> Option<Result<std::sync::Arc<parking_lot::RwLock<crate::Xmp>>, crate::XmpError>> {
match self {
$(
Self::$variant(maybe_inner) => {
let Ok(inner) = maybe_inner else {
::log::error!("The inner provider is an error, not `Ok`. Cannot get metadata.");
return None;
};
<$provider_ty as $crate::MetadataProvider>::xmp(inner)
},
)+
}
}
}
$(
impl From<$provider_ty> for MagicNumber {
fn from(_item: $provider_ty) -> Self {
Self::$variant
}
}
impl From<$provider_ty> for AnyProvider {
fn from(item: $provider_ty) -> Self {
Self::$variant(Ok(item))
}
}
impl _MagicNumberMarker for $provider_ty {
fn _do_not_implement_this_manually(self) {}
}
)+
impl From<AnyProvider> for MagicNumber {
fn from(item: AnyProvider) -> MagicNumber {
match &item {
$(
AnyProvider::$variant(_) => MagicNumber::$variant,
)+
}
}
}
pub(super) fn parse(input: &impl AsRef<[u8]>) -> Option<AnyProvider> {
let slice_input: &[u8] = input.as_ref();
$(
::log::trace!("Attempting to parse blob as `{}`...", core::any::type_name::<$provider_ty>());
if <$provider_ty as $crate::MetadataProvider>::magic_number(slice_input) {
let p = <$provider_ty as $crate::MetadataProvider>::new(input)
.ok()
.map(AnyProvider::from);
if p.is_some() {
return p;
}
}
::log::trace!("Not `{}`!", core::any::type_name::<$provider_ty>());
)+
::log::trace!("No providers matched the blob.");
return None;
}
pub(super) fn get(input: &impl AsRef<[u8]>) -> Option<MagicNumber> {
let slice_input: &[u8] = input.as_ref();
$(
::log::trace!("Attempting to parse blob as `{}`...", core::any::type_name::<$provider_ty>());
if <$provider_ty as $crate::MetadataProvider>::magic_number(slice_input) {
return Some(MagicNumber::$variant);
}
::log::trace!("Not `{}`!", core::any::type_name::<$provider_ty>());
)+
::log::trace!("No providers matched the blob.");
return None;
}
};
}
generate!(
Avif => { provider_ty: Avif },
Heic => { provider_ty: Heic },
Jpeg => { provider_ty: Jpeg },
Mov => { provider_ty: Mov },
Mp4 => { provider_ty: Mp4 },
Png => { provider_ty: Png },
Webp => { provider_ty: Webp },
Gif => { provider_ty: Gif },
);