1use std::{collections::HashMap, convert::TryInto, fmt::Display, ops::Deref, rc::Rc};
2
3use heck::{ToSnakeCase, ToUpperCamelCase};
4use ramhorns_derive::Content;
5
6use log::{error, trace};
7
8#[derive(Clone, Debug)]
10pub(crate) enum PropertyDataType {
11 Unknown,
12 Resolved(String, Option<String>),
13 Any,
14 RawString,
15 String(openapiv3::StringType),
16 Enum(String, String),
17 Boolean,
18 Integer(openapiv3::IntegerType),
19 Number(openapiv3::NumberType),
20 Model(String),
21 DiscModel(String, String),
22 Map(Box<PropertyDataType>, Box<PropertyDataType>),
23 Array(Box<PropertyDataType>),
24 Empty,
25}
26
27impl Display for PropertyDataType {
28 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
29 write!(f, "{}", self.as_str())
30 }
31}
32
33impl PropertyDataType {
34 fn as_str(&self) -> &str {
35 match self {
36 PropertyDataType::Unknown => "Unkown",
37 PropertyDataType::Resolved(inner, _) => inner.as_ref(),
38 PropertyDataType::Array(inner) => inner.as_str(),
39 PropertyDataType::Any => "Any",
40 PropertyDataType::Map(_, _) => "Map",
41 PropertyDataType::RawString => "String",
42 PropertyDataType::String(_) => "String",
43 PropertyDataType::Enum(_, _) => "Enum",
44 PropertyDataType::Boolean => "bool",
45 PropertyDataType::Integer(_) => "integer",
46 PropertyDataType::Number(_) => "number",
47 PropertyDataType::Model(inner) => inner.as_str(),
48 PropertyDataType::DiscModel(_, _) => "Disc",
49 PropertyDataType::Empty => "Empty",
50 }
51 }
52 fn format(&self) -> Option<&String> {
53 match self {
54 PropertyDataType::Resolved(_, format) => format.as_ref(),
55 _ => None,
56 }
57 }
58 fn resolve(&mut self, data_type: &str) {
59 self.set_if_unresolved(Self::Resolved(data_type.into(), None));
60 }
61 fn resolve_format<T: Into<String>>(&mut self, data_type: &str, format: T) {
62 self.set_if_unresolved(Self::Resolved(data_type.into(), Some(format.into())));
63 }
64 fn resolve_format_opt(&mut self, data_type: &str, format: Option<String>) {
65 self.set_if_unresolved(Self::Resolved(data_type.into(), format));
66 }
67 fn set_string(&mut self, data_type: &openapiv3::StringType) {
68 self.set_if_unresolved(Self::String(data_type.clone()));
69 }
70 fn set_array(&mut self, data_type: &Self) {
71 self.set_if_unresolved(Self::Array(Box::new(data_type.clone())));
72 }
73 fn set_boolean(&mut self) {
74 self.set_if_unresolved(Self::Boolean);
75 }
76 fn set_integer(&mut self, data_type: &openapiv3::IntegerType) {
77 self.set_if_unresolved(Self::Integer(data_type.clone()));
78 }
79 fn set_number(&mut self, data_type: &openapiv3::NumberType) {
80 self.set_if_unresolved(Self::Number(data_type.clone()));
81 }
82 fn set_model(&mut self, data_type: &str) {
83 self.set_if_unresolved(Self::Model(data_type.to_string()));
84 }
85 fn set_disc_model(&mut self, parent: String, name: &str) {
86 self.set_if_unresolved(Self::DiscModel(parent, name.to_string()));
87 }
88 fn set_map(&mut self, key: &Self, value: &Self) {
89 self.set_if_unresolved(Self::Map(Box::new(key.clone()), Box::new(value.clone())));
90 }
91 fn set_enum(&mut self, name: &str, data_type: &str) {
92 self.set_if_unresolved(Self::Enum(name.to_string(), data_type.to_string()));
93 }
94 fn set_any(&mut self) {
95 *self = Self::Any;
96 }
97 fn set_if_unresolved(&mut self, to: Self) {
98 if !matches!(self, Self::Resolved(_, _)) {
99 *self = to;
100 }
101 }
102}
103
104#[allow(clippy::derivable_impls)]
106impl Default for PropertyDataType {
107 fn default() -> Self {
108 Self::Unknown
109 }
110}
111
112impl ramhorns::Content for PropertyDataType {
113 #[inline]
114 fn is_truthy(&self) -> bool {
115 !self.as_str().is_empty()
116 }
117
118 #[inline]
119 fn capacity_hint(&self, _tpl: &ramhorns::Template) -> usize {
120 self.as_str().len()
121 }
122
123 #[inline]
124 fn render_escaped<E: ramhorns::encoding::Encoder>(
125 &self,
126 encoder: &mut E,
127 ) -> Result<(), E::Error> {
128 encoder.write_escaped(self.as_str())
129 }
130
131 #[inline]
132 fn render_unescaped<E: ramhorns::encoding::Encoder>(
133 &self,
134 encoder: &mut E,
135 ) -> Result<(), E::Error> {
136 encoder.write_unescaped(self.as_str())
137 }
138}
139
140pub(crate) type Properties = Vec<Property>;
142
143#[derive(Default, Content, Clone, Debug)]
149#[ramhorns(rename_all = "camelCase")]
150pub(crate) struct Property {
151 name: String,
153
154 pub classname: String,
159 schema_name: String,
160 class_filename: String,
161
162 base_name: String,
163 enum_name: Option<String>,
164 title: Option<String>,
166 description: Option<String>,
167 example: Option<String>,
168 class_var_name: String,
169 model_json: String,
170 data_type: PropertyDataType,
171 data_format: String,
172 type_: String,
174
175 is_string: bool,
177 is_integer: bool,
178 is_long: bool,
179 is_number: bool,
180 is_numeric: bool,
181 is_float: bool,
182 is_double: bool,
183 is_date: bool,
184 is_date_time: bool,
185 is_password: bool,
186 is_decimal: bool,
187 is_binary: bool,
188 is_byte: bool,
189 is_short: bool,
190 is_unbounded_integer: bool,
191 is_primitive_type: bool,
192 is_boolean: bool,
193 is_uuid: bool,
194 is_uri: bool,
195 is_any_type: bool,
196 is_enum: bool,
197 is_array: bool,
198 is_container: bool,
199 is_map: bool,
200 is_null: bool,
201 is_var: bool,
202
203 additional_properties_is_any_type: bool,
205
206 vars: Properties,
208 all_vars: Properties,
210
211 required_vars: Properties,
214 optional_vars: Properties,
216 read_only_vars: Properties,
218 read_write_vars: Properties,
220 parent_vars: Properties,
222
223 allowable_values: HashMap<String, Vec<EnumValue>>,
225
226 items: Option<Box<Property>>,
228
229 has_vars: bool,
231 empty_vars: bool,
233 has_enums: bool,
234 has_validation: bool,
236 is_nullable: bool,
238 has_required: bool,
240 has_optional: bool,
242 has_children: bool,
244
245 is_deprecated: bool,
246 has_only_read_only: bool,
247 required: bool,
248 max_properties: Option<usize>,
249 min_properties: Option<usize>,
250 unique_items: bool,
251 max_items: Option<usize>,
252 min_items: Option<usize>,
253 max_length: Option<usize>,
254 min_length: Option<usize>,
255 exclusive_minimum: bool,
256 exclusive_maximum: bool,
257 minimum: Option<String>,
258 maximum: Option<String>,
259 pattern: Option<String>,
260
261 is_model: bool,
263 is_component_model: bool,
265
266 one_of: Properties,
267 all_of: Properties,
268
269 discovered_props: Rc<Properties>,
271
272 parent: Option<Rc<Property>>,
274
275 vendor_extensions: HashMap<String, String>,
276}
277
278impl Display for Property {
279 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
280 write!(
281 f,
282 "{}/{}/{}.rs",
283 self.data_type(),
284 self.classname,
285 self.class_filename
286 )
287 }
288}
289
290impl Property {
291 pub fn with_data(mut self, data: &openapiv3::SchemaData) -> Self {
293 self.is_null = data.nullable;
294 self.is_nullable = data.nullable;
295 self.is_deprecated = data.deprecated;
296 self.title = data.title.clone();
297 self.description = data.description.as_ref().map(|s| s.replace('\n', " "));
298 self.example = data.example.as_ref().map(ToString::to_string);
299 self.vendor_extensions = data
300 .extensions
301 .iter()
302 .map(|(k, v)| (k.clone(), v.to_string()))
303 .collect();
304 self
305 }
306 pub fn with_model(mut self, model: bool) -> Self {
308 self.is_model = model;
309 self
310 }
311 pub fn with_component_model(mut self, root_model: bool) -> Self {
313 if root_model {
314 self.is_component_model = true;
315 }
316 self
317 }
318 pub fn type_ref(&self) -> &str {
320 &self.type_
321 }
322 pub fn data_type(&self) -> String {
324 self.data_type.to_string()
325 }
326 pub fn data_format(&self) -> String {
328 self.data_type.format().map(Into::into).unwrap_or_default()
329 }
330 pub fn filename(&self) -> &str {
332 self.class_filename.as_str()
333 }
334 pub fn with_data_property(mut self, type_: &PropertyDataType) -> Self {
336 self.data_type = type_.clone();
337 self
338 }
339 pub fn with_model_type(mut self, type_: &str) -> Self {
341 match self.parent() {
342 Some(parent) if type_.is_empty() => {
343 let parent_type = parent.type_.clone();
344 self.data_type.set_disc_model(parent_type, &self.name);
345 }
346 _ => {
347 self.data_type.set_model(type_);
348 }
349 }
350 self
351 }
352 fn with_data_type_any(mut self, is_add_props: bool) -> Self {
354 self.data_type.set_any();
355 self.is_any_type = true;
356 self.is_model = false;
357 self.is_container = true;
358 self.additional_properties_is_any_type = is_add_props;
359 self
360 }
361 pub fn with_type(mut self, type_: &str) -> Self {
363 self.type_ = type_.to_string();
364 self
365 }
366 pub fn with_one_all_of(self, single: Property) -> Self {
369 self.with_name(&single.name)
370 .with_type(&single.type_)
371 .with_data_property(&single.data_type)
372 .with_model(true)
373 .with_parent(&Some(&single))
374 .with_all_of(vec![single])
375 }
376 fn with_all_of(mut self, all_of: Vec<Property>) -> Self {
377 self.all_of = all_of;
378 self
379 }
380 fn discovered_props(&self) -> &Vec<Property> {
382 &self.discovered_props
383 }
384 pub fn discovered_models(&self) -> Vec<Property> {
386 self.discovered_props()
387 .iter()
388 .flat_map(|m| {
389 let mut v = m.discovered_models();
390 v.push(m.clone());
391 v
392 })
393 .filter(|p| !p.is_component_model && p.is_model && !p.is_all_of() && !p.is_enum)
394 .collect::<Vec<_>>()
395 }
396}
397impl From<&openapiv3::SchemaData> for Property {
398 fn from(data: &openapiv3::SchemaData) -> Self {
399 Self::default().with_data(data)
400 }
401}
402
403impl Property {
404 pub fn from_schema(
406 root: &super::OpenApiV3,
407 parent: Option<&Property>,
408 schema: &openapiv3::Schema,
409 name: Option<&str>,
410 type_: Option<&str>,
411 ) -> Self {
412 let name = name.unwrap_or_default();
413 let type_ = type_.unwrap_or_default();
414 trace!(
415 "PropertyFromSchema: {}/{}/{}",
416 name,
417 type_,
418 Self::schema_kind_str(schema)
419 );
420 let prop = Property::from(&schema.schema_data)
421 .with_name(name)
422 .with_parent(&parent)
423 .with_type(type_)
424 .with_component_model(root.contains_schema(type_));
425
426 prop.with_kind(root, schema, &schema.schema_kind, parent, name, type_)
427 }
428
429 fn schema_kind_str(schema: &openapiv3::Schema) -> &str {
430 match &schema.schema_kind {
431 openapiv3::SchemaKind::Type(_) => "type",
432 openapiv3::SchemaKind::OneOf { .. } => "oneOf",
433 openapiv3::SchemaKind::AllOf { .. } => "allOf",
434 openapiv3::SchemaKind::AnyOf { .. } => "anyOf",
435 openapiv3::SchemaKind::Not { .. } => "not",
436 openapiv3::SchemaKind::Any(..) => "any",
437 }
438 }
439
440 fn with_kind(
441 mut self,
442 root: &super::OpenApiV3,
443 schema: &openapiv3::Schema,
444 schema_kind: &openapiv3::SchemaKind,
445 parent: Option<&Self>,
446 name: &str,
447 type_: &str,
448 ) -> Self {
449 match schema_kind {
450 openapiv3::SchemaKind::Type(t) => match t {
451 openapiv3::Type::String(t) => self.with_string(root, t),
452 openapiv3::Type::Number(t) => self.with_number(root, t),
453 openapiv3::Type::Integer(t) => self.with_integer(root, t),
454 openapiv3::Type::Object(t) => self.with_model_type(type_).with_obj(root, t),
455 openapiv3::Type::Array(t) => self.with_array(root, t),
456 openapiv3::Type::Boolean(_) => {
457 self.data_type.set_boolean();
458 self.is_boolean = true;
459 self.is_primitive_type = true;
460 self
461 }
462 },
463 openapiv3::SchemaKind::OneOf { .. } => {
464 panic!("OneOf: {:#?} not implemented", schema);
465 }
466 openapiv3::SchemaKind::AllOf { all_of } if all_of.len() != 1 => {
467 unimplemented!()
468 }
469 openapiv3::SchemaKind::AllOf { all_of } => {
470 let first = all_of.first().unwrap();
471 let first_model = root
472 .resolve_reference_or(first, parent, Some(name), None)
473 .with_data(&schema.schema_data);
474 Self::from(&schema.schema_data).with_one_all_of(first_model)
475 }
476 openapiv3::SchemaKind::AnyOf { .. } => {
477 unimplemented!()
478 }
479 openapiv3::SchemaKind::Not { .. } => {
480 unimplemented!()
481 }
482 openapiv3::SchemaKind::Any(any_schema) => match &any_schema.typ {
486 Some(typ) => match typ.as_str() {
487 "bool" => {
488 let kind = openapiv3::SchemaKind::Type(openapiv3::Type::Boolean(
489 openapiv3::BooleanType {
490 enumeration: vec![],
491 },
492 ));
493 self.with_kind(root, schema, &kind, parent, name, type_)
494 }
495 "object" => self.with_model_type(type_).with_anyobj(root, any_schema),
496 not_handled => {
497 error!("BUG - must handle {not_handled} data type as AnySchema");
499 self.with_data_type_any(false)
500 }
501 },
502 None => self.with_data_type_any(false),
504 },
505 }
506 }
507
508 fn assign_classnames(&mut self) {
509 if self.classname.is_empty() && self.is_model && !self.is_var {
510 let schema_name = self.data_type.as_str();
511 self.class_filename = schema_name.to_snake_case();
512 self.classname = schema_name.to_upper_camel_case();
513 }
514 self.assign_enumnames();
515 }
516 fn assign_varnames(&mut self) {
517 if !self.name.is_empty() {
518 self.name = self.name.to_snake_case();
519 }
520 }
521 fn assign_enumnames(&mut self) {
522 if self.is_enum {
523 self.enum_name = Some(self.data_type());
524 }
525 }
526 fn string_format_str(format: openapiv3::StringFormat) -> &'static str {
527 match format {
528 openapiv3::StringFormat::Date => "date",
529 openapiv3::StringFormat::DateTime => "date-time",
530 openapiv3::StringFormat::Password => "password",
531 openapiv3::StringFormat::Byte => "byte",
532 openapiv3::StringFormat::Binary => "binary",
533 }
534 }
535 fn post_process_dt(data_type: &mut PropertyDataType, is_decl: bool) {
537 match data_type.clone() {
538 PropertyDataType::Unknown => {}
539 PropertyDataType::Resolved(_, _) => {}
540 PropertyDataType::Any => data_type.resolve("serde_json::Value"),
541 PropertyDataType::RawString => data_type.resolve("String"),
542 PropertyDataType::String(str) => {
543 match str.format {
544 openapiv3::VariantOrUnknownOrEmpty::Item(format) => {
545 data_type.resolve_format("String", Self::string_format_str(format));
547 }
548 openapiv3::VariantOrUnknownOrEmpty::Unknown(format) => match format.as_str() {
549 "uuid" => data_type.resolve("uuid::Uuid"),
550 "uri" => data_type.resolve("url::Url"),
551 _ => data_type.resolve_format("String", format),
552 },
553 openapiv3::VariantOrUnknownOrEmpty::Empty => {
554 data_type.resolve("String");
555 }
556 }
557 }
558 PropertyDataType::Enum(name, type_) if !is_decl => {
559 let enum_ = if type_.is_empty() { name } else { type_ }.to_upper_camel_case();
560 data_type.resolve(&format!("crate::models::{enum_}"))
561 }
562 PropertyDataType::Enum(name, type_) => {
563 let enum_ = if type_.is_empty() { name } else { type_ }.to_upper_camel_case();
564 data_type.resolve(&enum_)
565 }
566 PropertyDataType::Boolean => data_type.resolve("bool"),
567 PropertyDataType::Integer(type_) => {
568 let (signed, mut bits, format) = match type_.format {
569 openapiv3::VariantOrUnknownOrEmpty::Item(item) => match item {
570 openapiv3::IntegerFormat::Int32 => (true, 32, Some("int32".into())),
571 openapiv3::IntegerFormat::Int64 => (true, 64, Some("int64".into())),
572 },
573 openapiv3::VariantOrUnknownOrEmpty::Unknown(format) => match format.as_str() {
574 "uint32" => (false, 32, Some(format)),
575 "uint64" => (false, 64, Some(format)),
576 "int16" => (true, 16, Some(format)),
577 "uint16" => (false, 16, Some(format)),
578 "int8" => (true, 8, Some(format)),
579 "uint8" => (false, 8, Some(format)),
580 _ => (true, 0, Some(format)),
581 },
582 _ => (true, 0, None),
583 };
584 let signed = type_.minimum.map(|m| m < 0).unwrap_or(signed);
585 if let Some(max) = type_.maximum {
586 let r_bits = floor_log2(max.try_into().unwrap());
587 if bits == 0 || bits > r_bits {
588 bits = r_bits;
589 }
590 }
591
592 let bits = if bits == 0 {
594 "size".to_string()
595 } else {
596 bits.to_string()
597 };
598
599 data_type.resolve_format_opt(
601 &format!("{}{}", if signed { "i" } else { "u" }, bits),
602 format,
603 )
604 }
605 PropertyDataType::Number(type_) => {
606 data_type.resolve(match type_.format {
607 openapiv3::VariantOrUnknownOrEmpty::Item(openapiv3::NumberFormat::Float) => {
608 "f32"
609 }
610 openapiv3::VariantOrUnknownOrEmpty::Item(openapiv3::NumberFormat::Double) => {
611 "f64"
612 }
613 openapiv3::VariantOrUnknownOrEmpty::Unknown(_) => "f64",
614 openapiv3::VariantOrUnknownOrEmpty::Empty => "f64",
615 });
616 }
617 PropertyDataType::Model(model) if !is_decl => {
618 data_type.resolve(&format!("crate::models::{model}"))
619 }
620 PropertyDataType::Model(model) => data_type.resolve(&model),
621 PropertyDataType::DiscModel(parent, this) => {
622 let this = this.to_upper_camel_case();
623 let parent = parent.to_upper_camel_case();
624 if is_decl {
625 data_type.resolve(&format!("{parent}{this}"));
626 } else {
627 data_type.resolve(&format!("crate::models::{parent}{this}"));
628 }
629 }
630 PropertyDataType::Map(key, mut value) => {
631 Self::post_process_dt(&mut value, false);
632 data_type.resolve(&format!(
633 "::std::collections::HashMap<{}, {}>",
634 key.as_ref(),
635 value.as_str()
636 ))
637 }
638 PropertyDataType::Array(mut inner) => {
639 Self::post_process_dt(&mut inner, is_decl);
640 data_type.resolve(&format!("Vec<{}>", inner.as_str()))
641 }
642 PropertyDataType::Empty => data_type.resolve("()"),
643 }
644 }
645 pub(crate) fn uninline_enums(&mut self) {
648 if self.is_var && self.is_component_model && self.is_enum {
649 self.is_enum = false;
651 }
652 }
653 pub fn post_process(mut self) -> Property {
657 self.post_process_refmut();
658 self
659 }
660 pub fn post_process_data_type(mut self) -> Property {
663 Self::post_process_dt(&mut self.data_type, false);
664 self
665 }
666 fn post_process_refmut(&mut self) {
667 let mut is_decl = !self.is_var && !self.is_container;
671 if self.is_var && !self.is_component_model && self.is_enum {
672 is_decl = true;
673 }
674 Self::post_process_dt(&mut self.data_type, is_decl);
675
676 self.assign_classnames();
678 self.assign_varnames();
680
681 self.uninline_enums();
684
685 for var in &mut self.vars {
687 var.post_process_refmut();
688 }
689 for var in &mut self.required_vars {
690 var.post_process_refmut();
691 }
692 for var in &mut self.optional_vars {
693 var.post_process_refmut();
694 }
695 for var in &mut self.all_vars {
696 var.post_process_refmut();
697 }
698 for var in &mut self.all_of {
699 var.post_process_refmut();
700 }
701 for var in &mut self.one_of {
702 var.post_process_refmut();
703 }
704 if let Some(item) = &mut self.items {
705 item.post_process_refmut();
706 }
707 }
708
709 fn parent(&self) -> Option<&Self> {
710 match &self.parent {
711 None => None,
712 Some(parent) => Some(parent.deref()),
713 }
714 }
715 pub fn items(&self) -> &Option<Box<Self>> {
717 &self.items
718 }
719 pub fn with_name(mut self, name: &str) -> Self {
721 self.name = name.to_string();
722 self.base_name = name.to_string();
723 self
724 }
725 fn with_is_var(mut self, is_var: bool) -> Self {
727 self.is_var = is_var;
728 self
729 }
730 pub fn schema(&self) -> &str {
733 if self.data_type.as_str().is_empty() {
734 panic!("Schema data type should not be empty! Schema: {:#?}", self);
735 }
736 self.data_type.as_str()
737 }
738 pub fn with_required(mut self, required: bool) -> Self {
740 self.required = required;
741 self
742 }
743 pub fn with_parent(mut self, parent: &Option<&Self>) -> Self {
745 self.parent = parent.map(|p| Rc::new(p.clone()));
746 self
747 }
748 pub fn is_model(&self) -> bool {
750 self.is_model
751 }
752 pub fn is_string(&self) -> bool {
754 self.is_string
755 }
756 pub fn is_array(&self) -> bool {
758 self.is_array
759 }
760 pub fn is_uuid(&self) -> bool {
762 self.is_uuid
763 }
764 pub fn is_uri(&self) -> bool {
766 self.is_uri
767 }
768 pub fn is_container(&self) -> bool {
770 self.is_container
771 }
772 pub fn is_any_type(&self) -> bool {
774 self.is_any_type
775 }
776 pub fn is_primitive_type(&self) -> bool {
778 self.is_primitive_type
779 }
780 pub fn is_all_of(&self) -> bool {
782 !self.all_of.is_empty()
783 }
784 fn with_array(mut self, _root: &super::OpenApiV3, by: &openapiv3::ArrayType) -> Self {
785 self.items = by
786 .items
787 .clone()
788 .map(|i| _root.resolve_reference_or(&i.unbox(), Some(&self), None, None))
789 .map(|i| i.with_is_var(true))
790 .map(Box::new);
791 self.min_items = by.min_items;
792 self.max_items = by.max_items;
793 self.unique_items = by.unique_items;
794 self.is_array = true;
795 match &self.items {
796 Some(items) => {
797 self.data_type.set_array(&items.data_type);
798 }
799 None => {
800 panic!("BUG: an array without an inner type: {:?}", self);
801 }
802 }
803 self.is_container = true;
804 self
805 }
806 fn with_anyobj(mut self, root: &super::OpenApiV3, by: &openapiv3::AnySchema) -> Self {
807 self.min_properties = by.min_properties;
808 self.max_properties = by.max_properties;
809
810 let vars = by
811 .properties
812 .iter()
813 .map(|(k, v)| root.resolve_reference_or(&v.clone().unbox(), Some(&self), Some(k), None))
814 .map(|m| {
815 let required = by.required.contains(&m.name);
816 m.with_required(required)
817 })
818 .collect::<Vec<_>>();
819
820 let vars = vars
821 .into_iter()
822 .map(|p| p.with_is_var(true))
823 .collect::<Vec<_>>();
824
825 self.required_vars = vars
826 .iter()
827 .filter(|m| m.required)
828 .cloned()
829 .collect::<Vec<_>>();
830 self.optional_vars = vars
831 .iter()
832 .filter(|m| !m.required)
833 .cloned()
834 .collect::<Vec<_>>();
835 self.vars = vars;
836
837 let mut vars_ = self.vars.iter().filter(|p| !p.required).collect::<Vec<_>>();
838 if vars_.len() != self.vars.len() {
839 panic!("Not Supported - all vars of oneOf must be optional");
840 }
841
842 let one_of = &by.one_of;
843 one_of
844 .iter()
845 .flat_map(|p| p.as_item())
846 .map(|s| match &s.schema_kind {
847 openapiv3::SchemaKind::Any(schema) => schema,
848 _ => todo!(),
849 })
850 .filter(|o| o.required.len() == 1)
851 .for_each(|o| vars_.retain(|v| v.name != o.required[0]));
852
853 self.is_model = true;
854 self.one_of = vec![self.clone()];
855 self
856 }
857 fn with_obj(mut self, root: &super::OpenApiV3, by: &openapiv3::ObjectType) -> Self {
858 self.min_properties = by.min_properties;
859 self.max_properties = by.max_properties;
860
861 if let Some(props) = &by.additional_properties {
862 match props {
863 openapiv3::AdditionalProperties::Any(any) => {
864 if *any {
865 return self.with_data_type_any(*any);
866 }
867 }
868 openapiv3::AdditionalProperties::Schema(ref_or) => match ref_or.deref() {
869 openapiv3::ReferenceOr::Reference { reference } => {
870 let inner = root.resolve_schema_name(None, reference);
871 self.data_type
872 .set_map(&PropertyDataType::RawString, &inner.data_type);
873 self.discovered_props = Rc::new(vec![inner]);
874 return self;
875 }
876 openapiv3::ReferenceOr::Item(item) => {
877 let property = Self::from_schema(root, None, item, None, None);
878 self.data_type
879 .set_map(&PropertyDataType::RawString, &property.data_type);
880 return self;
881 }
882 },
883 }
884 }
885
886 if !root.resolving(&self) {
887 let vars = by
888 .properties
889 .iter()
890 .map(|(k, v)| {
891 root.resolve_reference_or(&v.clone().unbox(), Some(&self), Some(k), None)
892 })
893 .map(|m| {
894 let required = by.required.contains(&m.name);
895 m.with_required(required)
896 })
897 .collect::<Vec<_>>();
898
899 if vars.is_empty() {
900 return self.with_data_type_any(false);
901 }
902 self.is_model = true;
903
904 self.discovered_props = Rc::new(vars.clone());
905 let vars = vars
906 .into_iter()
907 .map(|p| p.with_is_var(true))
908 .collect::<Vec<_>>();
909
910 self.required_vars = vars
911 .iter()
912 .filter(|m| m.required)
913 .cloned()
914 .collect::<Vec<_>>();
915 self.optional_vars = vars
916 .iter()
917 .filter(|m| !m.required)
918 .cloned()
919 .collect::<Vec<_>>();
920 self.vars = vars;
921 } else {
922 self.is_model = true;
924 }
925
926 self
943 }
944 fn with_integer(mut self, _root: &super::OpenApiV3, by: &openapiv3::IntegerType) -> Self {
945 self.exclusive_maximum = by.exclusive_maximum;
946 self.exclusive_minimum = by.exclusive_minimum;
947 self.minimum = by.minimum.map(|v| v.to_string());
948 self.maximum = by.maximum.map(|v| v.to_string());
949 self.is_integer = true;
950 self.is_primitive_type = true;
951 self.data_type.set_integer(by);
952 self
953 }
954 fn with_number(mut self, _root: &super::OpenApiV3, by: &openapiv3::NumberType) -> Self {
955 self.exclusive_maximum = by.exclusive_maximum;
956 self.exclusive_minimum = by.exclusive_minimum;
957 self.minimum = by.minimum.map(|v| v.to_string());
958 self.maximum = by.maximum.map(|v| v.to_string());
959 self.data_type.set_number(by);
960 self.is_primitive_type = true;
961 self
962 }
963 fn with_string(mut self, _root: &super::OpenApiV3, by: &openapiv3::StringType) -> Self {
964 self.pattern = by.pattern.clone();
965 self.has_enums = !by.enumeration.is_empty();
966 self.is_enum = self.has_enums;
967
968 self.min_length = by.min_length;
969 self.data_type.set_string(by);
970
971 match &by.format {
972 openapiv3::VariantOrUnknownOrEmpty::Item(item) => match item {
973 openapiv3::StringFormat::Date => self.is_date = true,
974 openapiv3::StringFormat::DateTime => self.is_date_time = true,
975 openapiv3::StringFormat::Password => self.is_date = true,
976 openapiv3::StringFormat::Byte => self.is_byte = true,
977 openapiv3::StringFormat::Binary => self.is_binary = true,
978 },
979 openapiv3::VariantOrUnknownOrEmpty::Unknown(format) => match format.as_str() {
980 "uuid" => self.is_uuid = true,
981 "uri" => self.is_string = true,
982 "date" => self.is_date = true,
983 "date-time" => self.is_date_time = true,
984 _ => {
985 self.is_string = true;
986 }
987 },
988 openapiv3::VariantOrUnknownOrEmpty::Empty => {
989 self.is_string = true;
990 }
991 }
992
993 if self.is_enum {
994 let enum_vars = by
995 .enumeration
996 .iter()
997 .flatten()
998 .map(|v| EnumValue {
999 name: v.to_upper_camel_case(),
1000 value: v.to_string(),
1001 })
1002 .collect::<Vec<_>>();
1003
1004 self.is_model = true;
1005 self.is_string = false;
1006 self.allowable_values.insert("enumVars".into(), enum_vars);
1007 self.data_type.set_enum(&self.name, &self.type_);
1008 } else {
1009 self.is_primitive_type = true;
1010 }
1011
1012 self
1013 }
1014}
1015
1016#[derive(Default, Content, Clone, Debug)]
1017#[ramhorns(rename_all = "camelCase")]
1018pub(crate) struct EnumValue {
1019 name: String,
1020 value: String,
1021}
1022
1023fn floor_log2(x: u64) -> u64 {
1024 65 - (x.leading_zeros() as u64)
1025}