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 #[doc = concat!("Constant for [`", stringify!($name), "`].")]
53 const $code_name: &str = $code;
54
55 #[doc = concat!("Constant string `", stringify!($code), "`.")]
56 #[derive(Eq, PartialEq)]
57 pub struct $name;
58
59 impl Default for $name {
60 fn default() -> Self {
61 Self
62 }
63 }
64
65 impl ::std::ops::Deref for $name {
66 type Target = str;
67
68 fn deref(&self) -> &Self::Target {
69 $code_name
70 }
71 }
72
73 impl ::std::fmt::Debug for $name {
74 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
75 ::std::fmt::Debug::fmt(&**self, f)
76 }
77 }
78 };
79}
80
81#[cfg(feature = "serde")]
83#[macro_export]
84macro_rules! constant_string_serde {
85 ($name:ident, $code_name:ident, $code:literal) => {
86 impl<'de> ::serde::Deserialize<'de> for $name {
87 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88 where
89 D: ::serde::Deserializer<'de>,
90 {
91 deserializer
92 .deserialize_any($crate::serde::MustBeStrVisitor($code_name))
93 .map(|()| Self)
94 }
95 }
96
97 impl ::serde::Serialize for $name {
98 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99 where
100 S: ::serde::Serializer,
101 {
102 serializer.serialize_str($code_name)
103 }
104 }
105 };
106}
107
108#[cfg(feature = "utoipa")]
110#[macro_export]
111macro_rules! constant_string_utoipa {
112 ($name:ident, $code_name:ident, $code:literal) => {
113 impl ::utoipa::PartialSchema for $name {
114 fn schema() -> ::utoipa::openapi::RefOr<::utoipa::openapi::schema::Schema> {
115 ::utoipa::openapi::schema::ObjectBuilder::new()
116 .schema_type(::utoipa::openapi::schema::Type::String)
117 .enum_values(Some([$code_name]))
118 .examples([$code_name])
119 .build()
120 .into()
121 }
122 }
123
124 impl ::utoipa::ToSchema for $name {}
125 };
126}
127
128#[cfg(test)]
129mod tests {
130 use std::ops::Deref;
131
132 constant_string!(Constant, CONSTANT, "constant");
133
134 #[test]
135 fn constant() {
136 assert_eq!(Constant.deref(), "constant");
137 assert_eq!(Constant.to_string(), "constant".to_owned());
138 }
139
140 #[test]
141 #[expect(clippy::default_constructed_unit_structs)]
142 fn default() {
143 assert_eq!(Constant::default().deref(), "constant");
144 assert_eq!(Constant::default().to_string(), "constant".to_owned());
145 }
146
147 #[cfg(feature = "serde")]
148 #[test]
149 fn serde() {
150 assert_eq!(
151 "\"constant\"",
152 serde_json::to_string(&Constant).expect("serializable value")
153 );
154 assert_eq!(
155 Constant,
156 serde_json::from_str("\"constant\"").expect("deserializable value")
157 );
158 }
159
160 #[cfg(feature = "utoipa")]
161 #[test]
162 fn utoipa() {
163 use utoipa::{
164 PartialSchema,
165 openapi::{
166 RefOr, Type,
167 schema::{Object, Schema},
168 },
169 };
170
171 assert_eq!(
172 RefOr::T(Schema::Object(
173 Object::builder()
174 .schema_type(Type::String)
175 .enum_values(Some(["constant"]))
176 .examples(["constant"])
177 .build()
178 )),
179 Constant::schema()
180 )
181 }
182}