1use google_ai_schema_derive::AsSchema;
2use std::{
3 borrow::Cow,
4 cell::{Cell, RefCell, RefMut},
5 collections::{BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
6 ffi::{CStr, CString},
7 marker::PhantomData,
8 num::{
9 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
10 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
11 },
12 path::{Path, PathBuf},
13 rc::{Rc, Weak},
14 sync::{
15 atomic::{
16 AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16,
17 AtomicU32, AtomicU64, AtomicU8, AtomicUsize,
18 },
19 Arc, Mutex, RwLock, Weak as ArcWeak,
20 },
21};
22use tokio::sync::{Mutex as TMutex, RwLock as TRwLock};
23
24use crate::proto::{Schema, Type};
25
26pub type SchemaType = Type;
29
30#[derive(Clone, Copy, Debug)]
35pub enum SchemaFormat {
36 Float,
38 Double,
40 Int32,
42 Int64,
44 Enum,
46 None,
47}
48
49impl SchemaFormat {
50 fn as_str(self) -> &'static str {
52 match self {
53 Self::Float => "float",
54 Self::Double => "double",
55 Self::Int32 => "int32",
56 Self::Int64 => "int64",
57 Self::Enum => "enum",
58 Self::None => "",
59 }
60 }
61}
62
63impl Schema {
64 pub fn new(typ: SchemaType) -> Self {
66 Schema {
67 r#type: typ as i32,
68 ..Default::default()
69 }
70 }
71
72 pub fn new_object() -> Self {
74 Self::new(Type::Object)
75 }
76
77 pub fn new_array() -> Self {
79 Self::new(Type::Array)
80 }
81
82 pub fn new_number() -> Self {
84 Self::new(Type::Number)
85 }
86
87 pub fn new_integer() -> Self {
89 Self::new(Type::Integer)
90 }
91
92 pub fn new_string() -> Self {
94 Self::new(Type::String)
95 }
96
97 pub fn format(mut self, format: SchemaFormat) -> Self {
101 self.format = format.as_str().to_owned();
102 self
103 }
104
105 pub fn description(mut self, description: impl Into<String>) -> Self {
109 self.description = description.into();
110 self
111 }
112
113 pub fn nullable(mut self, nullable: bool) -> Self {
115 self.nullable = nullable;
116 self
117 }
118
119 pub fn into_enum<I, S>(self, r#enum: I) -> Self
131 where
132 I: IntoIterator<Item = S>,
133 S: Into<String>,
134 {
135 if self.is_string() {
137 let mut self_with_format = self.format(SchemaFormat::Enum);
138 self_with_format.r#enum = r#enum.into_iter().map(Into::into).collect();
139 self_with_format
140 } else {
141 self
142 }
143 }
144
145 pub fn items(mut self, items: Schema) -> Self {
158 if self.is_array() {
159 self.items = Some(Box::new(items));
160 }
161 self
162 }
163
164 pub fn max_items(mut self, max_items: i64) -> Self {
168 if self.is_array() {
169 self.max_items = max_items;
170 }
171 self
172 }
173
174 pub fn min_items(mut self, min_items: i64) -> Self {
178 if self.is_array() {
179 self.min_items = min_items;
180 }
181 self
182 }
183
184 pub fn property(mut self, name: impl Into<String>, schema: Schema) -> Self {
193 if self.is_object() {
194 self.properties.insert(name.into(), schema);
195 }
196 self
197 }
198
199 pub fn properties<I, S>(mut self, properties: I) -> Self
207 where
208 I: IntoIterator<Item = (S, Schema)>,
209 S: Into<String>,
210 {
211 if self.is_object() {
212 self.properties = properties.into_iter().map(|(k, v)| (k.into(), v)).collect();
213 }
214 self
215 }
216
217 pub fn required_field(mut self, name: impl Into<String>) -> Self {
224 if self.is_object() {
225 self.required.push(name.into());
226 }
227 self
228 }
229
230 pub fn required<I, S>(mut self, required: I) -> Self
237 where
238 I: IntoIterator<Item = S>,
239 S: Into<String>,
240 {
241 if self.is_object() {
242 self.required = required.into_iter().map(Into::into).collect();
243 }
244 self
245 }
246
247 fn is_object(&self) -> bool {
248 SchemaType::Object as i32 == self.r#type
249 }
250
251 fn is_array(&self) -> bool {
252 SchemaType::Array as i32 == self.r#type
253 }
254
255 fn is_string(&self) -> bool {
256 SchemaType::Object as i32 == self.r#type
257 }
258}
259
260#[cfg_attr(
360 not(no_diagnostic_namespace),
361 diagnostic::on_unimplemented(
362 note = "for local types consider adding `#[derive(google_ai_rs::AsSchema)]` to your `{Self}` type",
363 note = "for types from other crates consider the as_schema attribute or check if you can represent with the r#type and format attributes",
364 note = "consider google_ai_rs::Map for maps, and google_ai_rs::Tuple or derive AsSchemaWithSerde for tuples"
365 )
366)]
367pub trait AsSchema {
368 fn as_schema() -> Schema;
370}
371
372impl<T: AsSchema + ?Sized> AsSchema for &T {
373 fn as_schema() -> Schema {
374 T::as_schema()
375 }
376}
377
378impl<T: AsSchema + ?Sized> AsSchema for &mut T {
379 fn as_schema() -> Schema {
380 T::as_schema()
381 }
382}
383
384impl<T: AsSchema + ?Sized> AsSchema for *const T {
385 fn as_schema() -> Schema {
386 T::as_schema()
387 }
388}
389
390impl<T: AsSchema + ?Sized> AsSchema for *mut T {
391 fn as_schema() -> Schema {
392 T::as_schema()
393 }
394}
395
396macro_rules! wrapper_generic {
397 (
398 $($ty:ident <$($life:lifetime, )* T $(: $b0:ident $(+ $b:ident)*)* $(, $g:ident : $gb:ident)*>)*
399 ) => {
400 $(
401 impl<$($life,)* T $(, $g)*> AsSchema for $ty<$($life,)* T $(, $g)*>
402 where
403 T: AsSchema $(+ $b0 $(+ $b)*)* + ?Sized,
404 $($g: $gb,)*
405 {
406 fn as_schema() -> Schema {
407 T::as_schema()
408 }
409 }
410 )*
411 };
412}
413
414wrapper_generic! {
415 Box<T>
416 Arc<T>
417 Rc<T>
418 Mutex<T>
419 RwLock<T>
420 TMutex<T>
421 TRwLock<T>
422 Weak<T>
423 ArcWeak<T>
424 Cell<T>
425 RefCell<T>
426 PhantomData<T>
427 RefMut<'a, T>
428}
429
430impl<'a, T: AsSchema + ToOwned + ?Sized + 'a> AsSchema for Cow<'a, T> {
431 fn as_schema() -> Schema {
432 T::as_schema()
433 }
434}
435
436macro_rules! number {
437 ($($n:ident, $ty:ident, $format:ident)*) => {
438 $(impl AsSchema for $n {
439 fn as_schema() -> Schema {
440 Schema {
441 r#type: SchemaType::$ty as i32,
442 format: SchemaFormat::$format.as_str().into(),
443 ..Default::default()
444 }
445 }
446 })*
447 };
448}
449
450number! {
451 usize, Number, None
452 u8, Number, None
453 u16, Number, None
454 u32, Number, None
455 u64, Number, None
456 u128, Number, None
457 AtomicUsize, Number, None
458 AtomicU8, Number, None
459 AtomicU16, Number, None
460 AtomicU32, Number, None
461 AtomicU64, Number, None
462 NonZeroUsize, Number, None
463 NonZeroU8, Number, None
464 NonZeroU16, Number, None
465 NonZeroU32, Number, None
466 NonZeroU64, Number, None
467 NonZeroU128, Number, None
468}
469
470number! {
471 isize, Integer, None
472 i8, Integer, None
473 i16, Integer, None
474 i32, Integer, Int32
475 i64, Integer, Int64
476 i128, Integer, None
477 AtomicIsize, Integer, None
478 AtomicI8, Integer, None
479 AtomicI16, Integer, None
480 AtomicI32, Integer, Int32
481 AtomicI64, Integer, Int64
482 NonZeroIsize, Integer, None
483 NonZeroI8, Integer, None
484 NonZeroI16, Integer, None
485 NonZeroI32, Integer, Int32
486 NonZeroI64, Integer, Int64
487 NonZeroI128, Integer, None
488}
489
490number! {
491 f32, Number, Float
492 f64, Number, Double
493}
494
495macro_rules! string {
496 ($($n:ident)*) => {
497 $(
498 impl AsSchema for $n {
499 fn as_schema() -> Schema {
500 Schema {
501 r#type: SchemaType::String as i32,
502 ..Default::default()
503 }
504 }
505 })*
506 };
507}
508
509string! {
510 str
511 String
512 Path
513 PathBuf
514 char }
516
517impl AsSchema for bool {
518 fn as_schema() -> Schema {
519 Schema {
520 r#type: SchemaType::Boolean as i32,
521 ..Default::default()
522 }
523 }
524}
525
526impl AsSchema for AtomicBool {
527 fn as_schema() -> Schema {
528 bool::as_schema()
529 }
530}
531
532macro_rules! list_generic {
533 (
534 $($ty:ident <T $(: $b0:ident $(+ $b:ident)*)* $(, $g:ident : $gb:ident)*>)*
535 ) => {
536 $(
537 impl<T $(, $g)*> AsSchema for $ty<T $(, $g)*>
538 where
539 T: AsSchema $(+ $b0 $(+ $b)*)*,
540 $($g: $gb,)*
541 {
542 fn as_schema() -> Schema {
543 Schema {
544 r#type: SchemaType::Array as i32,
545 items: Some(Box::new(T::as_schema())),
546 nullable: true,
547 ..Default::default()
548 }
549 }
550 }
551 )*
552 };
553}
554
555list_generic! {
556 LinkedList<T>
557 Vec<T>
558 VecDeque<T>
559 HashSet<T>
560 BTreeSet<T>
561 BinaryHeap<T>
562}
563
564impl AsSchema for CStr {
565 fn as_schema() -> Schema {
566 Vec::<u8>::as_schema()
567 }
568}
569
570impl AsSchema for CString {
571 fn as_schema() -> Schema {
572 Vec::<u8>::as_schema()
573 }
574}
575
576impl<T: AsSchema, const N: usize> AsSchema for [T; N] {
577 fn as_schema() -> Schema {
578 Schema {
579 r#type: SchemaType::Array as i32,
580 nullable: true,
581 items: Some(Box::new(T::as_schema())),
582 max_items: N as i64,
583 min_items: N as i64,
584 ..Default::default()
585 }
586 }
587}
588
589impl AsSchema for () {
590 fn as_schema() -> Schema {
591 Schema {
592 r#type: SchemaType::Array as i32,
593 nullable: true,
594 ..Default::default()
595 }
596 }
597}
598
599impl<T: AsSchema> AsSchema for Option<T> {
600 fn as_schema() -> Schema {
601 let mut schema = T::as_schema();
602 schema.nullable = true;
603 schema
604 }
605}
606
607use std::fmt::Debug;
608use std::ops::{Deref, DerefMut};
609
610macro_rules! custom_wrapper_utils {
611 ($($name:ident)*) => {
612 $(impl<T> Debug for $name<T>
613 where
614 T: Debug,
615 {
616 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
617 T::fmt(&self.inner, f)
618 }
619 }
620
621 impl<T> Deref for $name<T> {
622 type Target = T;
623
624 fn deref(&self) -> &Self::Target {
625 &self.inner
626 }
627 }
628
629 impl<T> DerefMut for $name<T> {
630 fn deref_mut(&mut self) -> &mut Self::Target {
631 &mut self.inner
632 }
633 }
634
635 impl<T> From<T> for $name<T> {
636 fn from(value: T) -> Self {
637 Self::new(value)
638 }
639 }
640
641 impl<T> IntoIterator for $name<T>
642 where
643 T: IntoIterator
644 {
645 type Item = T::Item;
646 type IntoIter = T::IntoIter;
647
648 fn into_iter(self) -> Self::IntoIter {
649 self.inner.into_iter()
650 }
651 }
652
653 impl<'a, T> IntoIterator for &'a $name<T>
654 where
655 &'a T: IntoIterator
656 {
657 type Item = <&'a T as IntoIterator>::Item;
658 type IntoIter = <&'a T as IntoIterator>::IntoIter;
659
660 fn into_iter(self) -> Self::IntoIter {
661 self.inner.into_iter()
662 }
663 }
664
665
666 impl<'a, T> IntoIterator for &'a mut $name<T>
667 where
668 &'a mut T: IntoIterator
669 {
670 type Item = <&'a mut T as IntoIterator>::Item;
671 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
672
673 fn into_iter(self) -> Self::IntoIter {
674 self.inner.into_iter()
675 }
676 }
677
678 impl<T> $name<T> {
679 pub fn new(inner: T) -> Self {
680 Self { inner }
681 }
682
683 pub fn into_inner(self) -> T {
684 self.inner
685 }
686 })*
687 };
688}
689
690custom_wrapper_utils! {
691 Tuple
692 Map
693}
694
695#[derive(Default)]
753pub struct Map<T: ?Sized> {
754 inner: T,
755}
756
757impl<T> AsSchema for Map<T>
758where
759 T: MapTrait,
760 T::Key: AsSchema,
761 T::Value: AsSchema,
762{
763 fn as_schema() -> Schema {
764 let mut schema = Vec::<Entry<T>>::as_schema();
765 if let Some(description) = T::DESCRIPTION {
766 schema.description = description.to_owned()
767 }
768 schema
769 }
770}
771
772pub trait MapTrait {
790 type Key;
791 type Value;
792 const KEY_IDENT: &str = "key";
793 const VALUE_IDENT: &str = "value";
794 const DESCRIPTION: Option<&str> = None;
795}
796
797impl<K, V> MapTrait for HashMap<K, V> {
798 type Key = K;
799
800 type Value = V;
801}
802
803#[allow(dead_code)]
823#[derive(AsSchema)]
824#[schema(crate_path = "crate", rename_all_with = "Self::rename_idents")]
825struct Entry<T>
826where
827 T: MapTrait,
828{
829 pub(super) key: T::Key,
830 pub(super) value: T::Value,
831}
832
833impl<T> Entry<T>
834where
835 T: MapTrait,
836{
837 fn rename_idents(f: &str) -> String {
838 match f {
839 "key" => T::KEY_IDENT.to_owned(),
840 "value" => T::VALUE_IDENT.to_owned(),
841 _ => panic!("{f}"),
842 }
843 }
844}
845
846#[derive(Default)]
884pub struct Tuple<T: ?Sized> {
885 inner: T,
886}
887
888macro_rules! tuple {
890 (
891 $(($($T:ident)*))*
892 ) => {
893 $(impl<$($T, )*> AsSchema for Tuple<($($T, )*)>
894 where
895 $($T: AsSchema),*
896 {
897 fn as_schema() -> Schema {
898 #[derive(google_ai_schema_derive::AsSchemaWithSerde)]
899 #[schema(crate_path = "crate")]
900 struct InnerTupleHelper<$($T, )*>($($T, )*);
901
902 #[cfg(feature = "serde")]
903 #[allow(non_local_definitions)]
904 impl<'de, $($T, )*> serde::Deserialize<'de> for Tuple<($($T, )*)>
905 where
906 $($T: serde::Deserialize<'de> + Sized),*
907 {
908 #[allow(non_snake_case)]
909 #[inline]
910 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
911 where
912 D: serde::Deserializer<'de>,
913 {
914 let inner = InnerTupleHelper::<$($T, )*>::deserialize(deserializer)?;
916 let InnerTupleHelper($($T, )*) = inner;
917 let inner = ($($T, )*);
918 Ok(Self{inner})
919 }
920 }
921
922 InnerTupleHelper::<$($T, )*>::as_schema()
923 }
924 })*
925 };
926}
927
928tuple! {
929 ()
930 (T0)
931 (T0 T1)
932 (T0 T1 T2)
933 (T0 T1 T2 T3)
934 (T0 T1 T2 T3 T4)
935 (T0 T1 T2 T3 T4 T5)
936 (T0 T1 T2 T3 T4 T5 T6)
937 (T0 T1 T2 T3 T4 T5 T6 T7)
938 (T0 T1 T2 T3 T4 T5 T6 T7 T8)
939 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9)
940 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10)
941 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11)
942 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12)
943 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13)
944 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14)
945 (T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15)
946}
947
948#[cfg(feature = "serde")]
949mod serde_support {
950 use std::marker::PhantomData;
951
952 use common::{EPhantomData, MapAccessSeqAccess};
953 use serde::{de::Visitor, forward_to_deserialize_any, Deserialize, Deserializer};
954
955 use super::{Entry, Map, MapTrait};
956
957 impl<'de, T> Deserialize<'de> for Entry<T>
958 where
959 T: MapTrait,
960 T::Key: Deserialize<'de>,
961 T::Value: Deserialize<'de>,
962 {
963 #[inline]
964 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
965 where
966 D: Deserializer<'de>,
967 {
968 deserializer.deserialize_struct(
969 "Entry",
970 &[T::KEY_IDENT, T::VALUE_IDENT],
971 EPhantomData(PhantomData::<Self>),
972 )
973 }
974 }
975
976 impl<'de, T> Deserialize<'de> for Map<T>
977 where
978 T: MapTrait + Deserialize<'de>,
979 {
980 #[inline]
981 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
982 where
983 D: Deserializer<'de>,
984 {
985 struct MapToSeq<D, T> {
986 inner: D,
987 _marker: PhantomData<T>,
988 }
989
990 impl<'de, D, T> Deserializer<'de> for MapToSeq<D, T>
991 where
992 D: Deserializer<'de>,
993 T: MapTrait,
994 {
995 type Error = D::Error;
996
997 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
998 where
999 V: serde::de::Visitor<'de>,
1000 {
1001 struct SeqMapV<V, T> {
1002 inner: V,
1003 _map: PhantomData<T>,
1004 }
1005
1006 impl<'de, V, T> Visitor<'de> for SeqMapV<V, T>
1007 where
1008 V: Visitor<'de>,
1009 T: MapTrait,
1010 {
1011 type Value = V::Value;
1012
1013 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1014 write!(
1015 f,
1016 "an array of object with two fields representing the key and value of a map"
1017 )
1018 }
1019
1020 fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
1021 where
1022 A: serde::de::SeqAccess<'de>,
1023 {
1024 self.inner.visit_map(MapAccessSeqAccess {
1025 _entry: PhantomData::<Entry<T>>,
1026 seq,
1027 })
1028 }
1029 }
1030
1031 self.inner.deserialize_seq(SeqMapV {
1032 inner: visitor,
1033 _map: self._marker,
1034 })
1035 }
1036
1037 forward_to_deserialize_any! {
1038 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
1039 bytes byte_buf option unit unit_struct newtype_struct seq tuple
1040 tuple_struct map struct enum identifier ignored_any
1041 }
1042
1043 fn is_human_readable(&self) -> bool {
1044 self.inner.is_human_readable()
1045 }
1046 }
1047
1048 T::deserialize(MapToSeq {
1049 inner: deserializer,
1050 _marker: PhantomData::<T>,
1051 })
1052 .map(Into::into)
1053 }
1054 }
1055
1056 #[cfg(test)]
1057 mod test {
1058 use std::collections::HashMap;
1059
1060 use crate::AsSchema;
1061
1062 use super::*;
1063
1064 #[test]
1065 fn map() {
1066 #[derive(Deserialize, AsSchema, Hash, Eq, PartialEq, Debug)]
1067 #[schema(crate_path = "crate")]
1068 struct Question {
1069 intensity: i64,
1070 raw: String,
1071 }
1072
1073 #[derive(Deserialize, AsSchema, Debug, PartialEq, Eq)]
1074 #[schema(crate_path = "crate")]
1075 struct Answer {
1076 uniqueness: i64,
1077 raw: String,
1078 }
1079
1080 #[derive(PartialEq, Eq, Deserialize, Debug)]
1081 #[serde(transparent)]
1082 struct Snippet(HashMap<Question, Answer>);
1083
1084 impl MapTrait for Snippet {
1085 type Key = Question;
1086 type Value = Answer;
1087
1088 const KEY_IDENT: &str = "question";
1089 const VALUE_IDENT: &str = "answer";
1090 }
1091
1092 assert_eq!(
1093 Map::<Snippet>::as_schema(),
1094 Vec::<Entry<Snippet>>::as_schema()
1095 );
1096
1097 let response = r#"[{"question": {
1098 "intensity": 50,
1099 "raw": "What is the blah blah blah?"
1100 }, "answer": {
1101 "uniqueness": 3,
1102 "raw": "Hmmmm hmm."
1103 }}]"#;
1104
1105 let m: Map<Snippet> = serde_json::from_str(response).unwrap();
1106
1107 assert_eq!(
1108 m.into_inner(),
1109 Snippet(
1110 [(
1111 Question {
1112 intensity: 50,
1113 raw: "What is the blah blah blah?".into(),
1114 },
1115 Answer {
1116 uniqueness: 3,
1117 raw: "Hmmmm hmm.".into(),
1118 }
1119 )]
1120 .into()
1121 )
1122 )
1123 }
1124 }
1125
1126 mod common {
1127 use std::marker::PhantomData;
1128
1129 use serde::{
1130 de::{DeserializeSeed, MapAccess, SeqAccess, Visitor},
1131 Deserialize, Deserializer,
1132 };
1133
1134 use crate::schema::{Entry, MapTrait};
1135
1136 pub(super) struct MapAccessSeqAccess<E, S> {
1137 pub(super) _entry: PhantomData<E>,
1138 pub(super) seq: S,
1139 }
1140
1141 impl<'de, E, S> MapAccess<'de> for MapAccessSeqAccess<E, S>
1142 where
1143 E: UnorderedEntry,
1144 S: SeqAccess<'de>,
1145 {
1146 type Error = S::Error;
1147
1148 fn next_entry_seed<K, V>(
1149 &mut self,
1150 kseed: K,
1151 vseed: V,
1152 ) -> Result<Option<(K::Value, V::Value)>, Self::Error>
1153 where
1154 K: DeserializeSeed<'de>,
1155 V: DeserializeSeed<'de>,
1156 {
1157 self.seq.next_element_seed(UnorderedEntrySeed {
1158 key_seed: kseed,
1159 value_seed: vseed,
1160 _entry: self._entry,
1161 })
1162 }
1163
1164 fn next_key_seed<K>(&mut self, _seed: K) -> Result<Option<K::Value>, Self::Error>
1168 where
1169 K: DeserializeSeed<'de>,
1170 {
1171 Err(<Self::Error as serde::de::Error>::custom(
1172 "Cannot call next_key_seed on MapAccessSeqAccess. \
1173 Use next_entry_seed to process key-value pairs atomically",
1174 ))
1175 }
1176
1177 fn next_value_seed<V>(&mut self, _seed: V) -> Result<V::Value, Self::Error>
1178 where
1179 V: DeserializeSeed<'de>,
1180 {
1181 Err(<Self::Error as serde::de::Error>::custom(
1182 "Cannot call next_value_seed on MapAccessSeqAccess. \
1183 Use next_entry_seed to process key-value pairs atomically",
1184 ))
1185 }
1186
1187 fn size_hint(&self) -> Option<usize> {
1188 self.seq.size_hint()
1189 }
1190 }
1191
1192 pub(super) struct UnorderedEntrySeed<K, V, E> {
1194 pub(super) key_seed: K,
1195 pub(super) value_seed: V,
1196 pub(super) _entry: PhantomData<E>,
1197 }
1198
1199 impl<'de, K, V, E> DeserializeSeed<'de> for UnorderedEntrySeed<K, V, E>
1200 where
1201 K: DeserializeSeed<'de>,
1202 V: DeserializeSeed<'de>,
1203 E: UnorderedEntry,
1204 {
1205 type Value = (K::Value, V::Value);
1206
1207 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
1208 where
1209 D: Deserializer<'de>,
1210 {
1211 deserializer.deserialize_struct(E::NAME, &[E::KEY_IDENT, E::VALUE_IDENT], self)
1212 }
1213 }
1214
1215 impl<'de, K, V, E> Visitor<'de> for UnorderedEntrySeed<K, V, E>
1216 where
1217 K: DeserializeSeed<'de>,
1218 V: DeserializeSeed<'de>,
1219 E: UnorderedEntry,
1220 {
1221 type Value = <Self as DeserializeSeed<'de>>::Value;
1222
1223 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1224 write!(f, "a struct representing a map entry")
1225 }
1226
1227 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
1228 where
1229 A: MapAccess<'de>,
1230 {
1231 let (mut key, mut value) = (None, None);
1232 let (mut key_seed, mut value_seed) = (Some(self.key_seed), Some(self.value_seed));
1233 let (key_ident, value_ident) = (E::KEY_IDENT, E::VALUE_IDENT);
1234
1235 macro_rules! try_fix_once {
1236 ($seed:tt, $target:tt, $field:expr) => {{
1237 if $target.is_none() {
1238 $target = Some(map.next_value_seed($seed.take().unwrap())?);
1239 } else {
1240 return Err(serde::de::Error::duplicate_field($field));
1241 }
1242 }};
1243 }
1244
1245 while let Some(field_ident) = map.next_key()? {
1246 match field_ident {
1247 key_field if key_field == key_ident => {
1248 try_fix_once!(key_seed, key, E::KEY_IDENT);
1249 }
1250 value_field if value_field == value_ident => {
1251 try_fix_once!(value_seed, value, E::VALUE_IDENT);
1252 }
1253 _ => {
1254 return Err(<A::Error as serde::de::Error>::unknown_field(
1255 field_ident,
1256 &[E::KEY_IDENT, E::VALUE_IDENT],
1257 ))
1258 }
1259 }
1260 }
1261
1262 match (key, value) {
1263 (Some(k), Some(v)) => Ok((k, v)),
1264 (None, _) => Err(<A::Error as serde::de::Error>::missing_field(E::KEY_IDENT)),
1265 (_, None) => Err(<A::Error as serde::de::Error>::missing_field(
1266 E::VALUE_IDENT,
1267 )),
1268 }
1269 }
1270 }
1271
1272 pub(super) trait UnorderedEntry {
1273 const NAME: &str;
1274 const KEY_IDENT: &str;
1275 const VALUE_IDENT: &str;
1276 }
1277
1278 impl<T: MapTrait> UnorderedEntry for Entry<T> {
1279 const NAME: &str = "Entry";
1280 const KEY_IDENT: &str = T::KEY_IDENT;
1281 const VALUE_IDENT: &str = T::VALUE_IDENT;
1282 }
1283
1284 pub(super) struct EPhantomData<T>(pub PhantomData<T>);
1285
1286 impl<'de, T> Visitor<'de> for EPhantomData<Entry<T>>
1287 where
1288 T: MapTrait,
1289 T::Key: Deserialize<'de>,
1290 T::Value: Deserialize<'de>,
1291 {
1292 type Value = Entry<T>;
1293
1294 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1295 write!(f, "a struct representing a map entry")
1296 }
1297
1298 fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
1299 where
1300 A: MapAccess<'de>,
1301 {
1302 let (key, value) = UnorderedEntrySeed {
1303 key_seed: PhantomData,
1304 value_seed: PhantomData,
1305 _entry: PhantomData::<Entry<T>>,
1306 }
1307 .visit_map(map)?;
1308
1309 Ok(Entry { key, value })
1310 }
1311 }
1312 }
1313}
1314
1315#[cfg(test)]
1316#[allow(dead_code)]
1317mod derive_test {
1318 use std::marker::PhantomData;
1319
1320 use super::AsSchema;
1321
1322 use crate::{Schema, SchemaType};
1323
1324 #[test]
1325 fn rename_all_with() {
1326 #[derive(AsSchema)]
1327 #[schema(crate_path = "crate")]
1328 #[schema(rename_all_with = "sAwCaSe")]
1329 struct S {
1330 field: (),
1331 field1: (),
1332 }
1333
1334 #[allow(non_snake_case)]
1335 fn sAwCaSe(former_name: &str) -> String {
1336 former_name
1337 .char_indices()
1338 .map(|(i, c)| {
1339 if i % 2 == 0 {
1340 c.to_ascii_lowercase()
1341 } else {
1342 c.to_ascii_uppercase()
1343 }
1344 })
1345 .collect()
1346 }
1347
1348 let expect = Schema {
1349 r#type: SchemaType::Object as i32,
1350 properties: [
1351 ("fIeLd".into(), <()>::as_schema()),
1352 ("fIeLd1".into(), <()>::as_schema()),
1353 ]
1354 .into(),
1355 required: vec!["fIeLd".into(), "fIeLd1".into()],
1356 ..Default::default()
1357 };
1358
1359 assert_eq!(S::as_schema(), expect)
1360 }
1361
1362 #[test]
1363 fn as_schema() {
1364 struct Wrapper<T>(T);
1365
1366 fn wrapper_as_schema<T: AsSchema>() -> Schema {
1367 T::as_schema()
1368 }
1369
1370 #[derive(AsSchema)]
1371 #[schema(crate_path = "crate")]
1372 struct S {
1373 #[schema(as_schema = "wrapper_as_schema::<String>")]
1374 field: Wrapper<String>,
1375 }
1376
1377 assert_eq!(
1378 S::as_schema(),
1379 Schema {
1380 r#type: SchemaType::Object.into(),
1381 properties: [("field".into(), String::as_schema())].into(),
1382 required: vec![("field".into())],
1383 ..Default::default()
1384 }
1385 )
1386 }
1387
1388 #[test]
1389 fn as_schema_generic() {
1390 struct Wrapper<T>(T);
1391
1392 fn wrapper_as_schema<T: AsSchema>() -> (Schema, PhantomData<Wrapper<T>>) {
1393 (T::as_schema(), PhantomData)
1394 }
1395
1396 #[derive(AsSchema)]
1397 #[schema(crate_path = "crate")]
1398 struct S {
1399 #[schema(as_schema_generic = "wrapper_as_schema")]
1400 field: Wrapper<String>,
1401 }
1402
1403 assert_eq!(
1404 S::as_schema(),
1405 Schema {
1406 r#type: SchemaType::Object.into(),
1407 properties: [("field".into(), String::as_schema())].into(),
1408 required: vec![("field".into())],
1409 ..Default::default()
1410 }
1411 )
1412 }
1413}