1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use core::{fmt, str::FromStr};
5use std::error::Error;
6
7macro_rules! drupal_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, DrupalError> {
14 let trimmed = input.trim();
15 if trimmed.is_empty() {
16 Err(DrupalError::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 = DrupalError;
35
36 fn from_str(input: &str) -> Result<Self, Self::Err> {
37 Self::new(input)
38 }
39 }
40 };
41}
42
43drupal_text_newtype!(DrupalModuleName);
44drupal_text_newtype!(DrupalThemeName);
45drupal_text_newtype!(DrupalRouteName);
46drupal_text_newtype!(DrupalEntityTypeId);
47drupal_text_newtype!(DrupalConfigObjectName);
48drupal_text_newtype!(DrupalPermission);
49
50#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
52pub enum DrupalExtensionKind {
53 Module,
54 Theme,
55 Profile,
56}
57
58impl DrupalExtensionKind {
59 pub const fn as_str(self) -> &'static str {
60 match self {
61 Self::Module => "module",
62 Self::Theme => "theme",
63 Self::Profile => "profile",
64 }
65 }
66}
67
68#[derive(Clone, Debug, Eq, PartialEq)]
70pub struct DrupalMetadataReference {
71 name: String,
72 kind: DrupalExtensionKind,
73}
74
75impl DrupalMetadataReference {
76 pub fn new(name: &str, kind: DrupalExtensionKind) -> Result<Self, DrupalError> {
77 let trimmed = name.trim();
78 if trimmed.is_empty() {
79 Err(DrupalError::Empty)
80 } else {
81 Ok(Self {
82 name: trimmed.to_string(),
83 kind,
84 })
85 }
86 }
87
88 pub fn name(&self) -> &str {
89 &self.name
90 }
91
92 pub const fn kind(&self) -> DrupalExtensionKind {
93 self.kind
94 }
95}
96
97#[derive(Clone, Copy, Debug, Eq, PartialEq)]
99pub enum DrupalError {
100 Empty,
101}
102
103impl fmt::Display for DrupalError {
104 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
105 formatter.write_str("Drupal metadata cannot be empty")
106 }
107}
108
109impl Error for DrupalError {}
110
111#[cfg(test)]
112mod tests {
113 use super::{
114 DrupalError, DrupalExtensionKind, DrupalMetadataReference, DrupalModuleName,
115 DrupalPermission, DrupalRouteName,
116 };
117
118 #[test]
119 fn builds_drupal_metadata() -> Result<(), DrupalError> {
120 let module = DrupalModuleName::new("book_tools")?;
121 let route = DrupalRouteName::new("book_tools.index")?;
122 let permission = DrupalPermission::new("administer book tools")?;
123 let reference = DrupalMetadataReference::new("book_tools", DrupalExtensionKind::Module)?;
124
125 assert_eq!(module.as_str(), "book_tools");
126 assert_eq!(route.as_str(), "book_tools.index");
127 assert_eq!(permission.as_str(), "administer book tools");
128 assert_eq!(reference.kind().as_str(), "module");
129 Ok(())
130 }
131}