openapi_trait_shared/codegen/
types.rs1use openapiv3::{IntegerFormat, NumberFormat, ReferenceOr, Schema, SchemaKind, StringFormat, Type};
2use proc_macro2::TokenStream;
3use quote::quote;
4
5#[must_use]
9pub fn schema_to_rust_type(ref_or: &ReferenceOr<Schema>, required: bool) -> TokenStream {
10 let inner = ref_or_to_inner_type(ref_or);
11 if required {
12 inner
13 } else {
14 quote! { ::core::option::Option<#inner> }
15 }
16}
17
18fn ref_or_to_inner_type(ref_or: &ReferenceOr<Schema>) -> TokenStream {
20 match ref_or {
21 ReferenceOr::Reference { reference } => ref_to_ident(reference),
22 ReferenceOr::Item(schema) => schema_kind_to_type(&schema.schema_kind),
23 }
24}
25
26#[must_use]
27pub fn ref_to_ident(reference: &str) -> TokenStream {
28 let name = reference.rsplit('/').next().unwrap_or(reference);
30 let ident = quote::format_ident!("{}", name);
31 quote! { #ident }
32}
33
34fn schema_kind_to_type(kind: &SchemaKind) -> TokenStream {
36 match kind {
37 SchemaKind::Type(t) => primitive_type_to_rust(t),
38 SchemaKind::OneOf { .. }
40 | SchemaKind::AllOf { .. }
41 | SchemaKind::AnyOf { .. }
42 | SchemaKind::Not { .. }
43 | SchemaKind::Any(_) => {
44 quote! { ::serde_json::Value }
45 }
46 }
47}
48
49fn primitive_type_to_rust(t: &Type) -> TokenStream {
51 match t {
52 Type::Integer(i) => {
53 if i.format == openapiv3::VariantOrUnknownOrEmpty::Item(IntegerFormat::Int32) {
54 quote! { i32 }
55 } else {
56 quote! { i64 }
57 }
58 }
59 Type::Number(n) => {
60 if n.format == openapiv3::VariantOrUnknownOrEmpty::Item(NumberFormat::Float) {
61 quote! { f32 }
62 } else {
63 quote! { f64 }
64 }
65 }
66 Type::String(s) => {
67 if s.enumeration.is_empty() {
70 if matches!(
71 &s.format,
72 openapiv3::VariantOrUnknownOrEmpty::Item(StringFormat::Binary)
73 ) {
74 quote! { ::std::vec::Vec<u8> }
75 } else {
76 quote! { ::std::string::String }
77 }
78 } else {
79 quote! { ::std::string::String }
80 }
81 }
82 Type::Boolean(_) => quote! { bool },
83 Type::Array(a) => {
84 let item_ty = a.items.as_ref().map_or_else(
85 || quote! { ::serde_json::Value },
86 |items| ref_or_to_inner_type(&items.clone().unbox()),
87 );
88 quote! { ::std::vec::Vec<#item_ty> }
89 }
90 Type::Object(_) => quote! { ::serde_json::Value },
91 }
92}
93
94#[must_use]
96pub fn is_string_enum(schema: &Schema) -> bool {
97 if let SchemaKind::Type(Type::String(s)) = &schema.schema_kind {
98 !s.enumeration.is_empty()
99 } else {
100 false
101 }
102}
103
104#[must_use]
106pub fn string_enum_values(schema: &Schema) -> Vec<String> {
107 if let SchemaKind::Type(Type::String(s)) = &schema.schema_kind {
108 s.enumeration.iter().filter_map(Clone::clone).collect()
109 } else {
110 vec![]
111 }
112}