diff --git a/bin/utils/test_file_list.yaml b/bin/utils/test_file_list.yaml index 1d0fb391de0..d9f0ef85e8d 100644 --- a/bin/utils/test_file_list.yaml +++ b/bin/utils/test_file_list.yaml @@ -61,4 +61,4 @@ - filename: "samples/server/petstore/rust-axum/output/rust-axum-oneof/tests/oneof_with_discriminator.rs" sha256: 2d4f5a069fdcb3057bb078d5e75b3de63cd477b97725e457079df24bd2c30600 - filename: "samples/server/petstore/rust-axum/output/openapi-v3/tests/oneof_untagged.rs" - sha256: e72fbf81a9849dc7abb7e2169f2fc355c8b1cf991c0e2ffc083126abd9e966e7 + sha256: 1d3fb01f65e98290b1d3eece28014c7d3e3f2fdf18e7110249d3c591cc4642ab diff --git a/docs/generators/rust-axum.md b/docs/generators/rust-axum.md index 743b58779eb..19d87abc124 100644 --- a/docs/generators/rust-axum.md +++ b/docs/generators/rust-axum.md @@ -77,6 +77,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • dyn
  • else
  • enum
  • +
  • errors
  • extern
  • false
  • final
  • @@ -207,8 +208,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl |Composite|✓|OAS2,OAS3 |Polymorphism|✗|OAS2,OAS3 |Union|✗|OAS3 -|allOf|✗|OAS2,OAS3 -|anyOf|✗|OAS3 +|allOf|✓|OAS2,OAS3 +|anyOf|✓|OAS3 |oneOf|✓|OAS3 |not|✗|OAS3 diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java index 1c883774d85..1366797328a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustAxumServerCodegen.java @@ -99,6 +99,18 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege public RustAxumServerCodegen() { super(); + // The `#[validate(nested)]` macro relies on an internal field named `errors` to accumulate validation results. Therefore, defining a struct like this will fail: + // + // ```rust + // struct A { + // #[validate(nested)] + // errors: B, + // } + // ``` + // + // To avoid this, either rename the field to something other than "errors", or reserve it. + this.reservedWords.add("errors"); + modifyFeatureSet(features -> features .wireFormatFeatures(EnumSet.of( WireFormatFeature.JSON, @@ -112,7 +124,9 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege .schemaSupportFeatures(EnumSet.of( SchemaSupportFeature.Simple, SchemaSupportFeature.Composite, - SchemaSupportFeature.oneOf + SchemaSupportFeature.oneOf, + SchemaSupportFeature.anyOf, + SchemaSupportFeature.allOf )) .excludeGlobalFeatures( GlobalFeature.Info, @@ -633,105 +647,163 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege return op; } - private void postProcessOneOfModels(List allModels) { - final HashMap> oneOfMapDiscriminator = new HashMap<>(); + private void postProcessPolymorphism(final List allModels) { + final HashMap> discriminatorsForModel = new HashMap<>(); - for (ModelMap mo : allModels) { + for (final ModelMap mo : allModels) { final CodegenModel cm = mo.getModel(); final CodegenComposedSchemas cs = cm.getComposedSchemas(); if (cs != null) { final List csOneOf = cs.getOneOf(); - if (csOneOf != null) { - for (CodegenProperty model : csOneOf) { - // Generate a valid name for the enum variant. - // Mainly needed for primitive types. - - model.datatypeWithEnum = camelize(model.dataType.replaceAll("(?:\\w+::)+(\\w+)", "$1") - .replace("<", "Of").replace(">", "")); - - // Primitive type is not properly set, this overrides it to guarantee adequate model generation. - if (!model.getDataType().matches(String.format(Locale.ROOT, ".*::%s", model.getDatatypeWithEnum()))) { - model.isPrimitiveType = true; - } - } - + processPolymorphismDataType(csOneOf); cs.setOneOf(csOneOf); cm.setComposedSchemas(cs); } + + final List csAnyOf = cs.getAnyOf(); + if (csAnyOf != null) { + processPolymorphismDataType(csAnyOf); + cs.setAnyOf(csAnyOf); + cm.setComposedSchemas(cs); + } } if (cm.discriminator != null) { - for (String model : cm.oneOf) { - List discriminators = oneOfMapDiscriminator.getOrDefault(model, new ArrayList<>()); + for (final String model : cm.oneOf) { + final List discriminators = discriminatorsForModel.getOrDefault(model, new ArrayList<>()); discriminators.add(cm.discriminator.getPropertyName()); - oneOfMapDiscriminator.put(model, discriminators); + discriminatorsForModel.put(model, discriminators); + } + + for (final String model : cm.anyOf) { + final List discriminators = discriminatorsForModel.getOrDefault(model, new ArrayList<>()); + discriminators.add(cm.discriminator.getPropertyName()); + discriminatorsForModel.put(model, discriminators); } } } + final var blocking = new HashSet(); for (ModelMap mo : allModels) { final CodegenModel cm = mo.getModel(); - for (CodegenProperty var : cm.vars) { - var.isDiscriminator = false; + final List discriminators = discriminatorsForModel.get(cm.getSchemaName()); + if (discriminators != null) { + // If the discriminator field is not a defined attribute in the variant structure, create it. + if (!discriminating(discriminators, cm)) { + final String discriminator = discriminators.get(0); + + CodegenProperty property = new CodegenProperty(); + + // Static attributes + // Only strings are supported by serde for tag field types, so it's the only one we'll deal with + property.openApiType = "string"; + property.complexType = "string"; + property.dataType = "String"; + property.datatypeWithEnum = "String"; + property.baseType = "string"; + property.required = true; + property.isPrimitiveType = true; + property.isString = true; + property.isDiscriminator = true; + + // Attributes based on the discriminator value + property.baseName = discriminator; + property.name = discriminator; + property.nameInCamelCase = camelize(discriminator); + property.nameInPascalCase = property.nameInCamelCase.substring(0, 1).toUpperCase(Locale.ROOT) + property.nameInCamelCase.substring(1); + property.nameInSnakeCase = underscore(discriminator).toUpperCase(Locale.ROOT); + property.getter = String.format(Locale.ROOT, "get%s", property.nameInPascalCase); + property.setter = String.format(Locale.ROOT, "set%s", property.nameInPascalCase); + property.defaultValueWithParam = String.format(Locale.ROOT, " = data.%s;", property.name); + + // Attributes based on the model name + property.defaultValue = String.format(Locale.ROOT, "r#\"%s\"#.to_string()", cm.getSchemaName()); + property.jsonSchema = String.format(Locale.ROOT, "{ \"default\":\"%s\"; \"type\":\"string\" }", cm.getSchemaName()); + + cm.vars.add(property); + } } - final List discriminatorsForModel = oneOfMapDiscriminator.get(cm.getSchemaName()); + if (cm.vars.stream().noneMatch(v -> v.isDiscriminator)) { + blocking.add(cm.getSchemaName()); + } + } - if (discriminatorsForModel != null) { - for (String discriminator : discriminatorsForModel) { - boolean hasDiscriminatorDefined = false; - - for (CodegenProperty var : cm.vars) { - if (var.baseName.equals(discriminator)) { - var.isDiscriminator = true; - hasDiscriminatorDefined = true; - break; - } - } - - // If the discriminator field is not a defined attribute in the variant structure, create it. - if (!hasDiscriminatorDefined) { - CodegenProperty property = new CodegenProperty(); - - // Static attributes - // Only strings are supported by serde for tag field types, so it's the only one we'll deal with - property.openApiType = "string"; - property.complexType = "string"; - property.dataType = "String"; - property.datatypeWithEnum = "String"; - property.baseType = "string"; - property.required = true; - property.isPrimitiveType = true; - property.isString = true; - property.isDiscriminator = true; - - // Attributes based on the discriminator value - property.baseName = discriminator; - property.name = discriminator; - property.nameInCamelCase = camelize(discriminator); - property.nameInPascalCase = property.nameInCamelCase.substring(0, 1).toUpperCase(Locale.ROOT) + property.nameInCamelCase.substring(1); - property.nameInSnakeCase = underscore(discriminator).toUpperCase(Locale.ROOT); - property.getter = String.format(Locale.ROOT, "get%s", property.nameInPascalCase); - property.setter = String.format(Locale.ROOT, "set%s", property.nameInPascalCase); - property.defaultValueWithParam = String.format(Locale.ROOT, " = data.%s;", property.name); - - // Attributes based on the model name - property.defaultValue = String.format(Locale.ROOT, "r#\"%s\"#.to_string()", cm.getSchemaName()); - property.jsonSchema = String.format(Locale.ROOT, "{ \"default\":\"%s\"; \"type\":\"string\" }", cm.getSchemaName()); - - cm.vars.add(property); - } + for (final ModelMap mo : allModels) { + final CodegenModel cm = mo.getModel(); + if (cm.discriminator != null) { + // if no discriminator in any of variant -> disable discriminator + if (cm.oneOf.stream().anyMatch(blocking::contains) || cm.anyOf.stream().anyMatch(blocking::contains)) { + cm.discriminator = null; } } } } + private static boolean discriminating(final List discriminatorsForModel, final CodegenModel cm) { + resetDiscriminatorProperty(cm); + + // Discriminator will be presented as enum tag -> One and only one tag is allowed + int countString = 0; + int countNonString = 0; + for (final CodegenProperty var : cm.vars) { + if (discriminatorsForModel.stream().anyMatch(discriminator -> var.baseName.equals(discriminator) || var.name.equals(discriminator))) { + if (var.isString) { + var.isDiscriminator = true; + ++countString; + } else + ++countNonString; + } + } + + if (countString > 0 && (countNonString > 0 || countString > 1)) { + // at least two discriminator, one of them is string -> should not render serde tag + resetDiscriminatorProperty(cm); + } + + return countNonString > 0 || countString > 0; + } + + private static void resetDiscriminatorProperty(final CodegenModel cm) { + for (final CodegenProperty var : cm.vars) { + var.isDiscriminator = false; + } + } + + private static void processPolymorphismDataType(final List cp) { + final HashSet dedupDataTypeWithEnum = new HashSet<>(); + final HashMap dedupDataType = new HashMap<>(); + + int idx = 0; + for (CodegenProperty model : cp) { + // Generate a valid name for the enum variant. + // Mainly needed for primitive types. + model.datatypeWithEnum = camelize(model.dataType.replaceAll("(?:\\w+::)+(\\w+)", "$1") + .replace("<", "Of").replace(">", "")).replace(" ", "").replace(",", ""); + if (!dedupDataTypeWithEnum.add(model.datatypeWithEnum)) { + model.datatypeWithEnum += ++idx; + } + + dedupDataType.put(model.getDataType(), dedupDataType.getOrDefault(model.getDataType(), 0) + 1); + + if (!model.getDataType().matches(String.format(Locale.ROOT, ".*::%s", model.getDatatypeWithEnum()))) { + model.isPrimitiveType = true; + } + } + + for (CodegenProperty model : cp) { + if (dedupDataType.get(model.getDataType()) == 1) { + model.vendorExtensions.put("x-from-trait", true); + } + } + } + @Override public OperationsMap postProcessOperationsWithModels(final OperationsMap operationsMap, List allModels) { - postProcessOneOfModels(allModels); + postProcessPolymorphism(allModels); final OperationMap operations = operationsMap.getOperations(); operations.put("classnamePascalCase", camelize(operations.getClassname())); @@ -901,7 +973,7 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege // restore things to sensible values. @Override public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) { - final Schema original_schema = ModelUtils.getSchemaFromRequestBody(body); + final var original_schema = ModelUtils.getSchemaFromRequestBody(body); CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); if (StringUtils.isNotBlank(original_schema.get$ref())) { @@ -920,10 +992,10 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege @Override public String toInstantiationType(final Schema p) { if (ModelUtils.isArraySchema(p)) { - final Schema inner = ModelUtils.getSchemaItems(p); + final var inner = ModelUtils.getSchemaItems(p); return instantiationTypes.get("array") + "<" + getSchemaType(inner) + ">"; } else if (ModelUtils.isMapSchema(p)) { - final Schema inner = ModelUtils.getAdditionalProperties(p); + final var inner = ModelUtils.getAdditionalProperties(p); return instantiationTypes.get("map") + "<" + typeMapping.get("string") + ", " + getSchemaType(inner) + ">"; } else { return null; @@ -952,6 +1024,10 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege @Override public String toDefaultValue(final Schema p) { String defaultValue = null; + + if (ModelUtils.isEnumSchema(p)) + return null; + if ((ModelUtils.isNullable(p)) && (p.getDefault() != null) && ("null".equalsIgnoreCase(p.getDefault().toString()))) return "Nullable::Null"; @@ -965,6 +1041,9 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege } else if (ModelUtils.isNumberSchema(p)) { if (p.getDefault() != null) { defaultValue = p.getDefault().toString(); + if (!defaultValue.contains(".")) { + defaultValue += ".0"; + } } } else if (ModelUtils.isIntegerSchema(p)) { if (p.getDefault() != null) { @@ -1081,7 +1160,7 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege String cmd = System.getenv("RUST_POST_PROCESS_FILE"); if (StringUtils.isEmpty(cmd)) { cmd = "rustfmt"; - command = new String[]{cmd, "--edition", "2021", fileName}; + command = new String[]{cmd, "--edition", "2024", fileName}; } else { command = new String[]{cmd, fileName}; } @@ -1093,7 +1172,7 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege } @Override - protected void updateParameterForString(CodegenParameter codegenParameter, Schema parameterSchema) { + protected void updateParameterForString(CodegenParameter codegenParameter, final Schema parameterSchema) { if (ModelUtils.isEmailSchema(parameterSchema)) { codegenParameter.isEmail = true; } else if (ModelUtils.isUUIDSchema(parameterSchema)) { @@ -1120,7 +1199,7 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege codegenParameter.isDecimal = true; codegenParameter.isPrimitiveType = true; } - if (Boolean.TRUE.equals(codegenParameter.isString)) { + if (codegenParameter.isString) { codegenParameter.isPrimitiveType = true; } } @@ -1152,6 +1231,16 @@ public class RustAxumServerCodegen extends AbstractRustCodegen implements Codege return null; } + @Override + public String toVarName(String name) { + final var varName = super.toVarName(name); + + if (varName.startsWith("r#")) + return "r_" + varName.substring(2); + + return varName; + } + static class PathMethodOperations { public String path; public ArrayList methodOperations; diff --git a/modules/openapi-generator/src/main/resources/rust-axum/models.mustache b/modules/openapi-generator/src/main/resources/rust-axum/models.mustache index 681d374d85a..6fedb142042 100644 --- a/modules/openapi-generator/src/main/resources/rust-axum/models.mustache +++ b/modules/openapi-generator/src/main/resources/rust-axum/models.mustache @@ -524,7 +524,7 @@ pub fn check_xss_map(v: &std::collections::HashMap) -> std::result /// Enumeration of values. /// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` /// which helps with FFI. -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] @@ -751,17 +751,38 @@ impl std::str::FromStr for {{{classname}}} { {{^arrayModelType}} {{! general struct}} {{#anyOf.size}} -/// Any of: -{{#anyOf}} -/// - {{{.}}} -{{/anyOf}} -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct {{{classname}}}(Box); +{{#discriminator}} +#[derive(Debug, Clone, PartialEq, serde::Deserialize)] +#[serde(tag = "{{{propertyBaseName}}}")] +{{/discriminator}} +{{^discriminator}} +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +{{/discriminator}} +#[allow(non_camel_case_types, clippy::large_enum_variant)] +pub enum {{{classname}}} { + {{#composedSchemas}} + {{#anyOf}} + {{{datatypeWithEnum}}}({{{dataType}}}), + {{/anyOf}} + {{/composedSchemas}} +} impl validator::Validate for {{{classname}}} { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { - std::result::Result::Ok(()) + match self { + {{#composedSchemas}} + {{#anyOf}} + {{^isModel}} + Self::{{{datatypeWithEnum}}}(_) => std::result::Result::Ok(()), + {{/isModel}} + {{#isModel}} + Self::{{{datatypeWithEnum}}}(v) => v.validate(), + {{/isModel}} + {{/anyOf}} + {{/composedSchemas}} + } } } @@ -776,11 +797,32 @@ impl std::str::FromStr for {{{classname}}} { } } -impl PartialEq for {{{classname}}} { - fn eq(&self, other: &Self) -> bool { - self.0.get() == other.0.get() +{{#discriminator}} +impl serde::Serialize for {{{classname}}} { + fn serialize(&self, serializer: S) -> Result + where S: serde::Serializer { + match self { + {{#composedSchemas}} + {{#anyOf}} + Self::{{{datatypeWithEnum}}}(x) => x.serialize(serializer), + {{/anyOf}} + {{/composedSchemas}} + } } } +{{/discriminator}} + +{{#composedSchemas}} +{{#anyOf}} +{{#vendorExtensions.x-from-trait}} +impl From<{{{dataType}}}> for {{{classname}}} { + fn from(value: {{{dataType}}}) -> Self { + Self::{{{datatypeWithEnum}}}(value) + } +} +{{/vendorExtensions.x-from-trait}} +{{/anyOf}} +{{/composedSchemas}} {{/anyOf.size}} {{#oneOf.size}} @@ -792,11 +834,11 @@ impl PartialEq for {{{classname}}} { #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(untagged)] {{/discriminator}} -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] pub enum {{{classname}}} { {{#composedSchemas}} {{#oneOf}} - {{{datatypeWithEnum}}}(Box<{{{dataType}}}>), + {{{datatypeWithEnum}}}({{{dataType}}}), {{/oneOf}} {{/composedSchemas}} } @@ -807,18 +849,29 @@ impl validator::Validate for {{{classname}}} match self { {{#composedSchemas}} {{#oneOf}} - {{#isPrimitiveType}} + {{^isModel}} Self::{{{datatypeWithEnum}}}(_) => std::result::Result::Ok(()), - {{/isPrimitiveType}} - {{^isPrimitiveType}} - Self::{{{datatypeWithEnum}}}(x) => x.validate(), - {{/isPrimitiveType}} + {{/isModel}} + {{#isModel}} + Self::{{{datatypeWithEnum}}}(v) => v.validate(), + {{/isModel}} {{/oneOf}} {{/composedSchemas}} } } } +/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for {{{classname}}} { + type Err = serde_json::Error; + + fn from_str(s: &str) -> std::result::Result { + serde_json::from_str(s) + } +} + {{#discriminator}} impl serde::Serialize for {{{classname}}} { fn serialize(&self, serializer: S) -> Result @@ -834,29 +887,18 @@ impl serde::Serialize for {{{classname}}} { } {{/discriminator}} - - {{#composedSchemas}} {{#oneOf}} +{{#vendorExtensions.x-from-trait}} impl From<{{{dataType}}}> for {{{classname}}} { fn from(value: {{{dataType}}}) -> Self { - Self::{{{datatypeWithEnum}}}(Box::new(value)) + Self::{{{datatypeWithEnum}}}(value) } } +{{/vendorExtensions.x-from-trait}} {{/oneOf}} {{/composedSchemas}} -/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for {{{classname}}} { - type Err = serde_json::Error; - - fn from_str(s: &str) -> std::result::Result { - serde_json::from_str(s) - } -} - {{/oneOf.size}} {{^anyOf.size}} {{^oneOf.size}} @@ -871,8 +913,10 @@ pub struct {{{classname}}} { /// Note: inline enums are not fully supported by openapi-generator {{/isEnum}} {{#isDiscriminator}} +{{#isString}} #[serde(default = "{{{classname}}}::_name_for_{{{name}}}")] #[serde(serialize_with = "{{{classname}}}::_serialize_{{{name}}}")] +{{/isString}} {{/isDiscriminator}} #[serde(rename = "{{{baseName}}}")] {{#hasValidation}} @@ -989,9 +1033,9 @@ pub struct {{{classname}}} { {{/vars}} } - {{#vars}} {{#isDiscriminator}} +{{#isString}} impl {{{classname}}} { fn _name_for_{{{name}}}() -> String { String::from("{{{classname}}}") @@ -1004,10 +1048,10 @@ impl {{{classname}}} { s.serialize_str(&Self::_name_for_{{{name}}}()) } } +{{/isString}} {{/isDiscriminator}} {{/vars}} - {{#vars}} {{#hasValidation}} {{#pattern}} @@ -1035,9 +1079,9 @@ fn validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowerc impl {{{classname}}} { #[allow(clippy::new_without_default, clippy::too_many_arguments)] - pub fn new({{#vars}}{{^defaultValue}}{{{name}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, {{/defaultValue}}{{/vars}}) -> {{{classname}}} { + pub fn new({{#vars}}{{^isDiscriminator}}{{^defaultValue}}{{{name}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, {{/defaultValue}}{{/isDiscriminator}}{{#isDiscriminator}}{{^isString}}{{^defaultValue}}{{{name}}}: {{#isNullable}}Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, {{/defaultValue}}{{/isString}}{{/isDiscriminator}}{{/vars}}) -> {{{classname}}} { {{{classname}}} { -{{#vars}} {{#defaultValue}}{{{name}}}: {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{{name}}}{{/defaultValue}}, +{{#vars}} {{^isDiscriminator}}{{#defaultValue}}{{{name}}}: {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{{name}}}{{/defaultValue}}{{/isDiscriminator}}{{#isDiscriminator}}{{#isString}}{{{name}}}: Self::_name_for_{{{name}}}(){{/isString}}{{^isString}}{{#defaultValue}}{{{name}}}: {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{{name}}}{{/defaultValue}}{{/isString}}{{/isDiscriminator}}, {{/vars}} } } @@ -1075,7 +1119,7 @@ impl std::fmt::Display for {{{classname}}} { {{/isArray}} {{#isArray}} {{#isNullable}} - Some(self.{{{name}}}.as_ref().map_or(vec!["null".to_string()], |x| x.iter().map(|x| x.to_string()).collect::>().join(","))), + Some(self.{{{name}}}.as_ref().map_or("null".to_string(), |x| x.iter().map(|x| x.to_string()).collect::>().join(","))), {{/isNullable}} {{^isNullable}} Some(self.{{{name}}}.iter().map(|x| x.to_string()).collect::>().join(",")), @@ -1226,7 +1270,6 @@ impl std::convert::TryFrom for header::IntoHeaderValue<{{{classname } } } - {{/oneOf.size}} {{/anyOf.size}} diff --git a/samples/server/petstore/rust-axum/output/apikey-authorization/src/models.rs b/samples/server/petstore/rust-axum/output/apikey-authorization/src/models.rs index b20237912cd..5d7b8b641a2 100644 --- a/samples/server/petstore/rust-axum/output/apikey-authorization/src/models.rs +++ b/samples/server/petstore/rust-axum/output/apikey-authorization/src/models.rs @@ -594,7 +594,7 @@ pub struct PaymentMethod { #[serde(rename = "type")] #[validate(custom(function = "check_xss_string"))] #[serde(skip_serializing_if = "Option::is_none")] - pub r#type: Option, + pub r_type: Option, } impl PaymentMethod { @@ -602,7 +602,7 @@ impl PaymentMethod { pub fn new() -> PaymentMethod { PaymentMethod { name: None, - r#type: None, + r_type: None, } } } @@ -616,9 +616,9 @@ impl std::fmt::Display for PaymentMethod { self.name .as_ref() .map(|name| ["name".to_string(), name.to_string()].join(",")), - self.r#type + self.r_type .as_ref() - .map(|r#type| ["type".to_string(), r#type.to_string()].join(",")), + .map(|r_type| ["type".to_string(), r_type.to_string()].join(",")), ]; write!( @@ -641,7 +641,7 @@ impl std::str::FromStr for PaymentMethod { #[allow(dead_code)] struct IntermediateRep { pub name: Vec, - pub r#type: Vec, + pub r_type: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -668,7 +668,7 @@ impl std::str::FromStr for PaymentMethod { ::from_str(val).map_err(|x| x.to_string())?, ), #[allow(clippy::redundant_clone)] - "type" => intermediate_rep.r#type.push( + "type" => intermediate_rep.r_type.push( ::from_str(val).map_err(|x| x.to_string())?, ), _ => { @@ -686,7 +686,7 @@ impl std::str::FromStr for PaymentMethod { // Use the intermediate representation to return the struct std::result::Result::Ok(PaymentMethod { name: intermediate_rep.name.into_iter().next(), - r#type: intermediate_rep.r#type.into_iter().next(), + r_type: intermediate_rep.r_type.into_iter().next(), }) } } diff --git a/samples/server/petstore/rust-axum/output/apikey-auths/src/models.rs b/samples/server/petstore/rust-axum/output/apikey-auths/src/models.rs index b20237912cd..5d7b8b641a2 100644 --- a/samples/server/petstore/rust-axum/output/apikey-auths/src/models.rs +++ b/samples/server/petstore/rust-axum/output/apikey-auths/src/models.rs @@ -594,7 +594,7 @@ pub struct PaymentMethod { #[serde(rename = "type")] #[validate(custom(function = "check_xss_string"))] #[serde(skip_serializing_if = "Option::is_none")] - pub r#type: Option, + pub r_type: Option, } impl PaymentMethod { @@ -602,7 +602,7 @@ impl PaymentMethod { pub fn new() -> PaymentMethod { PaymentMethod { name: None, - r#type: None, + r_type: None, } } } @@ -616,9 +616,9 @@ impl std::fmt::Display for PaymentMethod { self.name .as_ref() .map(|name| ["name".to_string(), name.to_string()].join(",")), - self.r#type + self.r_type .as_ref() - .map(|r#type| ["type".to_string(), r#type.to_string()].join(",")), + .map(|r_type| ["type".to_string(), r_type.to_string()].join(",")), ]; write!( @@ -641,7 +641,7 @@ impl std::str::FromStr for PaymentMethod { #[allow(dead_code)] struct IntermediateRep { pub name: Vec, - pub r#type: Vec, + pub r_type: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -668,7 +668,7 @@ impl std::str::FromStr for PaymentMethod { ::from_str(val).map_err(|x| x.to_string())?, ), #[allow(clippy::redundant_clone)] - "type" => intermediate_rep.r#type.push( + "type" => intermediate_rep.r_type.push( ::from_str(val).map_err(|x| x.to_string())?, ), _ => { @@ -686,7 +686,7 @@ impl std::str::FromStr for PaymentMethod { // Use the intermediate representation to return the struct std::result::Result::Ok(PaymentMethod { name: intermediate_rep.name.into_iter().next(), - r#type: intermediate_rep.r#type.into_iter().next(), + r_type: intermediate_rep.r_type.into_iter().next(), }) } } diff --git a/samples/server/petstore/rust-axum/output/openapi-v3/src/models.rs b/samples/server/petstore/rust-axum/output/openapi-v3/src/models.rs index 4d2fb31b5ab..a02749ce055 100644 --- a/samples/server/petstore/rust-axum/output/openapi-v3/src/models.rs +++ b/samples/server/petstore/rust-axum/output/openapi-v3/src/models.rs @@ -767,15 +767,20 @@ impl std::convert::TryFrom for header::IntoHeaderValue); +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] +pub enum AnyOfGet202Response { + String(String), + Uuid(uuid::Uuid), +} impl validator::Validate for AnyOfGet202Response { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { - std::result::Result::Ok(()) + match self { + Self::String(_) => std::result::Result::Ok(()), + Self::Uuid(_) => std::result::Result::Ok(()), + } } } @@ -790,22 +795,32 @@ impl std::str::FromStr for AnyOfGet202Response { } } -impl PartialEq for AnyOfGet202Response { - fn eq(&self, other: &Self) -> bool { - self.0.get() == other.0.get() +impl From for AnyOfGet202Response { + fn from(value: String) -> Self { + Self::String(value) + } +} +impl From for AnyOfGet202Response { + fn from(value: uuid::Uuid) -> Self { + Self::Uuid(value) } } /// Test a model containing an anyOf of a hash map -/// Any of: -/// - String -/// - std::collections::HashMap -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct AnyOfHashMapObject(Box); +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] +pub enum AnyOfHashMapObject { + String(String), + HashMapOfStringString(std::collections::HashMap), +} impl validator::Validate for AnyOfHashMapObject { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { - std::result::Result::Ok(()) + match self { + Self::String(_) => std::result::Result::Ok(()), + Self::HashMapOfStringString(_) => std::result::Result::Ok(()), + } } } @@ -820,21 +835,32 @@ impl std::str::FromStr for AnyOfHashMapObject { } } -impl PartialEq for AnyOfHashMapObject { - fn eq(&self, other: &Self) -> bool { - self.0.get() == other.0.get() +impl From for AnyOfHashMapObject { + fn from(value: String) -> Self { + Self::String(value) + } +} +impl From> for AnyOfHashMapObject { + fn from(value: std::collections::HashMap) -> Self { + Self::HashMapOfStringString(value) } } /// Test a model containing an anyOf -/// Any of: -/// - String -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct AnyOfObject(Box); +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] +pub enum AnyOfObject { + String(String), + String1(String), +} impl validator::Validate for AnyOfObject { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { - std::result::Result::Ok(()) + match self { + Self::String(_) => std::result::Result::Ok(()), + Self::String1(_) => std::result::Result::Ok(()), + } } } @@ -849,12 +875,6 @@ impl std::str::FromStr for AnyOfObject { } } -impl PartialEq for AnyOfObject { - fn eq(&self, other: &Self) -> bool { - self.0.get() == other.0.get() - } -} - /// Test containing an anyOf object #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] @@ -1166,7 +1186,7 @@ impl std::convert::TryFrom for header::IntoHeaderValue for header::IntoHeaderValue); +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(untagged)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] +pub enum Model12345AnyOfObject { + String(String), + String1(String), +} impl validator::Validate for Model12345AnyOfObject { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { - std::result::Result::Ok(()) + match self { + Self::String(_) => std::result::Result::Ok(()), + Self::String1(_) => std::result::Result::Ok(()), + } } } @@ -1473,12 +1499,6 @@ impl std::str::FromStr for Model12345AnyOfObject { } } -impl PartialEq for Model12345AnyOfObject { - fn eq(&self, other: &Self) -> bool { - self.0.get() == other.0.get() - } -} - #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct MultigetGet201Response { @@ -2319,8 +2339,9 @@ pub struct ObjectParam { pub required_param: bool, #[serde(rename = "optionalParam")] + #[validate(range(min = 1u64, max = 10000000000000000000u64))] #[serde(skip_serializing_if = "Option::is_none")] - pub optional_param: Option, + pub optional_param: Option, } impl ObjectParam { @@ -2366,7 +2387,7 @@ impl std::str::FromStr for ObjectParam { #[allow(dead_code)] struct IntermediateRep { pub required_param: Vec, - pub optional_param: Vec, + pub optional_param: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -2394,7 +2415,7 @@ impl std::str::FromStr for ObjectParam { ), #[allow(clippy::redundant_clone)] "optionalParam" => intermediate_rep.optional_param.push( - ::from_str(val).map_err(|x| x.to_string())?, + ::from_str(val).map_err(|x| x.to_string())?, ), _ => { return std::result::Result::Err( @@ -2813,10 +2834,10 @@ impl std::ops::DerefMut for Ok { #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(untagged)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] pub enum OneOfGet200Response { - I32(Box), - VecOfString(Box>), + I32(i32), + VecOfString(Vec), } impl validator::Validate for OneOfGet200Response { @@ -2828,17 +2849,6 @@ impl validator::Validate for OneOfGet200Response { } } -impl From for OneOfGet200Response { - fn from(value: i32) -> Self { - Self::I32(Box::new(value)) - } -} -impl From> for OneOfGet200Response { - fn from(value: Vec) -> Self { - Self::VecOfString(Box::new(value)) - } -} - /// Converts Query Parameters representation (style=form, explode=false) to a OneOfGet200Response value /// as specified in https://swagger.io/docs/specification/serialization/ /// Should be implemented in a serde deserializer @@ -2850,6 +2860,17 @@ impl std::str::FromStr for OneOfGet200Response { } } +impl From for OneOfGet200Response { + fn from(value: i32) -> Self { + Self::I32(value) + } +} +impl From> for OneOfGet200Response { + fn from(value: Vec) -> Self { + Self::VecOfString(value) + } +} + #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct OptionalObjectHeader(i32); @@ -2971,7 +2992,7 @@ impl std::ops::DerefMut for Result { /// Enumeration of values. /// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` /// which helps with FFI. -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] #[repr(C)] #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, diff --git a/samples/server/petstore/rust-axum/output/openapi-v3/tests/oneof_untagged.rs b/samples/server/petstore/rust-axum/output/openapi-v3/tests/oneof_untagged.rs index 63c04df4913..40d18c33605 100644 --- a/samples/server/petstore/rust-axum/output/openapi-v3/tests/oneof_untagged.rs +++ b/samples/server/petstore/rust-axum/output/openapi-v3/tests/oneof_untagged.rs @@ -12,7 +12,7 @@ fn test_oneof_schema_untagged() { let test2 = r#"{"value": ["foo", "bar"]}"#; let test3 = Test { - value: OneOfGet200Response::I32(123.into()), + value: OneOfGet200Response::I32(123), }; let test4 = Test { value: OneOfGet200Response::VecOfString(vec!["foo".to_string(), "bar".to_string()].into()), diff --git a/samples/server/petstore/rust-axum/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs b/samples/server/petstore/rust-axum/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs index 69f5dda3e2e..bb81873332e 100644 --- a/samples/server/petstore/rust-axum/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs +++ b/samples/server/petstore/rust-axum/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs @@ -349,6 +349,8 @@ impl std::convert::TryFrom for header::IntoHeaderValue, } +impl Animal { + fn _name_for_class_name() -> String { + String::from("Animal") + } + + fn _serialize_class_name(_: &String, s: S) -> Result + where + S: serde::Serializer, + { + s.serialize_str(&Self::_name_for_class_name()) + } +} + impl Animal { #[allow(clippy::new_without_default, clippy::too_many_arguments)] - pub fn new(class_name: String) -> Animal { + pub fn new() -> Animal { Animal { - class_name, + class_name: Self::_name_for_class_name(), color: Some(r#"red"#.to_string()), } } @@ -649,7 +664,7 @@ pub struct ApiResponse { #[serde(rename = "type")] #[validate(custom(function = "check_xss_string"))] #[serde(skip_serializing_if = "Option::is_none")] - pub r#type: Option, + pub r_type: Option, #[serde(rename = "message")] #[validate(custom(function = "check_xss_string"))] @@ -662,7 +677,7 @@ impl ApiResponse { pub fn new() -> ApiResponse { ApiResponse { code: None, - r#type: None, + r_type: None, message: None, } } @@ -677,9 +692,9 @@ impl std::fmt::Display for ApiResponse { self.code .as_ref() .map(|code| ["code".to_string(), code.to_string()].join(",")), - self.r#type + self.r_type .as_ref() - .map(|r#type| ["type".to_string(), r#type.to_string()].join(",")), + .map(|r_type| ["type".to_string(), r_type.to_string()].join(",")), self.message .as_ref() .map(|message| ["message".to_string(), message.to_string()].join(",")), @@ -705,7 +720,7 @@ impl std::str::FromStr for ApiResponse { #[allow(dead_code)] struct IntermediateRep { pub code: Vec, - pub r#type: Vec, + pub r_type: Vec, pub message: Vec, } @@ -733,7 +748,7 @@ impl std::str::FromStr for ApiResponse { ::from_str(val).map_err(|x| x.to_string())?, ), #[allow(clippy::redundant_clone)] - "type" => intermediate_rep.r#type.push( + "type" => intermediate_rep.r_type.push( ::from_str(val).map_err(|x| x.to_string())?, ), #[allow(clippy::redundant_clone)] @@ -755,7 +770,7 @@ impl std::str::FromStr for ApiResponse { // Use the intermediate representation to return the struct std::result::Result::Ok(ApiResponse { code: intermediate_rep.code.into_iter().next(), - r#type: intermediate_rep.r#type.into_iter().next(), + r_type: intermediate_rep.r_type.into_iter().next(), message: intermediate_rep.message.into_iter().next(), }) } @@ -2539,7 +2554,7 @@ impl std::convert::TryFrom for header::IntoHeaderValue /// Enumeration of values. /// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` /// which helps with FFI. -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] #[repr(C)] #[derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, @@ -3337,7 +3352,9 @@ impl std::str::FromStr for List { let val = match string_iter.next() { Some(x) => x, None => { - return std::result::Result::Err("Missing value while parsing List".to_string()); + return std::result::Result::Err( + "Missing value while parsing List".to_string(), + ); } }; @@ -3976,7 +3993,9 @@ impl std::str::FromStr for Name { let val = match string_iter.next() { Some(x) => x, None => { - return std::result::Result::Err("Missing value while parsing Name".to_string()); + return std::result::Result::Err( + "Missing value while parsing Name".to_string(), + ); } }; @@ -4786,7 +4805,7 @@ impl std::convert::TryFrom for header::IntoHeaderValue for header::IntoHeaderValue, + pub r_return: Option, } impl Return { #[allow(clippy::new_without_default, clippy::too_many_arguments)] pub fn new() -> Return { - Return { r#return: None } + Return { r_return: None } } } @@ -5299,9 +5318,9 @@ impl Return { impl std::fmt::Display for Return { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.r#return + self.r_return .as_ref() - .map(|r#return| ["return".to_string(), r#return.to_string()].join(",")), + .map(|r_return| ["return".to_string(), r_return.to_string()].join(",")), ]; write!( @@ -5323,7 +5342,7 @@ impl std::str::FromStr for Return { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub r#return: Vec, + pub r_return: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -5346,7 +5365,7 @@ impl std::str::FromStr for Return { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "return" => intermediate_rep.r#return.push( + "return" => intermediate_rep.r_return.push( ::from_str(val).map_err(|x| x.to_string())?, ), _ => { @@ -5363,7 +5382,7 @@ impl std::str::FromStr for Return { // Use the intermediate representation to return the struct std::result::Result::Ok(Return { - r#return: intermediate_rep.r#return.into_iter().next(), + r_return: intermediate_rep.r_return.into_iter().next(), }) } } @@ -5899,7 +5918,7 @@ impl TestEnumParametersRequest { #[allow(clippy::new_without_default, clippy::too_many_arguments)] pub fn new() -> TestEnumParametersRequest { TestEnumParametersRequest { - enum_form_string: Some(r#"-efg"#.to_string()), + enum_form_string: None, } } } @@ -6611,7 +6630,9 @@ impl std::str::FromStr for User { let val = match string_iter.next() { Some(x) => x, None => { - return std::result::Result::Err("Missing value while parsing User".to_string()); + return std::result::Result::Err( + "Missing value while parsing User".to_string(), + ); } }; diff --git a/samples/server/petstore/rust-axum/output/petstore/src/models.rs b/samples/server/petstore/rust-axum/output/petstore/src/models.rs index 107ff2617b5..9db0d59cbfa 100644 --- a/samples/server/petstore/rust-axum/output/petstore/src/models.rs +++ b/samples/server/petstore/rust-axum/output/petstore/src/models.rs @@ -177,7 +177,7 @@ pub struct ApiResponse { #[serde(rename = "type")] #[validate(custom(function = "check_xss_string"))] #[serde(skip_serializing_if = "Option::is_none")] - pub r#type: Option, + pub r_type: Option, #[serde(rename = "message")] #[validate(custom(function = "check_xss_string"))] @@ -190,7 +190,7 @@ impl ApiResponse { pub fn new() -> ApiResponse { ApiResponse { code: None, - r#type: None, + r_type: None, message: None, } } @@ -205,9 +205,9 @@ impl std::fmt::Display for ApiResponse { self.code .as_ref() .map(|code| ["code".to_string(), code.to_string()].join(",")), - self.r#type + self.r_type .as_ref() - .map(|r#type| ["type".to_string(), r#type.to_string()].join(",")), + .map(|r_type| ["type".to_string(), r_type.to_string()].join(",")), self.message .as_ref() .map(|message| ["message".to_string(), message.to_string()].join(",")), @@ -233,7 +233,7 @@ impl std::str::FromStr for ApiResponse { #[allow(dead_code)] struct IntermediateRep { pub code: Vec, - pub r#type: Vec, + pub r_type: Vec, pub message: Vec, } @@ -261,7 +261,7 @@ impl std::str::FromStr for ApiResponse { ::from_str(val).map_err(|x| x.to_string())?, ), #[allow(clippy::redundant_clone)] - "type" => intermediate_rep.r#type.push( + "type" => intermediate_rep.r_type.push( ::from_str(val).map_err(|x| x.to_string())?, ), #[allow(clippy::redundant_clone)] @@ -283,7 +283,7 @@ impl std::str::FromStr for ApiResponse { // Use the intermediate representation to return the struct std::result::Result::Ok(ApiResponse { code: intermediate_rep.code.into_iter().next(), - r#type: intermediate_rep.r#type.into_iter().next(), + r_type: intermediate_rep.r_type.into_iter().next(), message: intermediate_rep.message.into_iter().next(), }) } @@ -1491,7 +1491,9 @@ impl std::str::FromStr for User { let val = match string_iter.next() { Some(x) => x, None => { - return std::result::Result::Err("Missing value while parsing User".to_string()); + return std::result::Result::Err( + "Missing value while parsing User".to_string(), + ); } }; diff --git a/samples/server/petstore/rust-axum/output/rust-axum-oneof/src/models.rs b/samples/server/petstore/rust-axum/output/rust-axum-oneof/src/models.rs index dbf993dae26..44ad498d4e2 100644 --- a/samples/server/petstore/rust-axum/output/rust-axum-oneof/src/models.rs +++ b/samples/server/petstore/rust-axum/output/rust-axum-oneof/src/models.rs @@ -91,8 +91,11 @@ impl Goodbye { impl Goodbye { #[allow(clippy::new_without_default, clippy::too_many_arguments)] - pub fn new(op: String, d: models::GoodbyeD) -> Goodbye { - Goodbye { op, d } + pub fn new(d: models::GoodbyeD) -> Goodbye { + Goodbye { + op: Self::_name_for_op(), + d, + } } } @@ -394,7 +397,7 @@ impl Greeting { pub fn new(d: models::GreetingD) -> Greeting { Greeting { d, - op: r#"Greeting"#.to_string(), + op: Self::_name_for_op(), } } } @@ -698,7 +701,7 @@ impl Hello { #[allow(clippy::new_without_default, clippy::too_many_arguments)] pub fn new(d: models::HelloD) -> Hello { Hello { - op: r#"Hello"#.to_string(), + op: Self::_name_for_op(), d, } } @@ -971,25 +974,36 @@ impl std::convert::TryFrom for header::IntoHeaderValue { #[derive(Debug, Clone, PartialEq, serde::Deserialize)] #[serde(tag = "op")] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] pub enum Message { - Hello(Box), - Greeting(Box), - Goodbye(Box), - SomethingCompletelyDifferent(Box), + Hello(models::Hello), + Greeting(models::Greeting), + Goodbye(models::Goodbye), + SomethingCompletelyDifferent(models::SomethingCompletelyDifferent), } impl validator::Validate for Message { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { match self { - Self::Hello(x) => x.validate(), - Self::Greeting(x) => x.validate(), - Self::Goodbye(x) => x.validate(), - Self::SomethingCompletelyDifferent(x) => x.validate(), + Self::Hello(v) => v.validate(), + Self::Greeting(v) => v.validate(), + Self::Goodbye(v) => v.validate(), + Self::SomethingCompletelyDifferent(v) => v.validate(), } } } +/// Converts Query Parameters representation (style=form, explode=false) to a Message value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for Message { + type Err = serde_json::Error; + + fn from_str(s: &str) -> std::result::Result { + serde_json::from_str(s) + } +} + impl serde::Serialize for Message { fn serialize(&self, serializer: S) -> Result where @@ -1006,64 +1020,42 @@ impl serde::Serialize for Message { impl From for Message { fn from(value: models::Hello) -> Self { - Self::Hello(Box::new(value)) + Self::Hello(value) } } impl From for Message { fn from(value: models::Greeting) -> Self { - Self::Greeting(Box::new(value)) + Self::Greeting(value) } } impl From for Message { fn from(value: models::Goodbye) -> Self { - Self::Goodbye(Box::new(value)) + Self::Goodbye(value) } } impl From for Message { fn from(value: models::SomethingCompletelyDifferent) -> Self { - Self::SomethingCompletelyDifferent(Box::new(value)) - } -} - -/// Converts Query Parameters representation (style=form, explode=false) to a Message value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for Message { - type Err = serde_json::Error; - - fn from_str(s: &str) -> std::result::Result { - serde_json::from_str(s) + Self::SomethingCompletelyDifferent(value) } } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(untagged)] -#[allow(non_camel_case_types)] +#[allow(non_camel_case_types, clippy::large_enum_variant)] pub enum SomethingCompletelyDifferent { - VecOfObject(Box>), - Object(Box), + VecOfObject(Vec), + Object(crate::types::Object), } impl validator::Validate for SomethingCompletelyDifferent { fn validate(&self) -> std::result::Result<(), validator::ValidationErrors> { match self { Self::VecOfObject(_) => std::result::Result::Ok(()), - Self::Object(x) => x.validate(), + Self::Object(_) => std::result::Result::Ok(()), } } } -impl From> for SomethingCompletelyDifferent { - fn from(value: Vec) -> Self { - Self::VecOfObject(Box::new(value)) - } -} -impl From for SomethingCompletelyDifferent { - fn from(value: crate::types::Object) -> Self { - Self::Object(Box::new(value)) - } -} - /// Converts Query Parameters representation (style=form, explode=false) to a SomethingCompletelyDifferent value /// as specified in https://swagger.io/docs/specification/serialization/ /// Should be implemented in a serde deserializer @@ -1074,3 +1066,14 @@ impl std::str::FromStr for SomethingCompletelyDifferent { serde_json::from_str(s) } } + +impl From> for SomethingCompletelyDifferent { + fn from(value: Vec) -> Self { + Self::VecOfObject(value) + } +} +impl From for SomethingCompletelyDifferent { + fn from(value: crate::types::Object) -> Self { + Self::Object(value) + } +}