Skip to main content

use_wordpress/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::{fmt, str::FromStr};
5use std::error::Error;
6
7macro_rules! wp_text_newtype {
8    ($name:ident) => {
9        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
10        pub struct $name(String);
11
12        impl $name {
13            pub fn new(input: &str) -> Result<Self, WordPressError> {
14                let trimmed = input.trim();
15                if trimmed.is_empty() {
16                    Err(WordPressError::Empty)
17                } else {
18                    Ok(Self(trimmed.to_string()))
19                }
20            }
21
22            pub fn as_str(&self) -> &str {
23                &self.0
24            }
25        }
26
27        impl fmt::Display for $name {
28            fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
29                formatter.write_str(self.as_str())
30            }
31        }
32
33        impl FromStr for $name {
34            type Err = WordPressError;
35
36            fn from_str(input: &str) -> Result<Self, Self::Err> {
37                Self::new(input)
38            }
39        }
40    };
41}
42
43wp_text_newtype!(WordPressText);
44wp_text_newtype!(WordPressPluginHeaderName);
45wp_text_newtype!(WordPressThemeFieldName);
46wp_text_newtype!(WordPressPostTypeSlug);
47wp_text_newtype!(WordPressTaxonomySlug);
48wp_text_newtype!(WordPressCapability);
49wp_text_newtype!(WordPressRestNamespace);
50wp_text_newtype!(WordPressRestRoute);
51
52/// WordPress plugin header metadata.
53#[derive(Clone, Debug, Eq, PartialEq)]
54pub struct WordPressPluginHeader {
55    name: WordPressPluginHeaderName,
56    value: WordPressText,
57}
58
59impl WordPressPluginHeader {
60    pub fn new(name: WordPressPluginHeaderName, value: WordPressText) -> Self {
61        Self { name, value }
62    }
63
64    pub const fn name(&self) -> &WordPressPluginHeaderName {
65        &self.name
66    }
67
68    pub const fn value(&self) -> &WordPressText {
69        &self.value
70    }
71}
72
73/// WordPress theme metadata field.
74#[derive(Clone, Debug, Eq, PartialEq)]
75pub struct WordPressThemeField {
76    name: WordPressThemeFieldName,
77    value: WordPressText,
78}
79
80impl WordPressThemeField {
81    pub fn new(name: WordPressThemeFieldName, value: WordPressText) -> Self {
82        Self { name, value }
83    }
84
85    pub const fn name(&self) -> &WordPressThemeFieldName {
86        &self.name
87    }
88
89    pub const fn value(&self) -> &WordPressText {
90        &self.value
91    }
92}
93
94/// WordPress primitive metadata kind.
95#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
96pub enum WordPressMetadataKind {
97    PluginHeader,
98    ThemeField,
99    PostType,
100    Taxonomy,
101    Capability,
102    RestRoute,
103}
104
105impl WordPressMetadataKind {
106    pub const fn as_str(self) -> &'static str {
107        match self {
108            Self::PluginHeader => "plugin-header",
109            Self::ThemeField => "theme-field",
110            Self::PostType => "post-type",
111            Self::Taxonomy => "taxonomy",
112            Self::Capability => "capability",
113            Self::RestRoute => "rest-route",
114        }
115    }
116}
117
118/// Error returned when WordPress metadata is invalid.
119#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120pub enum WordPressError {
121    Empty,
122}
123
124impl fmt::Display for WordPressError {
125    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
126        formatter.write_str("WordPress metadata cannot be empty")
127    }
128}
129
130impl Error for WordPressError {}
131
132#[cfg(test)]
133mod tests {
134    use super::{
135        WordPressCapability, WordPressError, WordPressMetadataKind, WordPressPluginHeader,
136        WordPressPluginHeaderName, WordPressPostTypeSlug, WordPressText,
137    };
138
139    #[test]
140    fn builds_wordpress_metadata() -> Result<(), WordPressError> {
141        let header = WordPressPluginHeader::new(
142            WordPressPluginHeaderName::new("Plugin Name")?,
143            WordPressText::new("Example Tools")?,
144        );
145        let post_type = WordPressPostTypeSlug::new("book")?;
146        let capability = WordPressCapability::new("edit_posts")?;
147
148        assert_eq!(header.name().as_str(), "Plugin Name");
149        assert_eq!(post_type.as_str(), "book");
150        assert_eq!(capability.as_str(), "edit_posts");
151        assert_eq!(WordPressMetadataKind::RestRoute.as_str(), "rest-route");
152        Ok(())
153    }
154}