use_wordpress_hook/
lib.rs1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::{fmt, str::FromStr};
5use std::error::Error;
6
7#[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#[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#[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#[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#[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#[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}