Skip to main content

use_wordpress_hook/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::{fmt, str::FromStr};
5use std::error::Error;
6
7/// WordPress hook name metadata.
8#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
9pub struct HookName(String);
10
11impl HookName {
12    pub fn new(input: &str) -> Result<Self, WordPressHookError> {
13        let trimmed = input.trim();
14        if trimmed.is_empty() {
15            Err(WordPressHookError::Empty)
16        } else {
17            Ok(Self(trimmed.to_string()))
18        }
19    }
20
21    pub fn as_str(&self) -> &str {
22        &self.0
23    }
24}
25
26impl fmt::Display for HookName {
27    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28        formatter.write_str(self.as_str())
29    }
30}
31
32impl FromStr for HookName {
33    type Err = WordPressHookError;
34
35    fn from_str(input: &str) -> Result<Self, Self::Err> {
36        Self::new(input)
37    }
38}
39
40/// WordPress hook kind metadata.
41#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
42pub enum HookKind {
43    Action,
44    Filter,
45}
46
47impl HookKind {
48    pub const fn as_str(self) -> &'static str {
49        match self {
50            Self::Action => "action",
51            Self::Filter => "filter",
52        }
53    }
54}
55
56/// WordPress hook priority metadata.
57#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
58pub struct HookPriority(u16);
59
60impl HookPriority {
61    pub const DEFAULT: Self = Self(10);
62
63    pub const fn new(value: u16) -> Self {
64        Self(value)
65    }
66
67    pub const fn get(self) -> u16 {
68        self.0
69    }
70}
71
72/// WordPress callback metadata.
73#[derive(Clone, Debug, Eq, PartialEq)]
74pub struct HookCallbackMetadata {
75    name: String,
76    accepted_args: u8,
77}
78
79impl HookCallbackMetadata {
80    pub fn new(name: &str) -> Self {
81        Self {
82            name: name.trim().to_string(),
83            accepted_args: 1,
84        }
85    }
86
87    pub const fn with_accepted_args(mut self, accepted_args: u8) -> Self {
88        self.accepted_args = accepted_args;
89        self
90    }
91
92    pub fn name(&self) -> &str {
93        &self.name
94    }
95
96    pub const fn accepted_args(&self) -> u8 {
97        self.accepted_args
98    }
99}
100
101/// WordPress hook reference metadata.
102#[derive(Clone, Debug, Eq, PartialEq)]
103pub struct HookReference {
104    name: HookName,
105    kind: HookKind,
106    priority: HookPriority,
107    callback: Option<HookCallbackMetadata>,
108}
109
110impl HookReference {
111    pub const fn new(name: HookName, kind: HookKind) -> Self {
112        Self {
113            name,
114            kind,
115            priority: HookPriority::DEFAULT,
116            callback: None,
117        }
118    }
119
120    pub const fn with_priority(mut self, priority: HookPriority) -> Self {
121        self.priority = priority;
122        self
123    }
124
125    pub fn with_callback(mut self, callback: HookCallbackMetadata) -> Self {
126        self.callback = Some(callback);
127        self
128    }
129
130    pub const fn name(&self) -> &HookName {
131        &self.name
132    }
133
134    pub const fn kind(&self) -> HookKind {
135        self.kind
136    }
137
138    pub const fn priority(&self) -> HookPriority {
139        self.priority
140    }
141
142    pub const fn callback(&self) -> Option<&HookCallbackMetadata> {
143        self.callback.as_ref()
144    }
145}
146
147/// Error returned when WordPress hook metadata is invalid.
148#[derive(Clone, Copy, Debug, Eq, PartialEq)]
149pub enum WordPressHookError {
150    Empty,
151}
152
153impl fmt::Display for WordPressHookError {
154    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
155        formatter.write_str("WordPress hook metadata cannot be empty")
156    }
157}
158
159impl Error for WordPressHookError {}
160
161#[cfg(test)]
162mod tests {
163    use super::{
164        HookCallbackMetadata, HookKind, HookName, HookPriority, HookReference, WordPressHookError,
165    };
166
167    #[test]
168    fn builds_hook_reference() -> Result<(), WordPressHookError> {
169        let hook = HookReference::new(HookName::new("init")?, HookKind::Action)
170            .with_priority(HookPriority::new(20))
171            .with_callback(HookCallbackMetadata::new("register_books").with_accepted_args(2));
172
173        assert_eq!(hook.name().as_str(), "init");
174        assert_eq!(hook.priority().get(), 20);
175        assert_eq!(hook.callback().expect("callback").accepted_args(), 2);
176        Ok(())
177    }
178}