1#![warn(missing_docs)]
2
3#[cfg(feature = "serde")]
6pub mod serde;
7
8#[cfg(all(feature = "serde", feature = "utoipa"))]
9#[macro_export]
11macro_rules! constant_string {
12 ($name:ident, $code_name:ident, $code:literal) => {
13 $crate::constant_string_base!($name, $code_name, $code);
14 $crate::constant_string_serde!($name, $code_name, $code);
15 $crate::constant_string_utoipa!($name, $code_name, $code);
16 };
17}
18
19#[cfg(all(feature = "serde", not(feature = "utoipa")))]
20#[macro_export]
22macro_rules! constant_string {
23 ($name:ident, $code_name:ident, $code:literal) => {
24 $crate::constant_string_base!($name, $code_name, $code);
25 $crate::constant_string_serde!($name, $code_name, $code);
26 };
27}
28
29#[cfg(all(not(feature = "serde"), feature = "utoipa"))]
30#[macro_export]
32macro_rules! constant_string {
33 ($name:ident, $code_name:ident, $code:literal) => {
34 $crate::constant_string_base!($name, $code_name, $code);
35 $crate::constant_string_utoipa!($name, $code_name, $code);
36 };
37}
38
39#[cfg(all(not(feature = "serde"), not(feature = "utoipa")))]
40#[macro_export]
42macro_rules! constant_string {
43 ($name:ident, $code_name:ident, $code:literal) => {
44 $crate::constant_string_base!($name, $code_name, $code);
45 };
46}
47
48#[macro_export]
50macro_rules! constant_string_base {
51 ($name:ident, $code_name:ident, $code:literal) => {
52 const $code_name: &str = $code;
53
54 #[derive(Eq, PartialEq)]
55 pub struct $name;
56
57 impl Default for $name {
58 fn default() -> Self {
59 Self
60 }
61 }
62
63 impl ::std::ops::Deref for $name {
64 type Target = str;
65
66 fn deref(&self) -> &Self::Target {
67 $code_name
68 }
69 }
70
71 impl ::std::fmt::Debug for $name {
72 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
73 ::std::fmt::Debug::fmt(&**self, f)
74 }
75 }
76 };
77}
78
79#[cfg(feature = "serde")]
81#[macro_export]
82macro_rules! constant_string_serde {
83 ($name:ident, $code_name:ident, $code:literal) => {
84 impl<'de> ::serde::Deserialize<'de> for $name {
85 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
86 where
87 D: ::serde::Deserializer<'de>,
88 {
89 deserializer
90 .deserialize_any($crate::serde::MustBeStrVisitor($code_name))
91 .map(|()| Self)
92 }
93 }
94
95 impl ::serde::Serialize for $name {
96 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
97 where
98 S: ::serde::Serializer,
99 {
100 serializer.serialize_str($code_name)
101 }
102 }
103 };
104}
105
106#[cfg(feature = "utoipa")]
108#[macro_export]
109macro_rules! constant_string_utoipa {
110 ($name:ident, $code_name:ident, $code:literal) => {
111 impl ::utoipa::PartialSchema for $name {
112 fn schema() -> ::utoipa::openapi::RefOr<::utoipa::openapi::schema::Schema> {
113 ::utoipa::openapi::schema::ObjectBuilder::new()
114 .schema_type(::utoipa::openapi::schema::Type::String)
115 .enum_values(Some([$code_name]))
116 .build()
117 .into()
118 }
119 }
120
121 impl ::utoipa::ToSchema for $name {}
122 };
123}
124
125#[cfg(test)]
126mod tests {
127 use std::ops::Deref;
128
129 constant_string!(Constant, CONSTANT, "constant");
130
131 #[test]
132 fn constant() {
133 assert_eq!(Constant.deref(), "constant");
134 assert_eq!(Constant.to_string(), "constant".to_owned());
135 }
136
137 #[test]
138 #[expect(clippy::default_constructed_unit_structs)]
139 fn default() {
140 assert_eq!(Constant::default().deref(), "constant");
141 assert_eq!(Constant::default().to_string(), "constant".to_owned());
142 }
143
144 #[cfg(feature = "serde")]
145 #[test]
146 fn serde() {
147 assert_eq!(
148 "\"constant\"",
149 serde_json::to_string(&Constant).expect("serializable value")
150 );
151 assert_eq!(
152 Constant,
153 serde_json::from_str("\"constant\"").expect("deserializable value")
154 );
155 }
156
157 #[cfg(feature = "utoipa")]
158 #[test]
159 fn utoipa() {
160 use utoipa::{
161 PartialSchema,
162 openapi::{
163 RefOr, Type,
164 schema::{Object, Schema},
165 },
166 };
167
168 assert_eq!(
169 RefOr::T(Schema::Object(
170 Object::builder()
171 .schema_type(Type::String)
172 .enum_values(Some(["constant"]))
173 .build()
174 )),
175 Constant::schema()
176 )
177 }
178}