use crate::filter::{DEFAULT_SEPARATOR, DEFAULT_UNSAFE_CHARS, Filter};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sequence {
pub(crate) filters: Vec<Filter>,
pub(crate) name: String,
}
impl Sequence {
#[must_use]
#[allow(clippy::should_implement_trait)]
pub fn default() -> Self {
Sequence {
name: "default".to_string(),
filters: vec![
Filter::Safe {
replacement: b'_',
unsafe_chars: DEFAULT_UNSAFE_CHARS.to_vec(),
},
Filter::Wipeup {
separator: DEFAULT_SEPARATOR,
remove_trailing: true,
},
],
}
}
#[must_use]
pub fn iso8859_1() -> Self {
Sequence {
name: "iso8859_1".to_string(),
filters: vec![
Filter::Iso8859_1,
Filter::Safe {
replacement: b'_',
unsafe_chars: DEFAULT_UNSAFE_CHARS.to_vec(),
},
Filter::Wipeup {
separator: DEFAULT_SEPARATOR,
remove_trailing: true,
},
],
}
}
#[must_use]
pub fn utf_8() -> Self {
Sequence {
name: "utf_8".to_string(),
filters: vec![
Filter::Utf8,
Filter::Safe {
replacement: b'_',
unsafe_chars: DEFAULT_UNSAFE_CHARS.to_vec(),
},
Filter::Wipeup {
separator: DEFAULT_SEPARATOR,
remove_trailing: true,
},
],
}
}
#[must_use]
pub fn new(name: impl Into<String>) -> Self {
Sequence {
name: name.into(),
filters: Vec::new(),
}
}
#[must_use]
pub fn push(mut self, filter: Filter) -> Self {
self.filters.push(filter);
self
}
pub fn name(&self) -> &str {
&self.name
}
pub fn filters(&self) -> &[Filter] {
&self.filters
}
pub(crate) fn apply(&self, input: &[u8]) -> Vec<u8> {
let mut buf = input.to_vec();
for filter in &self.filters {
buf = filter.apply(&buf);
}
buf
}
}
impl Default for Sequence {
fn default() -> Self {
Self::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_inherent_matches_trait_default() {
let inherent = Sequence::default();
let trait_d: Sequence = <Sequence as Default>::default();
assert_eq!(inherent, trait_d);
}
#[test]
fn default_sanitizes_space_to_underscore() {
let s = Sequence::default();
assert_eq!(s.apply(b"hello world.txt"), b"hello_world.txt");
}
#[test]
fn utf_8_strips_e_acute() {
let s = Sequence::utf_8();
assert_eq!(s.apply("café résumé.pdf".as_bytes()), b"cafe_resume.pdf");
}
#[test]
fn push_returns_self_for_chaining() {
let s = Sequence::new("custom")
.push(Filter::safe_default())
.push(Filter::wipeup_default());
assert_eq!(s.filters().len(), 2);
}
}