use bytes::Bytes;
use smol_str::SmolStr;
#[cfg_attr(
feature = "quickcheck",
derive(::quickcheck_richderive::Arbitrary),
quickcheck(arbitrary = "crate::quickcheck_helpers::composite::fingerprint")
)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Fingerprint {
algorithm: SmolStr,
value: Bytes,
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
const _: () = {
use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct};
impl Serialize for Fingerprint {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut st = ser.serialize_struct("Fingerprint", 2)?;
st.serialize_field("algorithm", &self.algorithm)?;
st.serialize_field("value", &self.value)?;
st.end()
}
}
#[derive(Deserialize)]
struct Shadow {
algorithm: SmolStr,
value: Bytes,
}
impl<'de> Deserialize<'de> for Fingerprint {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
let s = Shadow::deserialize(de)?;
Fingerprint::try_new(s.algorithm, s.value).map_err(serde::de::Error::custom)
}
}
};
impl Default for Fingerprint {
fn default() -> Self {
Self {
algorithm: SmolStr::new_inline("default"),
value: Bytes::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error)]
#[non_exhaustive]
pub enum FingerprintError {
#[error("audio fingerprint algorithm label is empty")]
EmptyAlgorithm,
}
impl Fingerprint {
pub fn try_new(
algorithm: impl Into<SmolStr>,
value: impl Into<Bytes>,
) -> Result<Self, FingerprintError> {
let algorithm = algorithm.into();
if algorithm.is_empty() {
return Err(FingerprintError::EmptyAlgorithm);
}
Ok(Self {
algorithm,
value: value.into(),
})
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn algorithm(&self) -> &str {
self.algorithm.as_str()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn value(&self) -> &[u8] {
self.value.as_ref()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn value_bytes(&self) -> Bytes {
self.value.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::std::vec;
#[test]
fn try_new_happy_path() {
let fp = Fingerprint::try_new("chromaprint", vec![1u8, 2, 3, 4]).unwrap();
assert_eq!(fp.algorithm(), "chromaprint");
assert_eq!(fp.value(), &[1, 2, 3, 4]);
}
#[test]
fn try_new_rejects_empty_algorithm() {
let err = Fingerprint::try_new("", vec![1u8]).unwrap_err();
assert_eq!(err, FingerprintError::EmptyAlgorithm);
}
#[test]
fn try_new_accepts_empty_value() {
let fp = Fingerprint::try_new("acoustid", vec![]).unwrap();
assert_eq!(fp.algorithm(), "acoustid");
assert!(fp.value().is_empty());
}
}