Skip to main content

renamer_rs/processor/
format.rs

1use crate::Error;
2use crate::Error::{NoFormattingPatterns, UnknownFormatType};
3use log::{debug, trace};
4use regex::Regex;
5
6const FORMAT_PATTERN: &str = r"%[dse]\d+%";
7const SELECTOR_TYPE_PREFIX: &str = "%s";
8const DELIMITER_TYPE_PREFIX: &str = "%d";
9const EXTRACTOR_TYPE_PREFIX: &str = "%e";
10
11/// Represents the type for format string being referenced
12#[derive(Debug, Copy, Clone)]
13pub(super) enum FormatType {
14    /// Represents a [`Delimiter`][crate::Delimiter]
15    Delimiter,
16    /// Represents a [`Extractor`][crate::Extractor]
17    Extractor,
18    /// Represents a [`Selector`][crate::Selector]
19    Selector,
20}
21
22/// Represents detected format patterns that will be replaced during processing
23#[derive(Debug, Clone)]
24pub(super) struct FormatPattern {
25    pattern: String,
26    format_type: FormatType,
27    id: usize,
28}
29
30/// Represents the provided format string and all the detected format patterns
31#[derive(Debug, Clone)]
32pub struct Format {
33    value: String,
34    patterns: Vec<FormatPattern>,
35}
36
37impl FormatPattern {
38    /// Create a new [`FormatPattern`]
39    pub(super) fn new<S: AsRef<str>>(pattern: S, format_type: FormatType, id: usize) -> Self {
40        Self {
41            pattern: pattern.as_ref().into(),
42            format_type,
43            id,
44        }
45    }
46
47    /// Returns the [`FormatType`]
48    pub(super) fn format_type(&self) -> FormatType {
49        self.format_type
50    }
51
52    /// Returns the actual format pattern [`String`]
53    pub fn pattern(&self) -> &str {
54        &self.pattern
55    }
56
57    /// Returns the detected ID value used to reference the pattern in combination with the [`FormatType`]
58    pub fn id(&self) -> usize {
59        self.id
60    }
61}
62
63impl Format {
64    /// Create a new [`Format`] from a provided format string
65    pub fn new<S: AsRef<str>>(value: S) -> Result<Self, Error> {
66        Ok(Self {
67            value: value.as_ref().into(),
68            patterns: Self::get_format_patterns(value)?,
69        })
70    }
71
72    fn get_format_patterns<S: AsRef<str>>(value: S) -> Result<Vec<FormatPattern>, Error> {
73        let format_pattern = Regex::new(FORMAT_PATTERN)?;
74        let format_matches: Vec<_> = format_pattern
75            .find_iter(value.as_ref())
76            .map(|m| m.as_str().to_string())
77            .collect();
78        trace!("{:?}", format_matches);
79        if format_matches.is_empty() {
80            return Err(NoFormattingPatterns);
81        }
82
83        let mut format_patterns = Vec::with_capacity(format_matches.len());
84        for format_match in &format_matches {
85            let format_type = get_format_type(format_match)?;
86            let id = format_match
87                .get(2..format_match.len() - 1)
88                .unwrap_or_default()
89                .parse::<usize>()?;
90            format_patterns.push(FormatPattern::new(format_match, format_type, id - 1))
91        }
92        debug!("{:?}", format_patterns);
93        Ok(format_patterns)
94    }
95
96    /// Return the format string
97    pub fn value(&self) -> &str {
98        &self.value
99    }
100
101    /// Return the detected format patterns
102    pub(super) fn patterns(&self) -> &[FormatPattern] {
103        self.patterns.as_slice()
104    }
105}
106
107fn get_format_type<S: AsRef<str>>(value: S) -> Result<FormatType, Error> {
108    match value.as_ref() {
109        v if v.starts_with(DELIMITER_TYPE_PREFIX) => Ok(FormatType::Delimiter),
110        v if v.starts_with(SELECTOR_TYPE_PREFIX) => Ok(FormatType::Selector),
111        v if v.starts_with(EXTRACTOR_TYPE_PREFIX) => Ok(FormatType::Extractor),
112        _ => Err(UnknownFormatType(value.as_ref().into())),
113    }
114}