qbt-clean 0.3.0

Automated rules-based cleaning of qBittorrent torrents.
#[derive(Debug)]
pub struct SerdeBytes(u64);

impl From<SerdeBytes> for u64 {
	fn from(value: SerdeBytes) -> Self {
		value.0
	}
}

impl<'d> serde::de::Deserialize<'d> for SerdeBytes {
	fn deserialize<D: serde::Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
		let s = <std::borrow::Cow<str> as serde::Deserialize>::deserialize(d)?;
		crate::parse_bytes(&s)
			.map(SerdeBytes)
			.map_err(|_| serde::de::Error::invalid_value(
				serde::de::Unexpected::Str(&s),
				&"duration"))
	}
}

#[derive(Debug)]
pub struct SerdeDuration(std::time::Duration);

impl From<SerdeDuration> for std::time::Duration {
	fn from(value: SerdeDuration) -> Self {
		value.0
	}
}

impl<'d> serde::de::Deserialize<'d> for SerdeDuration {
	fn deserialize<D: serde::Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
		let s = <std::borrow::Cow<str> as serde::Deserialize>::deserialize(d)?;
		humanize_rs::duration::parse(&s)
			.map(SerdeDuration)
			.map_err(|_| serde::de::Error::invalid_value(
				serde::de::Unexpected::Str(&s),
				&"duration"))
	}
}

#[derive(Debug)]
pub struct SerdeRegex(regex::Regex);

impl From<SerdeRegex> for regex::Regex {
	fn from(value: SerdeRegex) -> Self {
		value.0
	}
}

impl<'d> serde::de::Deserialize<'d> for SerdeRegex {
	fn deserialize<D: serde::Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
		let s = <std::borrow::Cow<str> as serde::Deserialize>::deserialize(d)?;
		s.parse().map(SerdeRegex).map_err(|e| serde::de::Error::custom(e))
	}
}

#[derive(Debug)]
pub struct SerdeRegexSet(regex::RegexSet);

impl From<SerdeRegexSet> for regex::RegexSet {
	fn from(value: SerdeRegexSet) -> Self {
		value.0
	}
}

impl<'d> serde::de::Deserialize<'d> for SerdeRegexSet {
	fn deserialize<D: serde::Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
		let patterns = <Vec<std::borrow::Cow<str>> as serde::Deserialize>::deserialize(d)?;
		regex::RegexSet::new(patterns.into_iter().map(|p| format!("^{p}$")))
			.map(SerdeRegexSet)
			.map_err(|e| serde::de::Error::custom(e))
	}
}