diff --git a/wfassoc/src/win32/concept.rs b/wfassoc/src/win32/concept.rs index 8878b54..8821997 100644 --- a/wfassoc/src/win32/concept.rs +++ b/wfassoc/src/win32/concept.rs @@ -782,10 +782,10 @@ pub struct FileName { impl FileName { /// Create a new file name. - /// + /// /// `filename` is the file name for validating. /// This function will validate whether given file name is legal in Windows, - /// in other words, checking whether it contain illegal words or Windows reserved name in given name + /// in other words, checking whether it contain illegal words or Windows reserved name in given name /// such as `?`, `COM` and etc. pub fn new(filename: &str) -> Result { Self::from_str(filename) @@ -817,7 +817,7 @@ impl Display for FileName { impl FromStr for FileName { type Err = ParseFileNameError; - + fn from_str(s: &str) -> Result { use windows_sys::Win32::UI::Shell::PathCleanupSpec; @@ -834,7 +834,80 @@ impl FromStr for FileName { } // Build self and return - Ok(Self { filename: s.to_string() }) + Ok(Self { + filename: s.to_string(), + }) + } +} + +// endregion + +// region: Verb + +pub type BadVerbError = ParseVerbError; + +/// The struct representing a verb when manipulating file +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Verb { + /// The validated verb name. + verb: String, +} + +impl Verb { + pub const OPEN: LazyLock = LazyLock::new(|| Verb::new("open").expect("unexpected bad verb")); + pub const EDIT: LazyLock = LazyLock::new(|| Verb::new("edit").expect("unexpected bad verb")); + pub const PLAY: LazyLock = LazyLock::new(|| Verb::new("play").expect("unexpected bad verb")); +} + +impl Verb { + /// Create a new verb. + /// + /// `verb` is the verb for validating. + /// This function will validate whether given verb is legal. + pub fn new(verb: &str) -> Result { + Self::from_str(verb) + } + + /// Get the validated verb name. + pub fn inner(&self) -> &str { + &self.verb + } +} + +/// The error occurs when constructing Verb with bad verb name. +#[derive(Debug, TeError)] +#[error("given verb \"{inner}\" is illegal")] +pub struct ParseVerbError { + inner: String, +} + +impl ParseVerbError { + fn new(inner: &str) -> Self { + Self { + inner: inner.to_string(), + } + } +} + +impl Display for Verb { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.verb.fmt(f) + } +} + +impl FromStr for Verb { + type Err = ParseVerbError; + + fn from_str(s: &str) -> Result { + static RE: LazyLock = LazyLock::new(|| { + Regex::new(r"^[a-zA-Z0-9_-]+$").expect("unexpected bad regex pattern string") + }); + match RE.captures(s) { + Some(_) => Ok(Self { + verb: s.to_string(), + }), + None => Err(ParseVerbError::new(s)), + } } } diff --git a/wfassoc/tests/concept.rs b/wfassoc/tests/concept.rs index 8c76014..7011862 100644 --- a/wfassoc/tests/concept.rs +++ b/wfassoc/tests/concept.rs @@ -254,3 +254,25 @@ fn test_file_name() { } // endregion + +// region: Verb + +#[test] +fn test_verb() { + fn ok_tester(s: &str) { + let rv = Verb::from_str(s); + assert!(rv.is_ok()); + let rv = rv.unwrap(); + assert_eq!(s, rv.inner()); + } + fn err_tester(s: &str) { + let rv = Verb::from_str(s); + assert!(rv.is_err()); + } + + ok_tester("Open"); + ok_tester("open"); + err_tester("Space Name"); +} + +// endregion