1use std::collections::{BTreeMap, BTreeSet, HashMap};
4
5use proc_macro2::{Punct, Spacing, TokenStream, TokenTree};
6use quote::{format_ident, quote, ToTokens};
7use schemars::schema::{Metadata, Schema};
8use syn::Path;
9use unicode_ident::is_xid_continue;
10
11use crate::{
12 enums::output_variant,
13 output::{OutputSpace, OutputSpaceMod},
14 sanitize,
15 structs::{generate_serde_attr, DefaultFunction},
16 util::{get_type_name, metadata_description, unique, TypePatch},
17 Case, DefaultImpl, Name, Result, TypeId, TypeSpace, TypeSpaceImpl,
18};
19
20#[derive(Debug, Clone, PartialEq)]
21pub(crate) struct SchemaWrapper(Schema);
22
23impl Eq for SchemaWrapper {}
24
25impl Ord for SchemaWrapper {
26 fn cmp(&self, _other: &Self) -> std::cmp::Ordering {
27 std::cmp::Ordering::Equal
28 }
29}
30impl PartialOrd for SchemaWrapper {
31 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
32 Some(self.cmp(other))
33 }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
37pub(crate) struct TypeEntryEnum {
38 pub name: String,
39 pub rename: Option<String>,
40 pub description: Option<String>,
41 pub default: Option<WrappedValue>,
42 pub tag_type: EnumTagType,
43 pub variants: Vec<Variant>,
44 pub deny_unknown_fields: bool,
45 pub bespoke_impls: BTreeSet<TypeEntryEnumImpl>,
46 pub schema: SchemaWrapper,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
51pub(crate) enum TypeEntryEnumImpl {
52 AllSimpleVariants,
53 UntaggedFromStr,
54 UntaggedDisplay,
55 UntaggedFromStringIrrefutable,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
62pub(crate) struct TypeEntryStruct {
63 pub name: String,
64 pub rename: Option<String>,
65 pub description: Option<String>,
66 pub default: Option<WrappedValue>,
67 pub properties: Vec<StructProperty>,
68 pub deny_unknown_fields: bool,
69 pub schema: SchemaWrapper,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
73pub(crate) struct TypeEntryNewtype {
74 pub name: String,
75 pub rename: Option<String>,
76 pub description: Option<String>,
77 pub default: Option<WrappedValue>,
78 pub type_id: TypeId,
79 pub constraints: TypeEntryNewtypeConstraints,
80 pub schema: SchemaWrapper,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
84pub(crate) enum TypeEntryNewtypeConstraints {
85 None,
86 EnumValue(Vec<WrappedValue>),
87 DenyValue(Vec<WrappedValue>),
88 String {
89 max_length: Option<u32>,
90 min_length: Option<u32>,
91 pattern: Option<String>,
92 },
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
96pub(crate) struct TypeEntryNative {
97 pub type_name: String,
98 impls: Vec<TypeSpaceImpl>,
99 pub parameters: Vec<TypeId>,
103}
104impl TypeEntryNative {
105 pub(crate) fn name_match(&self, type_name: &Name) -> bool {
106 let native_name = self.type_name.rsplit("::").next().unwrap();
107 !self.parameters.is_empty()
108 || matches!(type_name, Name::Required(req) if req == native_name)
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub(crate) struct WrappedValue(pub serde_json::Value);
114impl WrappedValue {
115 pub(crate) fn new(value: serde_json::Value) -> Self {
116 Self(value)
117 }
118}
119
120impl Ord for WrappedValue {
121 fn cmp(&self, _: &Self) -> std::cmp::Ordering {
122 std::cmp::Ordering::Equal
123 }
124}
125impl PartialOrd for WrappedValue {
126 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
127 Some(self.cmp(other))
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq)]
138pub(crate) struct TypeEntry {
139 pub details: TypeEntryDetails,
140 pub extra_derives: BTreeSet<String>,
141 pub extra_attrs: BTreeSet<String>,
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
145pub(crate) enum TypeEntryDetails {
146 Enum(TypeEntryEnum),
147 Struct(TypeEntryStruct),
148 Newtype(TypeEntryNewtype),
149
150 Native(TypeEntryNative),
152
153 Option(TypeId),
155 Box(TypeId),
156 Vec(TypeId),
157 Map(TypeId, TypeId),
158 Set(TypeId),
159 Array(TypeId, usize),
160 Tuple(Vec<TypeId>),
161 Unit,
162 Boolean,
163 Integer(String),
165 Float(String),
167 String,
169 JsonValue,
171
172 Reference(TypeId),
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
179pub(crate) enum EnumTagType {
180 External,
181 Internal { tag: String },
182 Adjacent { tag: String, content: String },
183 Untagged,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
187pub(crate) struct Variant {
188 pub raw_name: String,
189 pub ident_name: Option<String>,
190 pub description: Option<String>,
191 pub details: VariantDetails,
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
195pub(crate) enum VariantDetails {
196 Simple,
197 Item(TypeId),
198 Tuple(Vec<TypeId>),
199 Struct(Vec<StructProperty>),
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
203pub(crate) struct StructProperty {
204 pub name: String,
205 pub rename: StructPropertyRename,
206 pub state: StructPropertyState,
207 pub description: Option<String>,
208 pub type_id: TypeId,
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
212pub(crate) enum StructPropertyRename {
213 None,
214 Rename(String),
215 Flatten,
216}
217
218#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
219pub(crate) enum StructPropertyState {
220 Required,
221 Optional,
222 Default(WrappedValue),
223}
224
225#[derive(Debug)]
226pub(crate) enum DefaultKind {
227 Intrinsic,
228 Specific,
229 Generic(DefaultImpl),
230}
231
232fn variants_unique(variants: &[Variant]) -> bool {
233 unique(
234 variants
235 .iter()
236 .map(|variant| variant.ident_name.as_ref().unwrap()),
237 )
238}
239
240impl TypeEntryEnum {
241 pub(crate) fn from_metadata(
242 type_space: &TypeSpace,
243 type_name: Name,
244 metadata: &Option<Box<Metadata>>,
245 tag_type: EnumTagType,
246 mut variants: Vec<Variant>,
247 deny_unknown_fields: bool,
248 schema: Schema,
249 ) -> TypeEntry {
250 variants.iter_mut().for_each(|variant| {
253 let ident_name = sanitize(&variant.raw_name, Case::Pascal);
254 variant.ident_name = Some(ident_name);
255 });
256
257 if !variants_unique(&variants) {
260 variants.iter_mut().for_each(|variant| {
261 let ident_name = sanitize(
262 &variant
263 .raw_name
264 .replace(|c| c == '_' || !is_xid_continue(c), "X"),
265 Case::Pascal,
266 );
267 variant.ident_name = Some(ident_name);
268 });
269 }
270
271 if !variants_unique(&variants) {
274 let mut counts = HashMap::new();
275 variants.iter().for_each(|variant| {
276 counts
277 .entry(variant.ident_name.as_ref().unwrap())
278 .and_modify(|xxx| *xxx += 1)
279 .or_insert(0);
280 });
281 let dups = variants
282 .iter()
283 .filter(|variant| *counts.get(variant.ident_name.as_ref().unwrap()).unwrap() > 0)
284 .map(|variant| variant.raw_name.as_str())
285 .collect::<Vec<_>>()
286 .join(",");
287 panic!("Failed to make unique variant names for [{}]", dups);
288 }
289
290 let name = get_type_name(&type_name, metadata).unwrap();
291 let rename = None;
292 let description = metadata_description(metadata);
293
294 let type_patch = TypePatch::new(type_space, name);
295
296 let details = TypeEntryDetails::Enum(Self {
297 name: type_patch.name,
298 rename,
299 description,
300 default: None,
301 tag_type,
302 variants,
303 deny_unknown_fields,
304 bespoke_impls: Default::default(),
305 schema: SchemaWrapper(schema),
306 });
307
308 TypeEntry {
309 details,
310 extra_derives: type_patch.derives,
311 extra_attrs: type_patch.attrs,
312 }
313 }
314
315 pub(crate) fn finalize(&mut self, type_space: &TypeSpace) {
316 self.bespoke_impls = [
317 (self.tag_type != EnumTagType::Untagged
319 && !self.variants.is_empty()
320 && self
321 .variants
322 .iter()
323 .all(|variant| matches!(variant.details, VariantDetails::Simple)))
324 .then_some(TypeEntryEnumImpl::AllSimpleVariants),
325 untagged_newtype_variants(
328 type_space,
329 &self.tag_type,
330 &self.variants,
331 TypeSpaceImpl::FromStr,
332 Some(TypeSpaceImpl::FromStringIrrefutable),
333 )
334 .then_some(TypeEntryEnumImpl::UntaggedFromStr),
335 untagged_newtype_variants(
337 type_space,
338 &self.tag_type,
339 &self.variants,
340 TypeSpaceImpl::Display,
341 None,
342 )
343 .then_some(TypeEntryEnumImpl::UntaggedDisplay),
344 untagged_newtype_string(type_space, &self.tag_type, &self.variants)
345 .then_some(TypeEntryEnumImpl::UntaggedFromStringIrrefutable),
346 ]
347 .into_iter()
348 .flatten()
349 .collect();
350 }
351}
352
353impl Variant {
354 pub(crate) fn new(
355 raw_name: String,
356 description: Option<String>,
357 details: VariantDetails,
358 ) -> Self {
359 Self {
360 raw_name,
361 ident_name: None,
362 description,
363 details,
364 }
365 }
366}
367
368impl TypeEntryStruct {
369 pub(crate) fn from_metadata(
370 type_space: &TypeSpace,
371 type_name: Name,
372 metadata: &Option<Box<Metadata>>,
373 properties: Vec<StructProperty>,
374 deny_unknown_fields: bool,
375 schema: Schema,
376 ) -> TypeEntry {
377 let name = get_type_name(&type_name, metadata).unwrap();
378 let rename = None;
379 let description = metadata_description(metadata);
380 let default = metadata
381 .as_ref()
382 .and_then(|m| m.default.as_ref())
383 .cloned()
384 .map(WrappedValue::new);
385
386 let type_patch = TypePatch::new(type_space, name);
387
388 let details = TypeEntryDetails::Struct(Self {
389 name: type_patch.name,
390 rename,
391 description,
392 default,
393 properties,
394 deny_unknown_fields,
395 schema: SchemaWrapper(schema),
396 });
397
398 TypeEntry {
399 details,
400 extra_derives: type_patch.derives,
401 extra_attrs: type_patch.attrs,
402 }
403 }
404}
405
406impl TypeEntryNewtype {
407 pub(crate) fn from_metadata(
408 type_space: &TypeSpace,
409 type_name: Name,
410 metadata: &Option<Box<Metadata>>,
411 type_id: TypeId,
412 schema: Schema,
413 ) -> TypeEntry {
414 let name = get_type_name(&type_name, metadata).unwrap();
415 let rename = None;
416 let description = metadata_description(metadata);
417
418 let type_patch = TypePatch::new(type_space, name);
419
420 let details = TypeEntryDetails::Newtype(Self {
421 name: type_patch.name,
422 rename,
423 description,
424 default: None,
425 type_id,
426 constraints: TypeEntryNewtypeConstraints::None,
427 schema: SchemaWrapper(schema),
428 });
429
430 TypeEntry {
431 details,
432 extra_derives: type_patch.derives,
433 extra_attrs: type_patch.attrs,
434 }
435 }
436
437 pub(crate) fn from_metadata_with_enum_values(
438 type_space: &TypeSpace,
439 type_name: Name,
440 metadata: &Option<Box<Metadata>>,
441 type_id: TypeId,
442 enum_values: &[serde_json::Value],
443 schema: Schema,
444 ) -> TypeEntry {
445 let name = get_type_name(&type_name, metadata).unwrap();
446 let rename = None;
447 let description = metadata_description(metadata);
448
449 let type_patch = TypePatch::new(type_space, name);
450
451 let details = TypeEntryDetails::Newtype(Self {
452 name: type_patch.name,
453 rename,
454 description,
455 default: None,
456 type_id,
457 constraints: TypeEntryNewtypeConstraints::EnumValue(
458 enum_values.iter().cloned().map(WrappedValue::new).collect(),
459 ),
460 schema: SchemaWrapper(schema),
461 });
462
463 TypeEntry {
464 details,
465 extra_derives: type_patch.derives,
466 extra_attrs: type_patch.attrs,
467 }
468 }
469
470 pub(crate) fn from_metadata_with_deny_values(
471 type_space: &TypeSpace,
472 type_name: Name,
473 metadata: &Option<Box<Metadata>>,
474 type_id: TypeId,
475 enum_values: &[serde_json::Value],
476 schema: Schema,
477 ) -> TypeEntry {
478 let name = get_type_name(&type_name, metadata).unwrap();
479 let rename = None;
480 let description = metadata_description(metadata);
481
482 let type_patch = TypePatch::new(type_space, name);
483
484 let details = TypeEntryDetails::Newtype(Self {
485 name: type_patch.name,
486 rename,
487 description,
488 default: None,
489 type_id,
490 constraints: TypeEntryNewtypeConstraints::DenyValue(
491 enum_values.iter().cloned().map(WrappedValue::new).collect(),
492 ),
493 schema: SchemaWrapper(schema),
494 });
495
496 TypeEntry {
497 details,
498 extra_derives: type_patch.derives,
499 extra_attrs: type_patch.attrs,
500 }
501 }
502
503 pub(crate) fn from_metadata_with_string_validation(
504 type_space: &TypeSpace,
505 type_name: Name,
506 metadata: &Option<Box<Metadata>>,
507 type_id: TypeId,
508 validation: &schemars::schema::StringValidation,
509 schema: Schema,
510 ) -> TypeEntry {
511 let name = get_type_name(&type_name, metadata).unwrap();
512 let rename = None;
513 let description = metadata_description(metadata);
514
515 let schemars::schema::StringValidation {
516 max_length,
517 min_length,
518 pattern,
519 } = validation.clone();
520
521 let type_patch = TypePatch::new(type_space, name);
522
523 let details = TypeEntryDetails::Newtype(Self {
524 name: type_patch.name,
525 rename,
526 description,
527 default: None,
528 type_id,
529 constraints: TypeEntryNewtypeConstraints::String {
530 max_length,
531 min_length,
532 pattern,
533 },
534 schema: SchemaWrapper(schema),
535 });
536
537 TypeEntry {
538 details,
539 extra_derives: type_patch.derives,
540 extra_attrs: type_patch.attrs,
541 }
542 }
543}
544
545impl From<TypeEntryDetails> for TypeEntry {
546 fn from(details: TypeEntryDetails) -> Self {
547 Self {
548 details,
549 extra_derives: Default::default(),
550 extra_attrs: Default::default(),
551 }
552 }
553}
554
555impl TypeEntry {
556 pub(crate) fn new_native<S: ToString>(type_name: S, impls: &[TypeSpaceImpl]) -> Self {
557 TypeEntry {
558 details: TypeEntryDetails::Native(TypeEntryNative {
559 type_name: type_name.to_string(),
560 impls: impls.to_vec(),
561 parameters: Default::default(),
562 }),
563 extra_derives: Default::default(),
564 extra_attrs: Default::default(),
565 }
566 }
567 pub(crate) fn new_native_params<S: ToString>(type_name: S, params: &[TypeId]) -> Self {
568 TypeEntry {
569 details: TypeEntryDetails::Native(TypeEntryNative {
570 type_name: type_name.to_string(),
571 impls: Default::default(),
572 parameters: params.to_vec(),
573 }),
574 extra_derives: Default::default(),
575 extra_attrs: Default::default(),
576 }
577 }
578 pub(crate) fn new_boolean() -> Self {
579 TypeEntry {
580 details: TypeEntryDetails::Boolean,
581 extra_derives: Default::default(),
582 extra_attrs: Default::default(),
583 }
584 }
585 pub(crate) fn new_integer<S: ToString>(type_name: S) -> Self {
586 TypeEntryDetails::Integer(type_name.to_string()).into()
587 }
588 pub(crate) fn new_float<S: ToString>(type_name: S) -> Self {
589 TypeEntry {
590 details: TypeEntryDetails::Float(type_name.to_string()),
591 extra_derives: Default::default(),
592 extra_attrs: Default::default(),
593 }
594 }
595
596 pub(crate) fn finalize(&mut self, type_space: &mut TypeSpace) -> Result<()> {
597 if let TypeEntryDetails::Enum(enum_details) = &mut self.details {
598 enum_details.finalize(type_space);
599 }
600
601 self.check_defaults(type_space)
602 }
603
604 pub(crate) fn name(&self) -> Option<&String> {
605 match &self.details {
606 TypeEntryDetails::Enum(TypeEntryEnum { name, .. })
607 | TypeEntryDetails::Struct(TypeEntryStruct { name, .. })
608 | TypeEntryDetails::Newtype(TypeEntryNewtype { name, .. }) => Some(name),
609
610 _ => None,
611 }
612 }
613
614 pub(crate) fn has_impl<'a>(
615 &'a self,
616 type_space: &'a TypeSpace,
617 impl_name: TypeSpaceImpl,
618 ) -> bool {
619 match &self.details {
620 TypeEntryDetails::Enum(details) => match impl_name {
621 TypeSpaceImpl::Default => details.default.is_some(),
622 TypeSpaceImpl::FromStr => {
623 details
624 .bespoke_impls
625 .contains(&TypeEntryEnumImpl::AllSimpleVariants)
626 || details
627 .bespoke_impls
628 .contains(&TypeEntryEnumImpl::UntaggedFromStr)
629 }
630 TypeSpaceImpl::Display => {
631 details
632 .bespoke_impls
633 .contains(&TypeEntryEnumImpl::AllSimpleVariants)
634 || details
635 .bespoke_impls
636 .contains(&TypeEntryEnumImpl::UntaggedDisplay)
637 }
638 TypeSpaceImpl::FromStringIrrefutable => details
639 .bespoke_impls
640 .contains(&TypeEntryEnumImpl::UntaggedFromStringIrrefutable),
641 },
642
643 TypeEntryDetails::Struct(details) => match impl_name {
644 TypeSpaceImpl::Default => details.default.is_some(),
645 _ => false,
646 },
647 TypeEntryDetails::Newtype(details) => match (&details.constraints, impl_name) {
648 (_, TypeSpaceImpl::Default) => details.default.is_some(),
649 (TypeEntryNewtypeConstraints::String { .. }, TypeSpaceImpl::FromStr) => true,
650 (TypeEntryNewtypeConstraints::String { .. }, TypeSpaceImpl::Display) => true,
651 (TypeEntryNewtypeConstraints::None, _) => {
652 let type_entry = type_space.id_to_entry.get(&details.type_id).unwrap();
668 type_entry.has_impl(type_space, impl_name)
669 }
670 _ => false,
671 },
672 TypeEntryDetails::Native(details) => details.impls.contains(&impl_name),
673 TypeEntryDetails::Box(type_id) => {
674 if impl_name == TypeSpaceImpl::Default {
675 let type_entry = type_space.id_to_entry.get(type_id).unwrap();
676 type_entry.has_impl(type_space, impl_name)
677 } else {
678 false
679 }
680 }
681
682 TypeEntryDetails::JsonValue => false,
683
684 TypeEntryDetails::Unit
685 | TypeEntryDetails::Option(_)
686 | TypeEntryDetails::Vec(_)
687 | TypeEntryDetails::Map(_, _)
688 | TypeEntryDetails::Set(_) => {
689 matches!(impl_name, TypeSpaceImpl::Default)
690 }
691
692 TypeEntryDetails::Tuple(type_ids) => {
693 matches!(impl_name, TypeSpaceImpl::Default)
695 && type_ids.len() <= 12
696 && type_ids.iter().all(|type_id| {
697 let type_entry = type_space.id_to_entry.get(type_id).unwrap();
698 type_entry.has_impl(type_space, TypeSpaceImpl::Default)
699 })
700 }
701
702 TypeEntryDetails::Array(item_id, length) => {
703 if *length <= 32 && impl_name == TypeSpaceImpl::Default {
705 let type_entry = type_space.id_to_entry.get(item_id).unwrap();
706 type_entry.has_impl(type_space, impl_name)
707 } else {
708 false
709 }
710 }
711
712 TypeEntryDetails::Boolean => match impl_name {
713 TypeSpaceImpl::Default | TypeSpaceImpl::FromStr | TypeSpaceImpl::Display => true,
714 TypeSpaceImpl::FromStringIrrefutable => false,
715 },
716 TypeEntryDetails::Integer(_) => match impl_name {
717 TypeSpaceImpl::Default | TypeSpaceImpl::FromStr | TypeSpaceImpl::Display => true,
718 TypeSpaceImpl::FromStringIrrefutable => false,
719 },
720
721 TypeEntryDetails::Float(_) => match impl_name {
722 TypeSpaceImpl::Default | TypeSpaceImpl::FromStr | TypeSpaceImpl::Display => true,
723 TypeSpaceImpl::FromStringIrrefutable => false,
724 },
725 TypeEntryDetails::String => match impl_name {
726 TypeSpaceImpl::Default
727 | TypeSpaceImpl::FromStr
728 | TypeSpaceImpl::Display
729 | TypeSpaceImpl::FromStringIrrefutable => true,
730 },
731
732 TypeEntryDetails::Reference(_) => unreachable!(),
733 }
734 }
735
736 pub(crate) fn output(&self, type_space: &TypeSpace, output: &mut OutputSpace) {
737 let derive_set = [
738 "::serde::Serialize",
739 "::serde::Deserialize",
740 "Debug",
741 "Clone",
742 ]
743 .into_iter()
744 .collect::<BTreeSet<_>>();
745
746 match &self.details {
747 TypeEntryDetails::Enum(enum_details) => {
748 self.output_enum(type_space, output, enum_details, derive_set)
749 }
750 TypeEntryDetails::Struct(struct_details) => {
751 self.output_struct(type_space, output, struct_details, derive_set)
752 }
753 TypeEntryDetails::Newtype(newtype_details) => {
754 self.output_newtype(type_space, output, newtype_details, derive_set)
755 }
756
757 TypeEntryDetails::Reference(_) => unreachable!(),
760
761 _ => (),
763 }
764 }
765
766 fn output_enum(
767 &self,
768 type_space: &TypeSpace,
769 output: &mut OutputSpace,
770 enum_details: &TypeEntryEnum,
771 mut derive_set: BTreeSet<&str>,
772 ) {
773 let TypeEntryEnum {
774 name,
775 rename,
776 description,
777 default,
778 tag_type,
779 variants,
780 deny_unknown_fields,
781 bespoke_impls,
782 schema: SchemaWrapper(schema),
783 } = enum_details;
784
785 let doc = make_doc(name, description.as_ref(), schema);
786
787 if variants
790 .iter()
791 .all(|variant| matches!(variant.details, VariantDetails::Simple))
792 {
793 derive_set.extend(["Copy", "PartialOrd", "Ord", "PartialEq", "Eq", "Hash"]);
794 }
795
796 let mut serde_options = Vec::new();
797 if let Some(old_name) = rename {
798 serde_options.push(quote! { rename = #old_name });
799 }
800 match tag_type {
801 EnumTagType::External => {}
802 EnumTagType::Internal { tag } => {
803 serde_options.push(quote! { tag = #tag });
804 }
805 EnumTagType::Adjacent { tag, content } => {
806 serde_options.push(quote! { tag = #tag });
807 serde_options.push(quote! { content = #content });
808 }
809 EnumTagType::Untagged => {
810 serde_options.push(quote! { untagged });
811 }
812 }
813 if *deny_unknown_fields {
814 serde_options.push(quote! { deny_unknown_fields });
815 }
816
817 let serde = (!serde_options.is_empty()).then(|| {
818 quote! { #[serde( #( #serde_options ),* )] }
819 });
820
821 let type_name = format_ident!("{}", name);
822
823 let variants_decl = variants
824 .iter()
825 .map(|variant| output_variant(variant, type_space, output, name))
826 .collect::<Vec<_>>();
827
828 if tag_type == &EnumTagType::Untagged {
831 assert!(
832 variants
833 .iter()
834 .filter(|variant| matches!(variant.details, VariantDetails::Simple))
835 .count()
836 <= 1
837 )
838 }
839
840 let simple_enum_impl = bespoke_impls
843 .contains(&TypeEntryEnumImpl::AllSimpleVariants)
844 .then(|| {
845 let (match_variants, match_strs): (Vec<_>, Vec<_>) = variants
846 .iter()
847 .map(|variant| {
848 let ident_name = variant.ident_name.as_ref().unwrap();
849 let variant_name = format_ident!("{}", ident_name);
850 (variant_name, &variant.raw_name)
851 })
852 .unzip();
853
854 quote! {
855 impl ::std::fmt::Display for #type_name {
856 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
857 match *self {
858 #(Self::#match_variants => f.write_str(#match_strs),)*
859 }
860 }
861 }
862 impl ::std::str::FromStr for #type_name {
863 type Err = self::error::ConversionError;
864
865 fn from_str(value: &str) ->
866 ::std::result::Result<Self, self::error::ConversionError>
867 {
868 match value {
869 #(#match_strs => Ok(Self::#match_variants),)*
870 _ => Err("invalid value".into()),
871 }
872 }
873 }
874 impl ::std::convert::TryFrom<&str> for #type_name {
875 type Error = self::error::ConversionError;
876
877 fn try_from(value: &str) ->
878 ::std::result::Result<Self, self::error::ConversionError>
879 {
880 value.parse()
881 }
882 }
883 impl ::std::convert::TryFrom<&::std::string::String> for #type_name {
884 type Error = self::error::ConversionError;
885
886 fn try_from(value: &::std::string::String) ->
887 ::std::result::Result<Self, self::error::ConversionError>
888 {
889 value.parse()
890 }
891 }
892 impl ::std::convert::TryFrom<::std::string::String> for #type_name {
893 type Error = self::error::ConversionError;
894
895 fn try_from(value: ::std::string::String) ->
896 ::std::result::Result<Self, self::error::ConversionError>
897 {
898 value.parse()
899 }
900 }
901 }
902 });
903
904 let default_impl = default.as_ref().map(|value| {
905 let default_stream = self.output_value(type_space, &value.0, "e! {}).unwrap();
906 quote! {
907 impl ::std::default::Default for #type_name {
908 fn default() -> Self {
909 #default_stream
910 }
911 }
912 }
913 });
914
915 let untagged_newtype_from_string_impl = bespoke_impls
916 .contains(&TypeEntryEnumImpl::UntaggedFromStr)
917 .then(|| {
918 let variant_name = variants
919 .iter()
920 .map(|variant| format_ident!("{}", variant.ident_name.as_ref().unwrap()));
921
922 quote! {
923 impl ::std::str::FromStr for #type_name {
924 type Err = self::error::ConversionError;
925
926 fn from_str(value: &str) ->
927 ::std::result::Result<Self, self::error::ConversionError>
928 {
929 #(
930 if let Ok(v) = value.parse() {
932 Ok(Self::#variant_name(v))
933 } else
934 )*
935 {
936 Err("string conversion failed for all variants".into())
937 }
938 }
939 }
940 impl ::std::convert::TryFrom<&str> for #type_name {
941 type Error = self::error::ConversionError;
942
943 fn try_from(value: &str) ->
944 ::std::result::Result<Self, self::error::ConversionError>
945 {
946 value.parse()
947 }
948 }
949 impl ::std::convert::TryFrom<&::std::string::String> for #type_name {
950 type Error = self::error::ConversionError;
951
952 fn try_from(value: &::std::string::String) ->
953 ::std::result::Result<Self, self::error::ConversionError>
954 {
955 value.parse()
956 }
957 }
958 impl ::std::convert::TryFrom<::std::string::String> for #type_name {
959 type Error = self::error::ConversionError;
960
961 fn try_from(value: ::std::string::String) ->
962 ::std::result::Result<Self, self::error::ConversionError>
963 {
964 value.parse()
965 }
966 }
967 }
968 });
969
970 let untagged_newtype_to_string_impl = bespoke_impls
971 .contains(&TypeEntryEnumImpl::UntaggedDisplay)
972 .then(|| {
973 let variant_name = variants
974 .iter()
975 .map(|variant| format_ident!("{}", variant.ident_name.as_ref().unwrap()));
976
977 quote! {
978 impl ::std::fmt::Display for #type_name {
979 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
980 match self {
981 #(Self::#variant_name(x) => x.fmt(f),)*
982 }
983 }
984 }
985 }
986 });
987
988 let convenience_from = {
989 let unique_variants =
996 variants
997 .iter()
998 .enumerate()
999 .fold(BTreeMap::new(), |mut map, (index, variant)| {
1000 let key = match &variant.details {
1001 VariantDetails::Item(type_id) => vec![type_id],
1002 VariantDetails::Tuple(type_ids) => type_ids.iter().collect(),
1003 _ => return map,
1004 };
1005
1006 map.entry(key)
1007 .and_modify(|v| *v = None)
1008 .or_insert(Some((index, variant)));
1009 map
1010 });
1011
1012 let ordered_variants = unique_variants
1018 .into_values()
1019 .flatten()
1020 .collect::<BTreeMap<_, _>>();
1021
1022 let variant_from = ordered_variants.into_values().map(|variant| {
1025 match &variant.details {
1026 VariantDetails::Item(type_id) => {
1027 let variant_type = type_space.id_to_entry.get(type_id).unwrap();
1028
1029 (variant_type.details != TypeEntryDetails::String).then(|| {
1032 let variant_type_ident = variant_type.type_ident(type_space, &None);
1033 let variant_name =
1034 format_ident!("{}", variant.ident_name.as_ref().unwrap());
1035 quote! {
1036 impl ::std::convert::From<#variant_type_ident> for #type_name {
1037 fn from(value: #variant_type_ident)
1038 -> Self
1039 {
1040 Self::#variant_name(value)
1041 }
1042 }
1043 }
1044 })
1045 }
1046 VariantDetails::Tuple(type_ids) => {
1047 let variant_type_idents = type_ids.iter().map(|type_id| {
1048 type_space
1049 .id_to_entry
1050 .get(type_id)
1051 .unwrap()
1052 .type_ident(type_space, &None)
1053 });
1054 let variant_type_ident = if type_ids.len() != 1 {
1055 quote! { ( #(#variant_type_idents),* ) }
1056 } else {
1057 quote! { ( #(#variant_type_idents,)* ) }
1060 };
1061 let variant_name =
1062 format_ident!("{}", variant.ident_name.as_ref().unwrap());
1063 let ii = (0..type_ids.len()).map(syn::Index::from);
1064 Some(quote! {
1065 impl ::std::convert::From<#variant_type_ident> for #type_name {
1066 fn from(value: #variant_type_ident) -> Self {
1067 Self::#variant_name(
1068 #( value.#ii, )*
1069 )
1070 }
1071 }
1072 })
1073 }
1074 _ => None,
1075 }
1076 });
1077
1078 quote! {
1079 #( #variant_from )*
1080 }
1081 };
1082
1083 let derives = strings_to_derives(
1084 derive_set,
1085 &self.extra_derives,
1086 &type_space.settings.extra_derives,
1087 );
1088
1089 let attrs = strings_to_attrs(&self.extra_attrs, &type_space.settings.extra_attrs);
1090
1091 let item = quote! {
1092 #doc
1093 #(#attrs)*
1094 #[derive(#(#derives),*)]
1095 #serde
1096 pub enum #type_name {
1097 #(#variants_decl)*
1098 }
1099
1100 #simple_enum_impl
1101 #default_impl
1102 #untagged_newtype_from_string_impl
1103 #untagged_newtype_to_string_impl
1104 #convenience_from
1105 };
1106 output.add_item(OutputSpaceMod::Crate, name, item);
1107 }
1108
1109 fn output_struct(
1110 &self,
1111 type_space: &TypeSpace,
1112 output: &mut OutputSpace,
1113 struct_details: &TypeEntryStruct,
1114 derive_set: BTreeSet<&str>,
1115 ) {
1116 enum PropDefault {
1117 None(String),
1118 Default(TokenStream),
1119 Custom(TokenStream),
1120 }
1121
1122 let TypeEntryStruct {
1123 name,
1124 rename,
1125 description,
1126 default,
1127 properties,
1128 deny_unknown_fields,
1129 schema: SchemaWrapper(schema),
1130 } = struct_details;
1131 let doc = make_doc(name, description.as_ref(), schema);
1132
1133 let mut serde_options = Vec::new();
1135 if let Some(old_name) = rename {
1136 serde_options.push(quote! { rename = #old_name });
1137 }
1138 if *deny_unknown_fields {
1139 serde_options.push(quote! { deny_unknown_fields });
1140 }
1141 let serde =
1142 (!serde_options.is_empty()).then(|| quote! { #[serde( #( #serde_options ),* )] });
1143
1144 let type_name = format_ident!("{}", name);
1145
1146 let mut prop_doc = Vec::new();
1148 let mut prop_serde = Vec::new();
1149 let mut prop_default = Vec::new();
1150 let mut prop_name = Vec::new();
1151 let mut prop_error = Vec::new();
1152 let mut prop_type = Vec::new();
1153 let mut prop_type_scoped = Vec::new();
1154
1155 properties.iter().for_each(|prop| {
1156 prop_doc.push(prop.description.as_ref().map(|d| quote! { #[doc = #d] }));
1157 prop_name.push(format_ident!("{}", prop.name));
1158 prop_error.push(format!(
1159 "error converting supplied value for {}: {{e}}",
1160 prop.name,
1161 ));
1162
1163 let prop_type_entry = type_space.id_to_entry.get(&prop.type_id).unwrap();
1164 prop_type.push(prop_type_entry.type_ident(type_space, &None));
1165 prop_type_scoped
1166 .push(prop_type_entry.type_ident(type_space, &Some("super".to_string())));
1167
1168 let (serde, default_fn) = generate_serde_attr(
1169 name,
1170 &prop.name,
1171 &prop.rename,
1172 &prop.state,
1173 prop_type_entry,
1174 type_space,
1175 output,
1176 );
1177
1178 prop_serde.push(serde);
1179 prop_default.push(match default_fn {
1180 DefaultFunction::Default => PropDefault::Default(quote! {
1181 Default::default()
1182 }),
1183 DefaultFunction::Custom(fn_name) => {
1184 let default_fn = syn::parse_str::<Path>(&fn_name).unwrap();
1185 PropDefault::Custom(quote! {
1186 #default_fn()
1187 })
1188 }
1189 DefaultFunction::None => {
1190 let err_msg = format!("no value supplied for {}", prop.name);
1191 PropDefault::None(err_msg)
1192 }
1193 });
1194 });
1195
1196 let derives = strings_to_derives(
1197 derive_set,
1198 &self.extra_derives,
1199 &type_space.settings.extra_derives,
1200 );
1201
1202 let attrs = strings_to_attrs(&self.extra_attrs, &type_space.settings.extra_attrs);
1203
1204 output.add_item(
1205 OutputSpaceMod::Crate,
1206 name,
1207 quote! {
1208 #doc
1209 #(#attrs)*
1210 #[derive(#(#derives),*)]
1211 #serde
1212 pub struct #type_name {
1213 #(
1214 #prop_doc
1215 #prop_serde
1216 pub #prop_name: #prop_type,
1217 )*
1218 }
1219 },
1220 );
1221
1222 if let Some(value) = default {
1224 let default_stream = self.output_value(type_space, &value.0, "e! {}).unwrap();
1225 output.add_item(
1226 OutputSpaceMod::Crate,
1227 name,
1228 quote! {
1229 impl ::std::default::Default for #type_name {
1230 fn default() -> Self {
1231 #default_stream
1232 }
1233 }
1234 },
1235 );
1236 } else if let Some(prop_default) = prop_default
1237 .iter()
1238 .map(|pd| match pd {
1239 PropDefault::None(_) => None,
1240 PropDefault::Default(token_stream) | PropDefault::Custom(token_stream) => {
1241 Some(token_stream)
1242 }
1243 })
1244 .collect::<Option<Vec<_>>>()
1245 {
1246 output.add_item(
1248 OutputSpaceMod::Crate,
1249 name,
1250 quote! {
1251 impl ::std::default::Default for #type_name {
1252 fn default() -> Self {
1253 Self {
1254 #(
1255 #prop_name: #prop_default,
1256 )*
1257 }
1258 }
1259 }
1260 },
1261 )
1262 }
1263
1264 if type_space.settings.struct_builder {
1265 output.add_item(
1266 OutputSpaceMod::Crate,
1267 name,
1268 quote! {
1269 impl #type_name {
1270 pub fn builder() -> builder::#type_name {
1271 Default::default()
1272 }
1273 }
1274 },
1275 );
1276
1277 let value_ident = if prop_name.is_empty() {
1280 quote! { _value }
1281 } else {
1282 quote! { value }
1283 };
1284
1285 let prop_default = prop_default.iter().map(|pd| match pd {
1286 PropDefault::None(err_msg) => quote! { Err(#err_msg.to_string()) },
1287 PropDefault::Default(default_fn) => quote! { Ok(#default_fn) },
1288 PropDefault::Custom(custom_fn) => quote! { Ok(super::#custom_fn) },
1289 });
1290
1291 output.add_item(
1292 OutputSpaceMod::Builder,
1293 name,
1294 quote! {
1295 #[derive(Clone, Debug)]
1296 pub struct #type_name {
1297 #(
1298 #prop_name: ::std::result::Result<#prop_type_scoped, ::std::string::String>,
1299 )*
1300 }
1301
1302 impl ::std::default::Default for #type_name {
1303 fn default() -> Self {
1304 Self {
1305 #(
1306 #prop_name: #prop_default,
1307 )*
1308 }
1309 }
1310 }
1311
1312 impl #type_name {
1313 #(
1314 pub fn #prop_name<T>(mut self, value: T) -> Self
1315 where
1316 T: ::std::convert::TryInto<#prop_type_scoped>,
1317 T::Error: ::std::fmt::Display,
1318 {
1319 self.#prop_name = value.try_into()
1320 .map_err(|e| format!(#prop_error));
1321 self
1322 }
1323 )*
1324 }
1325
1326 impl ::std::convert::TryFrom<#type_name>
1328 for super::#type_name
1329 {
1330 type Error = super::error::ConversionError;
1331
1332 fn try_from(#value_ident: #type_name)
1333 -> ::std::result::Result<Self, super::error::ConversionError>
1334 {
1335 Ok(Self {
1336 #(
1337 #prop_name: value.#prop_name?,
1338 )*
1339 })
1340 }
1341 }
1342
1343 impl ::std::convert::From<super::#type_name> for #type_name {
1345 fn from(#value_ident: super::#type_name) -> Self {
1346 Self {
1347 #(
1348 #prop_name: Ok(value.#prop_name),
1349 )*
1350 }
1351 }
1352 }
1353 },
1354 );
1355 }
1356 }
1357
1358 fn output_newtype<'a>(
1359 &self,
1360 type_space: &'a TypeSpace,
1361 output: &mut OutputSpace,
1362 newtype_details: &TypeEntryNewtype,
1363 mut derive_set: BTreeSet<&'a str>,
1364 ) {
1365 let TypeEntryNewtype {
1366 name,
1367 rename: _,
1368 description,
1369 default,
1370 type_id,
1371 constraints,
1372 schema: SchemaWrapper(schema),
1373 } = newtype_details;
1374 let doc = make_doc(name, description.as_ref(), schema);
1375
1376 let type_name = format_ident!("{}", name);
1377 let inner_type = type_space.id_to_entry.get(type_id).unwrap();
1378 let inner_type_name = inner_type.type_ident(type_space, &None);
1379
1380 let is_str = matches!(inner_type.details, TypeEntryDetails::String);
1381
1382 if is_str {
1385 derive_set.extend(["PartialOrd", "Ord", "PartialEq", "Eq", "Hash"]);
1386 }
1387
1388 derive_set.extend(type_space.settings.extra_derives.iter().map(|s| s.as_str()));
1389
1390 let constraint_impl = match constraints {
1391 TypeEntryNewtypeConstraints::None => {
1393 let str_impl = is_str.then(|| {
1394 quote! {
1395 impl ::std::str::FromStr for #type_name {
1396 type Err = ::std::convert::Infallible;
1397
1398 fn from_str(value: &str) ->
1399 ::std::result::Result<Self, Self::Err>
1400 {
1401 Ok(Self(value.to_string()))
1402 }
1403 }
1404 }
1405 });
1406
1407 let from_str_impl = (inner_type.has_impl(type_space, TypeSpaceImpl::FromStr)
1409 && !is_str)
1410 .then(|| {
1411 quote! {
1412 impl ::std::str::FromStr for #type_name {
1413 type Err = <#inner_type_name as
1414 ::std::str::FromStr>::Err;
1415
1416 fn from_str(value: &str) ->
1417 ::std::result::Result<Self, Self::Err>
1418 {
1419 Ok(Self(value.parse()?))
1420 }
1421 }
1422 impl ::std::convert::TryFrom<&str> for #type_name {
1423 type Error = <#inner_type_name as
1424 ::std::str::FromStr>::Err;
1425
1426 fn try_from(value: &str) ->
1427 ::std::result::Result<Self, Self::Error>
1428 {
1429 value.parse()
1430 }
1431 }
1432 impl ::std::convert::TryFrom<String> for #type_name {
1433 type Error = <#inner_type_name as
1434 ::std::str::FromStr>::Err;
1435
1436 fn try_from(value: String) ->
1437 ::std::result::Result<Self, Self::Error>
1438 {
1439 value.parse()
1440 }
1441 }
1442 }
1443 });
1444
1445 let display_impl = inner_type
1446 .has_impl(type_space, TypeSpaceImpl::Display)
1447 .then(|| {
1448 quote! {
1449 impl ::std::fmt::Display for #type_name {
1450 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
1451 self.0.fmt(f)
1452 }
1453 }
1454 }
1455 });
1456
1457 quote! {
1458 impl ::std::convert::From<#inner_type_name> for #type_name {
1459 fn from(value: #inner_type_name) -> Self {
1460 Self(value)
1461 }
1462 }
1463
1464 #str_impl
1465 #from_str_impl
1466 #display_impl
1467 }
1468 }
1469
1470 TypeEntryNewtypeConstraints::DenyValue(enum_values)
1471 | TypeEntryNewtypeConstraints::EnumValue(enum_values) => {
1472 assert!(
1476 matches!(constraints, TypeEntryNewtypeConstraints::DenyValue(_))
1477 || !matches!(&inner_type.details, TypeEntryDetails::String)
1478 );
1479
1480 derive_set.remove("::serde::Deserialize");
1483
1484 let value_output = enum_values
1485 .iter()
1486 .map(|value| inner_type.output_value(type_space, &value.0, "e! {}));
1487
1488 let value_string = enum_values
1489 .iter()
1490 .map(|value| serde_json::to_string(&value.0).unwrap());
1491
1492 let has_json_schema = derive_set.remove("schemars::JsonSchema")
1497 || derive_set.remove("::schemars::JsonSchema");
1498 let json_schema = has_json_schema.then(|| match constraints {
1499 TypeEntryNewtypeConstraints::DenyValue(_) => quote! {
1500 impl ::schemars::JsonSchema for #type_name {
1501 fn schema_name() -> ::std::string::String {
1502 #name.to_string()
1503 }
1504
1505 fn json_schema(gen: &mut ::schemars::gen::SchemaGenerator)
1506 -> ::schemars::schema::Schema {
1507 let mut schema =
1508 <#inner_type_name as ::schemars::JsonSchema>
1509 ::json_schema(gen)
1510 .into_object();
1511 let not = ::schemars::schema::SchemaObject {
1512 enum_values: ::std::option::Option::Some([
1513 #( ::serde_json::from_str(#value_string).unwrap(), )*
1514 ].into_iter().collect()),
1515 ..::std::default::Default::default()
1516 };
1517 schema.subschemas().not = Some(
1518 ::std::boxed::Box::new(not.into())
1519 );
1520 schema.into()
1521 }
1522 }
1523 },
1524 TypeEntryNewtypeConstraints::EnumValue(_) => quote! {
1525 impl ::schemars::JsonSchema for #type_name {
1526 fn schema_name() -> ::std::string::String {
1527 #name.to_string()
1528 }
1529
1530 fn json_schema(gen: &mut ::schemars::gen::SchemaGenerator)
1531 -> ::schemars::schema::Schema {
1532 let mut schema =
1533 <#inner_type_name as ::schemars::JsonSchema>
1534 ::json_schema(gen)
1535 .into_object();
1536 schema.enum_values = ::std::option::Option::Some([
1537 #( ::serde_json::from_str(#value_string).unwrap(), )*
1538 ].into_iter().collect());
1539 schema.into()
1540 }
1541 }
1542 },
1543
1544 _ => unreachable!(),
1545 });
1546
1547 let not = matches!(constraints, TypeEntryNewtypeConstraints::EnumValue(_))
1551 .then(|| quote! { ! });
1552
1553 quote! {
1554 impl ::std::convert::TryFrom<#inner_type_name> for #type_name {
1556 type Error = self::error::ConversionError;
1557
1558 fn try_from(
1559 value: #inner_type_name
1560 ) -> ::std::result::Result<Self, self::error::ConversionError>
1561 {
1562 if #not [
1563 #(#value_output,)*
1564 ].contains(&value) {
1565 Err("invalid value".into())
1566 } else {
1567 Ok(Self(value))
1568 }
1569 }
1570 }
1571
1572 impl<'de> ::serde::Deserialize<'de> for #type_name {
1573 fn deserialize<D>(
1574 deserializer: D,
1575 ) -> ::std::result::Result<Self, D::Error>
1576 where
1577 D: ::serde::Deserializer<'de>,
1578 {
1579 Self::try_from(
1580 <#inner_type_name>::deserialize(deserializer)?,
1581 )
1582 .map_err(|e| {
1583 <D::Error as ::serde::de::Error>::custom(
1584 e.to_string(),
1585 )
1586 })
1587 }
1588 }
1589
1590 #json_schema
1591 }
1592 }
1593
1594 TypeEntryNewtypeConstraints::String {
1595 max_length,
1596 min_length,
1597 pattern,
1598 } => {
1599 let max = max_length.map(|v| {
1600 let v = v as usize;
1601 let err = format!("longer than {} characters", v);
1602 quote! {
1603 if value.chars().count() > #v {
1604 return Err(#err.into());
1605 }
1606 }
1607 });
1608 let min = min_length.map(|v| {
1609 let v = v as usize;
1610 let err = format!("shorter than {} characters", v);
1611 quote! {
1612 if value.chars().count() < #v {
1613 return Err(#err.into());
1614 }
1615 }
1616 });
1617
1618 let pat = pattern.as_ref().map(|p| {
1619 let err = format!("doesn't match pattern \"{}\"", p);
1620 quote! {
1621 static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(|| {
1622 ::regress::Regex::new(#p).unwrap()
1623 });
1624 if PATTERN.find(value).is_none() {
1625 return Err(#err.into());
1626 }
1627 }
1628 });
1629
1630 derive_set.remove("::serde::Deserialize");
1633
1634 quote! {
1637 impl ::std::str::FromStr for #type_name {
1638 type Err = self::error::ConversionError;
1639
1640 fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
1641 #max
1642 #min
1643 #pat
1644
1645 Ok(Self(value.to_string()))
1646 }
1647 }
1648 impl ::std::convert::TryFrom<&str> for #type_name {
1649 type Error = self::error::ConversionError;
1650
1651 fn try_from(value: &str) ->
1652 ::std::result::Result<Self, self::error::ConversionError>
1653 {
1654 value.parse()
1655 }
1656 }
1657 impl ::std::convert::TryFrom<&::std::string::String> for #type_name {
1658 type Error = self::error::ConversionError;
1659
1660 fn try_from(value: &::std::string::String) ->
1661 ::std::result::Result<Self, self::error::ConversionError>
1662 {
1663 value.parse()
1664 }
1665 }
1666 impl ::std::convert::TryFrom<::std::string::String> for #type_name {
1667 type Error = self::error::ConversionError;
1668
1669 fn try_from(value: ::std::string::String) ->
1670 ::std::result::Result<Self, self::error::ConversionError>
1671 {
1672 value.parse()
1673 }
1674 }
1675
1676 impl<'de> ::serde::Deserialize<'de> for #type_name {
1677 fn deserialize<D>(
1678 deserializer: D,
1679 ) -> ::std::result::Result<Self, D::Error>
1680 where
1681 D: ::serde::Deserializer<'de>,
1682 {
1683 ::std::string::String::deserialize(deserializer)?
1684 .parse()
1685 .map_err(|e: self::error::ConversionError| {
1686 <D::Error as ::serde::de::Error>::custom(
1687 e.to_string(),
1688 )
1689 })
1690 }
1691 }
1692 }
1693 }
1694 };
1695
1696 let vis = match constraints {
1698 TypeEntryNewtypeConstraints::None => Some(quote! {pub}),
1699 _ => None,
1700 };
1701
1702 let default_impl = default.as_ref().map(|value| {
1703 let default_stream = self.output_value(type_space, &value.0, "e! {}).unwrap();
1704 quote! {
1705 impl ::std::default::Default for #type_name {
1706 fn default() -> Self {
1707 #default_stream
1708 }
1709 }
1710 }
1711 });
1712
1713 let derives = strings_to_derives(derive_set, &self.extra_derives, &[]);
1717
1718 let attrs = strings_to_attrs(&self.extra_attrs, &type_space.settings.extra_attrs);
1719
1720 let item = quote! {
1721 #doc
1722 #(#attrs)*
1723 #[derive(#(#derives),*)]
1724 #[serde(transparent)]
1725 pub struct #type_name(#vis #inner_type_name);
1726
1727 impl ::std::ops::Deref for #type_name {
1728 type Target = #inner_type_name;
1729 fn deref(&self) -> &#inner_type_name {
1730 &self.0
1731 }
1732 }
1733
1734 impl ::std::convert::From<#type_name> for #inner_type_name {
1735 fn from(value: #type_name) -> Self {
1736 value.0
1737 }
1738 }
1739
1740 #default_impl
1741 #constraint_impl
1742 };
1743 output.add_item(OutputSpaceMod::Crate, name, item);
1744 }
1745
1746 pub(crate) fn type_name(&self, type_space: &TypeSpace) -> String {
1747 self.type_ident(type_space, &None).to_string()
1748 }
1749
1750 pub(crate) fn type_ident(
1751 &self,
1752 type_space: &TypeSpace,
1753 type_mod: &Option<String>,
1754 ) -> TokenStream {
1755 match &self.details {
1756 TypeEntryDetails::Enum(TypeEntryEnum { name, .. })
1758 | TypeEntryDetails::Struct(TypeEntryStruct { name, .. })
1759 | TypeEntryDetails::Newtype(TypeEntryNewtype { name, .. }) => match &type_mod {
1760 Some(type_mod) => {
1761 let type_mod = format_ident!("{}", type_mod);
1762 let type_name = format_ident!("{}", name);
1763 quote! { #type_mod :: #type_name }
1764 }
1765 None => {
1766 let type_name = format_ident!("{}", name);
1767 quote! { #type_name }
1768 }
1769 },
1770
1771 TypeEntryDetails::Option(id) => {
1772 let inner_ty = type_space
1773 .id_to_entry
1774 .get(id)
1775 .expect("unresolved type id for option");
1776 let inner_ident = inner_ty.type_ident(type_space, type_mod);
1777
1778 match &inner_ty.details {
1781 TypeEntryDetails::Option(_) => inner_ident,
1782 _ => quote! { ::std::option::Option<#inner_ident> },
1783 }
1784 }
1785
1786 TypeEntryDetails::Box(id) => {
1787 let inner_ty = type_space
1788 .id_to_entry
1789 .get(id)
1790 .expect("unresolved type id for box");
1791
1792 let item = inner_ty.type_ident(type_space, type_mod);
1793
1794 quote! { ::std::boxed::Box<#item> }
1795 }
1796
1797 TypeEntryDetails::Vec(id) => {
1798 let inner_ty = type_space
1799 .id_to_entry
1800 .get(id)
1801 .expect("unresolved type id for array");
1802 let item = inner_ty.type_ident(type_space, type_mod);
1803
1804 quote! { ::std::vec::Vec<#item> }
1805 }
1806
1807 TypeEntryDetails::Map(key_id, value_id) => {
1808 let map_to_use = &type_space.settings.map_type;
1809 let key_ty = type_space
1810 .id_to_entry
1811 .get(key_id)
1812 .expect("unresolved type id for map key");
1813 let value_ty = type_space
1814 .id_to_entry
1815 .get(value_id)
1816 .expect("unresolved type id for map value");
1817
1818 if key_ty.details == TypeEntryDetails::String
1819 && value_ty.details == TypeEntryDetails::JsonValue
1820 {
1821 quote! { ::serde_json::Map<::std::string::String, ::serde_json::Value> }
1822 } else {
1823 let key_ident = key_ty.type_ident(type_space, type_mod);
1824 let value_ident = value_ty.type_ident(type_space, type_mod);
1825 let map_to_use = &map_to_use.0;
1826
1827 quote! { #map_to_use<#key_ident, #value_ident> }
1828 }
1829 }
1830
1831 TypeEntryDetails::Set(id) => {
1832 let inner_ty = type_space
1833 .id_to_entry
1834 .get(id)
1835 .expect("unresolved type id for set");
1836 let item = inner_ty.type_ident(type_space, type_mod);
1837 quote! { Vec<#item> }
1840 }
1841
1842 TypeEntryDetails::Tuple(items) => {
1843 let type_idents = items.iter().map(|item| {
1844 type_space
1845 .id_to_entry
1846 .get(item)
1847 .expect("unresolved type id for tuple")
1848 .type_ident(type_space, type_mod)
1849 });
1850
1851 if items.len() != 1 {
1852 quote! { ( #(#type_idents),* ) }
1853 } else {
1854 quote! { ( #(#type_idents,)* ) }
1856 }
1857 }
1858
1859 TypeEntryDetails::Array(item_id, length) => {
1860 let item_ty = type_space
1861 .id_to_entry
1862 .get(item_id)
1863 .expect("unresolved type id for array");
1864 let item_ident = item_ty.type_ident(type_space, type_mod);
1865
1866 quote! { [#item_ident; #length]}
1867 }
1868
1869 TypeEntryDetails::Native(TypeEntryNative {
1870 type_name,
1871 impls: _,
1872 parameters,
1873 }) => {
1874 let path =
1875 syn::parse_str::<syn::TypePath>(type_name).expect("type path wasn't valid");
1876
1877 let type_idents = (!parameters.is_empty()).then(|| {
1878 let type_idents = parameters.iter().map(|type_id| {
1879 type_space
1880 .id_to_entry
1881 .get(type_id)
1882 .expect("unresolved type id for tuple")
1883 .type_ident(type_space, type_mod)
1884 });
1885 quote! { < #(#type_idents,)* > }
1886 });
1887
1888 quote! {
1889 #path
1890 #type_idents
1891 }
1892 }
1893
1894 TypeEntryDetails::Unit => quote! { () },
1895 TypeEntryDetails::String => quote! { ::std::string::String },
1896 TypeEntryDetails::Boolean => quote! { bool },
1897 TypeEntryDetails::JsonValue => quote! { ::serde_json::Value },
1898 TypeEntryDetails::Integer(name) | TypeEntryDetails::Float(name) => {
1899 syn::parse_str::<syn::TypePath>(name)
1900 .unwrap()
1901 .to_token_stream()
1902 }
1903
1904 TypeEntryDetails::Reference(_) => panic!("references should be resolved by now"),
1905 }
1906 }
1907
1908 pub(crate) fn type_parameter_ident(
1909 &self,
1910 type_space: &TypeSpace,
1911 lifetime_name: Option<&str>,
1912 ) -> TokenStream {
1913 let lifetime = lifetime_name.map(|s| {
1914 vec![
1915 TokenTree::from(Punct::new('\'', Spacing::Joint)),
1916 TokenTree::from(format_ident!("{}", s)),
1917 ]
1918 .into_iter()
1919 .collect::<TokenStream>()
1920 });
1921 match &self.details {
1922 TypeEntryDetails::Enum(TypeEntryEnum { variants, .. })
1928 if variants
1929 .iter()
1930 .all(|variant| matches!(&variant.details, VariantDetails::Simple)) =>
1931 {
1932 self.type_ident(type_space, &type_space.settings.type_mod)
1933 }
1934 TypeEntryDetails::Enum(_)
1935 | TypeEntryDetails::Struct(_)
1936 | TypeEntryDetails::Newtype(_)
1937 | TypeEntryDetails::Vec(_)
1938 | TypeEntryDetails::Map(..)
1939 | TypeEntryDetails::Set(_)
1940 | TypeEntryDetails::Box(_)
1941 | TypeEntryDetails::Native(_)
1942 | TypeEntryDetails::Array(..)
1943 | TypeEntryDetails::JsonValue => {
1944 let ident = self.type_ident(type_space, &type_space.settings.type_mod);
1945 quote! {
1946 & #lifetime #ident
1947 }
1948 }
1949
1950 TypeEntryDetails::Option(id) => {
1951 let inner_ty = type_space
1952 .id_to_entry
1953 .get(id)
1954 .expect("unresolved type id for option");
1955 let inner_ident = inner_ty.type_parameter_ident(type_space, lifetime_name);
1956
1957 match &inner_ty.details {
1960 TypeEntryDetails::Option(_) => inner_ident,
1961 _ => quote! { Option<#inner_ident> },
1962 }
1963 }
1964
1965 TypeEntryDetails::Tuple(items) => {
1966 let type_streams = items.iter().map(|item| {
1967 type_space
1968 .id_to_entry
1969 .get(item)
1970 .expect("unresolved type id for tuple")
1971 .type_parameter_ident(type_space, lifetime_name)
1972 });
1973
1974 if items.len() != 1 {
1975 quote! { ( #(#type_streams),* ) }
1976 } else {
1977 quote! { ( #(#type_streams,)* ) }
1981 }
1982 }
1983
1984 TypeEntryDetails::Unit
1985 | TypeEntryDetails::Boolean
1986 | TypeEntryDetails::Integer(_)
1987 | TypeEntryDetails::Float(_) => {
1988 self.type_ident(type_space, &type_space.settings.type_mod)
1989 }
1990 TypeEntryDetails::String => quote! { & #lifetime str },
1991
1992 TypeEntryDetails::Reference(_) => panic!("references should be resolved by now"),
1993 }
1994 }
1995
1996 pub(crate) fn describe(&self) -> String {
1997 match &self.details {
1998 TypeEntryDetails::Enum(TypeEntryEnum { name, .. }) => format!("enum {}", name),
1999 TypeEntryDetails::Struct(TypeEntryStruct { name, .. }) => format!("struct {}", name),
2000 TypeEntryDetails::Newtype(TypeEntryNewtype { name, type_id, .. }) => {
2001 format!("newtype {} {}", name, type_id.0)
2002 }
2003
2004 TypeEntryDetails::Unit => "()".to_string(),
2005 TypeEntryDetails::Option(type_id) => format!("option {}", type_id.0),
2006 TypeEntryDetails::Vec(type_id) => format!("vec {}", type_id.0),
2007 TypeEntryDetails::Map(key_id, value_id) => {
2008 format!("map {} {}", key_id.0, value_id.0)
2009 }
2010 TypeEntryDetails::Set(type_id) => format!("set {}", type_id.0),
2011 TypeEntryDetails::Box(type_id) => format!("box {}", type_id.0),
2012 TypeEntryDetails::Tuple(type_ids) => {
2013 format!(
2014 "tuple ({})",
2015 type_ids
2016 .iter()
2017 .map(|type_id| type_id.0.to_string())
2018 .collect::<Vec<String>>()
2019 .join(", ")
2020 )
2021 }
2022 TypeEntryDetails::Array(type_id, length) => {
2023 format!("array {}; {}", type_id.0, length)
2024 }
2025 TypeEntryDetails::Boolean => "bool".to_string(),
2026 TypeEntryDetails::Native(TypeEntryNative {
2027 type_name: name, ..
2028 })
2029 | TypeEntryDetails::Integer(name)
2030 | TypeEntryDetails::Float(name) => name.clone(),
2031 TypeEntryDetails::String => "string".to_string(),
2032
2033 TypeEntryDetails::JsonValue => "json value".to_string(),
2034
2035 TypeEntryDetails::Reference(_) => unreachable!(),
2036 }
2037 }
2038}
2039
2040fn make_doc(name: &str, description: Option<&String>, schema: &Schema) -> TokenStream {
2041 let desc = match description {
2042 Some(desc) => desc,
2043 None => &format!("`{}`", name),
2044 };
2045 let schema_json = serde_json::to_string_pretty(schema).unwrap();
2046 let schema_lines = schema_json.lines();
2047 quote! {
2048 #[doc = #desc]
2049 #(
2054 #[doc = #schema_lines]
2055 )*
2056 }
2059}
2060
2061fn strings_to_derives<'a>(
2062 derive_set: BTreeSet<&'a str>,
2063 type_derives: &'a BTreeSet<String>,
2064 extra_derives: &'a [String],
2065) -> impl Iterator<Item = TokenStream> + 'a {
2066 let mut combined_derives = derive_set.clone();
2067 combined_derives.extend(extra_derives.iter().map(String::as_str));
2068 combined_derives.extend(type_derives.iter().map(String::as_str));
2069 combined_derives.into_iter().map(|derive| {
2070 syn::parse_str::<syn::Path>(derive)
2071 .unwrap()
2072 .into_token_stream()
2073 })
2074}
2075
2076fn strings_to_attrs<'a>(
2077 type_attrs: &'a BTreeSet<String>,
2078 extra_attrs: &'a [String],
2079) -> impl Iterator<Item = TokenStream> + 'a {
2080 let mut combined_attrs = BTreeSet::new();
2081 combined_attrs.extend(extra_attrs.iter().map(String::as_str));
2082 combined_attrs.extend(type_attrs.iter().map(String::as_str));
2083 combined_attrs
2084 .into_iter()
2085 .map(|attr| attr.parse::<TokenStream>().unwrap())
2086}
2087
2088fn untagged_newtype_variants(
2093 type_space: &TypeSpace,
2094 tag_type: &EnumTagType,
2095 variants: &[Variant],
2096 req_impl: TypeSpaceImpl,
2097 neg_impl: Option<TypeSpaceImpl>,
2098) -> bool {
2099 tag_type == &EnumTagType::Untagged
2100 && variants.iter().all(|variant| {
2101 match &variant.details {
2103 VariantDetails::Item(type_id) => Some(type_id),
2104 _ => None,
2105 }
2106 .map_or_else(
2107 || false,
2108 |type_id| {
2109 let type_entry = type_space.id_to_entry.get(type_id).unwrap();
2110 type_entry.has_impl(type_space, req_impl)
2112 && neg_impl
2113 .is_none_or(|neg_impl| !type_entry.has_impl(type_space, neg_impl))
2114 },
2115 )
2116 })
2117}
2118
2119fn untagged_newtype_string(
2123 type_space: &TypeSpace,
2124 tag_type: &EnumTagType,
2125 variants: &[Variant],
2126) -> bool {
2127 tag_type == &EnumTagType::Untagged
2128 && variants.iter().any(|variant| {
2129 match &variant.details {
2131 VariantDetails::Item(type_id) => Some(type_id),
2132 _ => None,
2133 }
2134 .map_or_else(
2135 || false,
2136 |type_id| {
2137 let type_entry = type_space.id_to_entry.get(type_id).unwrap();
2138 type_entry.has_impl(type_space, TypeSpaceImpl::FromStringIrrefutable)
2140 },
2141 )
2142 })
2143}
2144
2145#[cfg(test)]
2146mod tests {
2147 use crate::{
2148 type_entry::{SchemaWrapper, TypeEntry, TypeEntryStruct},
2149 TypeEntryDetails, TypeSpace,
2150 };
2151
2152 #[test]
2153 fn test_ident() {
2154 let ts = TypeSpace::default();
2155
2156 let type_mod = Some("the_mod".to_string());
2157
2158 let t = TypeEntry::new_integer("u32");
2159 let ident = t.type_ident(&ts, &type_mod);
2160 assert_eq!(ident.to_string(), "u32");
2161 let parameter = t.type_parameter_ident(&ts, None);
2162 assert_eq!(parameter.to_string(), "u32");
2163
2164 let t = TypeEntry::from(TypeEntryDetails::String);
2165 let ident = t.type_ident(&ts, &type_mod);
2166 assert_eq!(ident.to_string(), ":: std :: string :: String");
2167 let parameter = t.type_parameter_ident(&ts, None);
2168 assert_eq!(parameter.to_string(), "& str");
2169 let parameter = t.type_parameter_ident(&ts, Some("static"));
2170 assert_eq!(parameter.to_string(), "& 'static str");
2171
2172 let t = TypeEntry::from(TypeEntryDetails::Unit);
2173 let ident = t.type_ident(&ts, &type_mod);
2174 assert_eq!(ident.to_string(), "()");
2175 let parameter = t.type_parameter_ident(&ts, None);
2176 assert_eq!(parameter.to_string(), "()");
2177
2178 let t = TypeEntry::from(TypeEntryDetails::Struct(TypeEntryStruct {
2179 name: "SomeType".to_string(),
2180 rename: None,
2181 description: None,
2182 default: None,
2183 properties: vec![],
2184 deny_unknown_fields: false,
2185 schema: SchemaWrapper(schemars::schema::Schema::Bool(false)),
2186 }));
2187
2188 let ident = t.type_ident(&ts, &type_mod);
2189 assert_eq!(ident.to_string(), "the_mod :: SomeType");
2190 let parameter = t.type_parameter_ident(&ts, None);
2191 assert_eq!(parameter.to_string(), "& SomeType");
2192 let parameter = t.type_parameter_ident(&ts, Some("a"));
2193 assert_eq!(parameter.to_string(), "& 'a SomeType");
2194 }
2195}