1use std::{
6 fmt::{self, Debug},
7 hash::Hash,
8 hash::Hasher,
9 ops::{Deref, DerefMut},
10};
11
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14pub struct Verbatim<T, Sch = T>(pub T, pub std::marker::PhantomData<Sch>);
27
28impl<T, Sch> Deref for Verbatim<T, Sch> {
29 type Target = T;
30
31 fn deref(&self) -> &Self::Target {
32 &self.0
33 }
34}
35
36impl<T, Sch> DerefMut for Verbatim<T, Sch> {
37 fn deref_mut(&mut self) -> &mut Self::Target {
38 &mut self.0
39 }
40}
41
42impl<T, Sch> AsRef<T> for Verbatim<T, Sch> {
43 fn as_ref(&self) -> &T {
44 &self.0
45 }
46}
47
48impl<T, Sch> AsMut<T> for Verbatim<T, Sch> {
49 fn as_mut(&mut self) -> &mut T {
50 &mut self.0
51 }
52}
53
54impl<T, Sch> Clone for Verbatim<T, Sch>
55where
56 T: Clone,
57{
58 fn clone(&self) -> Self {
59 Verbatim(self.0.clone(), std::marker::PhantomData::<Sch>)
60 }
61}
62
63impl<T, Sch> Copy for Verbatim<T, Sch> where T: Copy {}
64
65impl<T, Sch> Debug for Verbatim<T, Sch>
66where
67 T: Debug,
68{
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 self.0.fmt(f)
71 }
72}
73
74impl<T, Sch> PartialEq for Verbatim<T, Sch>
75where
76 T: PartialEq,
77{
78 fn eq(&self, other: &Self) -> bool {
79 self.0 == other.0
80 }
81}
82
83impl<T, Sch> Eq for Verbatim<T, Sch> where T: Eq {}
84
85impl<T, Sch> PartialOrd for Verbatim<T, Sch>
86where
87 T: PartialOrd,
88{
89 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
90 self.0.partial_cmp(&other.0)
91 }
92}
93
94impl<T, Sch> Ord for Verbatim<T, Sch>
95where
96 T: Ord,
97{
98 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
99 self.0.cmp(&other.0)
100 }
101}
102
103impl<T, Sch> Hash for Verbatim<T, Sch>
104where
105 T: Hash,
106{
107 fn hash<H: Hasher>(&self, state: &mut H) {
108 self.0.hash(state)
109 }
110}
111
112impl<T, Sch> Default for Verbatim<T, Sch>
113where
114 T: Default,
115{
116 fn default() -> Self {
117 Verbatim(T::default(), std::marker::PhantomData::<Sch>)
118 }
119}
120
121impl<T, Sch> From<T> for Verbatim<T, Sch> {
122 fn from(value: T) -> Self {
123 Verbatim(value, std::marker::PhantomData::<Sch>)
124 }
125}
126
127impl<T, Sch> Serialize for Verbatim<T, Sch>
128where
129 T: Serialize,
130{
131 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132 where
133 S: Serializer,
134 {
135 self.0.serialize(serializer)
136 }
137}
138
139impl<'de, T, Sch> Deserialize<'de> for Verbatim<T, Sch>
140where
141 T: Deserialize<'de>,
142{
143 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144 where
145 D: Deserializer<'de>,
146 {
147 let _g = with_should_not_transform_any();
148 T::deserialize(deserializer).map(|value| Verbatim(value, std::marker::PhantomData::<Sch>))
149 }
150}
151
152#[cfg(feature = "schemars")]
153impl<T, Sch> schemars::JsonSchema for Verbatim<T, Sch>
154where
155 Sch: schemars::JsonSchema,
156{
157 fn schema_name() -> String {
158 Sch::schema_name()
159 }
160
161 fn json_schema(generator: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
162 Sch::json_schema(generator)
163 }
164
165 fn is_referenceable() -> bool {
166 Sch::is_referenceable()
167 }
168
169 fn schema_id() -> std::borrow::Cow<'static, str> {
170 Sch::schema_id()
171 }
172
173 #[doc(hidden)]
174 fn _schemars_private_non_optional_json_schema(
175 generator: &mut schemars::gen::SchemaGenerator,
176 ) -> schemars::schema::Schema {
177 Sch::_schemars_private_non_optional_json_schema(generator)
178 }
179
180 #[doc(hidden)]
181 fn _schemars_private_is_option() -> bool {
182 Sch::_schemars_private_is_option()
183 }
184}
185
186#[cfg(feature = "schemars")]
187pub mod maybe_transformable {
189 use std::collections::BTreeMap;
190
191 const TRANSFORMABLE_STRING_PATTERN: &str = "^\\{.*\\}$";
192
193 fn make_stringable_field(schema: schemars::schema::Schema) -> schemars::schema::Schema {
196 let schemars::schema::Schema::Object(mut schema_object) = schema else {
197 return schema;
198 };
199
200 if let Some(obj) = &mut schema_object.object {
201 if let Some(add) = obj.additional_properties.take() {
202 obj.additional_properties = Some(Box::new(make_stringable_field(*add)));
203 }
204 }
205 if let Some(arr) = &mut schema_object.array {
206 if let Some(items) = arr.items.take() {
207 match items {
208 schemars::schema::SingleOrVec::Single(sch) => {
209 arr.items = Some(schemars::schema::SingleOrVec::Single(Box::new(
210 make_stringable_field(*sch),
211 )));
212 }
213 schemars::schema::SingleOrVec::Vec(schs) => {
214 arr.items = Some(schemars::schema::SingleOrVec::Vec(
215 schs.into_iter().map(make_stringable_field).collect(),
216 ));
217 }
218 }
219 }
220 }
221
222 let is_primitive = match schema_object.instance_type {
223 Some(schemars::schema::SingleOrVec::Single(ref mut ty)) => match **ty {
224 schemars::schema::InstanceType::Boolean
225 | schemars::schema::InstanceType::Integer
226 | schemars::schema::InstanceType::Number => true,
227 _ => false,
228 },
229 Some(schemars::schema::SingleOrVec::Vec(ref mut tys)) => {
230 tys.iter().any(|ty| match *ty {
231 schemars::schema::InstanceType::Boolean
232 | schemars::schema::InstanceType::Integer
233 | schemars::schema::InstanceType::Number => true,
234 _ => false,
235 })
236 }
237 _ => false,
238 };
239
240 if is_primitive {
241 let subschema = schemars::schema::SubschemaValidation {
242 any_of: Some(vec![
243 schemars::schema::Schema::Object(schema_object),
244 schemars::schema::Schema::Object(schemars::schema::SchemaObject {
245 instance_type: Some(schemars::schema::SingleOrVec::Single(Box::new(
246 schemars::schema::InstanceType::String,
247 ))),
248 string: Some(Box::new(schemars::schema::StringValidation {
249 pattern: Some(TRANSFORMABLE_STRING_PATTERN.to_string()),
250 ..Default::default()
251 })),
252 ..Default::default()
253 }),
254 ]),
255 ..Default::default()
256 };
257 schemars::schema::Schema::Object(schemars::schema::SchemaObject {
258 subschemas: Some(Box::new(subschema)),
259 ..Default::default()
260 })
261 } else {
262 schemars::schema::Schema::Object(schema_object)
263 }
264 }
265
266 pub fn maybe_transformable(schema: schemars::schema::Schema) -> schemars::schema::Schema {
268 if !SHOULD_GENERATE_PRE_TRANSFORMATION_SCHEMA.with(|flag| flag.get()) {
269 return schema;
270 }
271 let schemars::schema::Schema::Object(mut schema_object) = schema else {
272 return schema;
273 };
274
275 match &schema_object.instance_type {
276 Some(schemars::schema::SingleOrVec::Single(ty)) => match **ty {
277 schemars::schema::InstanceType::Object => {
278 if let Some(obj) = schema_object.object.take() {
281 let properties = obj
282 .properties
283 .into_iter()
284 .map(|(key, value)| (key, make_stringable_field(value)))
285 .collect::<BTreeMap<_, _>>();
286 let additional_properties = obj
287 .additional_properties
288 .map(|add| Box::new(make_stringable_field(*add)));
289 schema_object.object = Some(Box::new(schemars::schema::ObjectValidation {
290 properties,
291 additional_properties,
292 ..*obj
293 }));
294 }
295 }
296 schemars::schema::InstanceType::Array => {
297 if let Some(arr) = &mut schema_object.array {
299 if let Some(items) = arr.items.take() {
300 match items {
301 schemars::schema::SingleOrVec::Single(sch) => {
302 arr.items = Some(schemars::schema::SingleOrVec::Single(
303 Box::new(make_stringable_field(*sch)),
304 ));
305 }
306 schemars::schema::SingleOrVec::Vec(schs) => {
307 arr.items = Some(schemars::schema::SingleOrVec::Vec(
308 schs.into_iter().map(make_stringable_field).collect(),
309 ));
310 }
311 }
312 }
313 }
314 }
315 _ => {}
316 },
317 None => {
318 if let Some(subschemas) = &mut schema_object.subschemas {
319 if let Some(any_of) = &mut subschemas.any_of {
321 any_of.push(schemars::schema::Schema::Object(
323 schemars::schema::SchemaObject {
324 instance_type: Some(schemars::schema::SingleOrVec::Single(
325 Box::new(schemars::schema::InstanceType::String),
326 )),
327 string: Some(Box::new(schemars::schema::StringValidation {
328 pattern: Some(TRANSFORMABLE_STRING_PATTERN.to_string()),
329 ..Default::default()
330 })),
331 ..Default::default()
332 },
333 ));
334 }
335 if let Some(one_of) = &mut subschemas.one_of {
336 *one_of = one_of.drain(..).map(make_stringable_field).collect();
338 }
339 }
340 }
341 _ => {}
342 }
343
344 schemars::schema::Schema::Object(schema_object)
345 }
346
347 pub fn set_generate_pre_transformation_schema(value: bool) {
351 SHOULD_GENERATE_PRE_TRANSFORMATION_SCHEMA.with(|flag| flag.set(value));
352 }
353
354 thread_local! {
355 static SHOULD_GENERATE_PRE_TRANSFORMATION_SCHEMA: std::cell::Cell<bool> = const {
356 std::cell::Cell::new(false)
357 };
358 }
359}
360
361pub(crate) fn should_transform_any() -> bool {
362 SHOULD_TRANSFORM_ANY.with(|flag| flag.get())
363}
364
365pub(crate) struct ShouldTransformAnyGuard(bool);
366
367impl Drop for ShouldTransformAnyGuard {
368 fn drop(&mut self) {
369 SHOULD_TRANSFORM_ANY.with(|flag| flag.set(self.0));
370 }
371}
372
373pub(crate) fn with_should_not_transform_any() -> ShouldTransformAnyGuard {
374 let current = SHOULD_TRANSFORM_ANY.with(|flag| flag.get());
375 SHOULD_TRANSFORM_ANY.with(|flag| flag.set(false));
376 ShouldTransformAnyGuard(current)
377}
378
379thread_local! {
380 static SHOULD_TRANSFORM_ANY: std::cell::Cell<bool> = const {
381 std::cell::Cell::new(true)
382 };
383}