Skip to main content

use_laravel/
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! laravel_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, LaravelError> {
14                let trimmed = input.trim();
15                if trimmed.is_empty() {
16                    Err(LaravelError::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 = LaravelError;
35
36            fn from_str(input: &str) -> Result<Self, Self::Err> {
37                Self::new(input)
38            }
39        }
40    };
41}
42
43laravel_text_newtype!(LaravelRouteName);
44laravel_text_newtype!(LaravelMiddlewareName);
45laravel_text_newtype!(ArtisanCommandName);
46laravel_text_newtype!(LaravelMigrationName);
47laravel_text_newtype!(ServiceProviderName);
48laravel_text_newtype!(LaravelConfigKey);
49
50/// Laravel metadata kind.
51#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
52pub enum LaravelMetadataKind {
53    Route,
54    Middleware,
55    ArtisanCommand,
56    Migration,
57    ServiceProvider,
58    ConfigKey,
59}
60
61impl LaravelMetadataKind {
62    pub const fn as_str(self) -> &'static str {
63        match self {
64            Self::Route => "route",
65            Self::Middleware => "middleware",
66            Self::ArtisanCommand => "artisan-command",
67            Self::Migration => "migration",
68            Self::ServiceProvider => "service-provider",
69            Self::ConfigKey => "config-key",
70        }
71    }
72}
73
74/// Laravel metadata reference.
75#[derive(Clone, Debug, Eq, PartialEq)]
76pub struct LaravelMetadata {
77    name: String,
78    kind: LaravelMetadataKind,
79}
80
81impl LaravelMetadata {
82    pub fn new(name: &str, kind: LaravelMetadataKind) -> Result<Self, LaravelError> {
83        let trimmed = name.trim();
84        if trimmed.is_empty() {
85            Err(LaravelError::Empty)
86        } else {
87            Ok(Self {
88                name: trimmed.to_string(),
89                kind,
90            })
91        }
92    }
93
94    pub fn name(&self) -> &str {
95        &self.name
96    }
97
98    pub const fn kind(&self) -> LaravelMetadataKind {
99        self.kind
100    }
101}
102
103/// Error returned when Laravel metadata is invalid.
104#[derive(Clone, Copy, Debug, Eq, PartialEq)]
105pub enum LaravelError {
106    Empty,
107}
108
109impl fmt::Display for LaravelError {
110    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
111        formatter.write_str("Laravel metadata cannot be empty")
112    }
113}
114
115impl Error for LaravelError {}
116
117#[cfg(test)]
118mod tests {
119    use super::{
120        ArtisanCommandName, LaravelConfigKey, LaravelError, LaravelMetadata, LaravelMetadataKind,
121        LaravelRouteName,
122    };
123
124    #[test]
125    fn builds_laravel_metadata() -> Result<(), LaravelError> {
126        let route = LaravelRouteName::new("books.index")?;
127        let command = ArtisanCommandName::new("books:sync")?;
128        let config = LaravelConfigKey::new("cache.default")?;
129        let metadata = LaravelMetadata::new(route.as_str(), LaravelMetadataKind::Route)?;
130
131        assert_eq!(route.as_str(), "books.index");
132        assert_eq!(command.as_str(), "books:sync");
133        assert_eq!(config.as_str(), "cache.default");
134        assert_eq!(metadata.kind().as_str(), "route");
135        Ok(())
136    }
137}