From d03c90cb976a6df012920cdbb4edefa45039d248 Mon Sep 17 00:00:00 2001 From: Richard Whitehouse Date: Wed, 18 Sep 2024 08:25:06 +0100 Subject: [PATCH] [Rust Server] Handle additional properties being nullable (#19594) With: ``` sampleObject: type: object additionalProperties: $ref: '#/components/schemas/SampleData' minProperties: 1 description: Map of Charging data policy decisions. ``` and ``` SampleData: type: object ... nullable: true ``` We currently generate: HashMap, which doesn't allow null charging data entries. This MR changes this to be `HashMap>`, which thus will allow null data entries. We do this by moving null-handling to the Java code - primarily `getTypeDeclaration()`. Note, to some extent this is wrong. In this MR (and previously) we are treating `nullable: true` as an extrinsic property (like required), whereas it should be an intrinsic property (and thus `HashMap` is correct, but `SampleData` absorbs the nullability. This would be possible with this code: ``` enum ChargingData = { Null, Present { ... } } ``` Which would remove the usage of https://docs.rs/swagger/2.0.2/swagger/nullable_format/enum.Nullable.html. I haven't resolved this - and have instead done a more targeted fix. This, along with some other crude code, creates a scenario where we need to unpick whether something is null. I've left that, though flagged a TODO to tidy it up at some point. --- .../codegen/languages/RustServerCodegen.java | 56 ++- .../resources/rust-server/models.mustache | 24 +- .../resources/3_0/rust-server/openapi-v3.yaml | 12 + .../output/multipart-v3/src/models.rs | 23 +- .../output/no-example-v3/src/models.rs | 2 - .../openapi-v3/.openapi-generator/FILES | 2 + .../rust-server/output/openapi-v3/README.md | 2 + .../output/openapi-v3/api/openapi.yaml | 13 + .../docs/AdditionalPropertiesWithNullable.md | 11 + .../output/openapi-v3/docs/NullableObject.md | 9 + .../output/openapi-v3/docs/NullableTest.md | 10 +- .../openapi-v3/docs/ObjectUntypedProps.md | 2 +- .../output/openapi-v3/src/models.rs | 390 +++++++++++++++--- .../src/models.rs | 230 ++--------- .../docs/ANullableContainer.md | 4 +- .../output/rust-server-test/src/models.rs | 27 +- 16 files changed, 485 insertions(+), 332 deletions(-) create mode 100644 samples/server/petstore/rust-server/output/openapi-v3/docs/AdditionalPropertiesWithNullable.md create mode 100644 samples/server/petstore/rust-server/output/openapi-v3/docs/NullableObject.md diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java index f0ddc5ca49a..7cef6659b77 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java @@ -1063,39 +1063,48 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon public String getTypeDeclaration(Schema p) { LOGGER.trace("Getting type declaration for schema"); + String type; + if (ModelUtils.isArraySchema(p)) { ArraySchema ap = (ArraySchema) p; Schema inner = ap.getItems(); String innerType = getTypeDeclaration(inner); - return typeMapping.get("array") + "<" + innerType + ">"; + type = typeMapping.get("array") + "<" + innerType + ">"; } else if (ModelUtils.isMapSchema(p)) { Schema inner = ModelUtils.getAdditionalProperties(p); String innerType = getTypeDeclaration(inner); StringBuilder typeDeclaration = new StringBuilder(typeMapping.get("map")).append("<").append(typeMapping.get("string")).append(", "); typeDeclaration.append(innerType).append(">"); - return typeDeclaration.toString(); + type = typeDeclaration.toString(); } else if (!StringUtils.isEmpty(p.get$ref())) { - String dataType; try { - dataType = modelFromSchema(p); + type = modelFromSchema(p); - if (dataType != null) { - dataType = "models::" + dataType; - LOGGER.debug("Returning " + dataType + " from ref"); + if (type != null) { + type = "models::" + type; + LOGGER.debug("Returning " + type + " from ref"); } } catch (Exception e) { - dataType = null; + type = null; LOGGER.error("Error obtaining the datatype from schema (model): " + p + ". Error was: " + e.getMessage(), e); } - - LOGGER.debug("Returning " + dataType); - - return dataType; } else if (p instanceof FileSchema) { - return typeMapping.get("File").toString(); + type = typeMapping.get("File").toString(); + } else { + type = super.getTypeDeclaration(p); } - return super.getTypeDeclaration(p); + // We are using extrinsic nullability, rather than intrinsic, so we need to dig into the inner + // layer of the referenced schema. + Schema rp = ModelUtils.getReferencedSchema(openAPI, p); + + if (rp.getNullable() == Boolean.TRUE) { + type = "swagger::Nullable<" + type + ">"; + } + + LOGGER.debug("Returning " + type + " for type declaration"); + + return type; } @Override @@ -1400,6 +1409,19 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon return "swagger::AnyOf" + types.size() + "<" + String.join(",", types) + ">"; } + /** + * Strip a swagger::Nullable wrapper on a datatype + * + * @deprecated Avoid using this - use a different mechanism instead. + */ + private static String stripNullable(String type) { + if (type.startsWith("swagger::Nullable<") && type.endsWith(">")) { + return type.substring("swagger::Nullable<".length(), type.length() - 1); + } else { + return type; + } + } + @Override public String toAllOfName(List names, Schema composedSchema) { // Handle all of objects as freeform @@ -1409,7 +1431,9 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon @Override public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { super.postProcessModelProperty(model, property); - if (!languageSpecificPrimitives.contains(property.dataType)) { + + // TODO: We should avoid reverse engineering primitive type status from the data type + if (!languageSpecificPrimitives.contains(stripNullable(property.dataType))) { // If we use a more qualified model name, then only camelize the actual type, not the qualifier. if (property.dataType.contains(":")) { int position = property.dataType.lastIndexOf(":"); @@ -1417,7 +1441,7 @@ public class RustServerCodegen extends AbstractRustCodegen implements CodegenCon } else { property.dataType = camelize(property.dataType); } - property.isPrimitiveType = property.isContainer && languageSpecificPrimitives.contains(typeMapping.get(property.complexType)); + property.isPrimitiveType = property.isContainer && languageSpecificPrimitives.contains(typeMapping.get(stripNullable(property.complexType))); } else { property.isPrimitiveType = true; } diff --git a/modules/openapi-generator/src/main/resources/rust-server/models.mustache b/modules/openapi-generator/src/main/resources/rust-server/models.mustache index 4038fd17fd7..9cdd4a1a580 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/models.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/models.mustache @@ -332,7 +332,7 @@ pub struct {{{classname}}} { )] {{/hasValidation}} {{#required}} - pub {{{name}}}: {{#isNullable}}swagger::Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, + pub {{{name}}}: {{{dataType}}}, {{/required}} {{^required}} {{#isNullable}} @@ -340,7 +340,7 @@ pub struct {{{classname}}} { #[serde(default = "swagger::nullable_format::default_optional_nullable")] {{/isNullable}} #[serde(skip_serializing_if="Option::is_none")] - pub {{{name}}}: Option<{{#isNullable}}swagger::Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}>, + pub {{{name}}}: Option<{{{dataType}}}>, {{/required}} {{/vars}} @@ -373,7 +373,7 @@ fn validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowerc impl {{{classname}}} { #[allow(clippy::new_without_default)] - pub fn new({{#vars}}{{^defaultValue}}{{{name}}}: {{#isNullable}}swagger::Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, {{/defaultValue}}{{/vars}}) -> {{{classname}}} { + pub fn new({{#vars}}{{^defaultValue}}{{{name}}}: {{{dataType}}}, {{/defaultValue}}{{/vars}}) -> {{{classname}}} { {{{classname}}} { {{#vars}} {{#defaultValue}}{{{name}}}: {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{{name}}}{{/defaultValue}}, {{/vars}} @@ -389,18 +389,21 @@ impl std::string::ToString for {{{classname}}} { let params: Vec> = vec![ {{#vars}} {{#isByteArray}} - // Skipping {{baseName}} in query parameter serialization + // Skipping byte array {{baseName}} in query parameter serialization {{/isByteArray}} +{{^isByteArray}} {{#isBinary}} - // Skipping {{baseName}} in query parameter serialization + // Skipping binary data {{baseName}} in query parameter serialization {{/isBinary}} +{{^isBinary}} {{#isMap}} - // Skipping {{baseName}} in query parameter serialization + // Skipping map {{baseName}} in query parameter serialization {{/isMap}} +{{^isMap}} {{^isPrimitiveType}} - // Skipping {{baseName}} in query parameter serialization + // Skipping non-primitive type {{baseName}} in query parameter serialization {{/isPrimitiveType}} -{{^isByteArray}}{{^isBinary}}{{^isMap}}{{#isPrimitiveType}} +{{#isPrimitiveType}} {{#required}} Some("{{{baseName}}}".to_string()), {{^isArray}} @@ -443,7 +446,10 @@ impl std::string::ToString for {{{classname}}} { ].join(",") }), {{/required}} -{{/isPrimitiveType}}{{/isMap}}{{/isBinary}}{{/isByteArray}} +{{/isPrimitiveType}} +{{/isMap}} +{{/isBinary}} +{{/isByteArray}} {{/vars}} ]; diff --git a/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml b/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml index c39cc89c6e0..21e29a5eee6 100644 --- a/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/rust-server/openapi-v3.yaml @@ -669,6 +669,15 @@ components: type: boolean OptionalObjectHeader: type: integer + AdditionalPropertiesWithNullable: + type: object + properties: + nullableString: + $ref: '#/components/schemas/NullableObject' + nullableMap: + type: object + additionalProperties: + $ref: '#/components/schemas/NullableObject' AdditionalPropertiesWithList: type: object maxProperties: 1 @@ -676,6 +685,9 @@ components: type: list items: type: string + NullableObject: + type: string + nullable: true NullableTest: type: object required: diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs index 690641e4c55..e4d230e6faf 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs @@ -40,14 +40,9 @@ impl MultipartRelatedRequest { impl std::string::ToString for MultipartRelatedRequest { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping object_field in query parameter serialization - - // Skipping optional_binary_field in query parameter serialization - // Skipping optional_binary_field in query parameter serialization - - // Skipping required_binary_field in query parameter serialization - // Skipping required_binary_field in query parameter serialization - + // Skipping non-primitive type object_field in query parameter serialization + // Skipping binary data optional_binary_field in query parameter serialization + // Skipping binary data required_binary_field in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -219,18 +214,14 @@ impl MultipartRequestObjectField { impl std::string::ToString for MultipartRequestObjectField { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("field_a".to_string()), Some(self.field_a.to_string()), - - self.field_b.as_ref().map(|field_b| { [ "field_b".to_string(), field_b.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -400,12 +391,8 @@ impl MultipleIdenticalMimeTypesPostRequest { impl std::string::ToString for MultipleIdenticalMimeTypesPostRequest { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping binary1 in query parameter serialization - // Skipping binary1 in query parameter serialization - - // Skipping binary2 in query parameter serialization - // Skipping binary2 in query parameter serialization - + // Skipping binary data binary1 in query parameter serialization + // Skipping binary data binary2 in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs index 31b5358ab60..6d87b86882f 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs @@ -30,10 +30,8 @@ impl OpGetRequest { impl std::string::ToString for OpGetRequest { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("property".to_string()), Some(self.property.to_string()), - ]; params.into_iter().flatten().collect::>().join(",") diff --git a/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES index 6ee53f334fd..5dac0fd77f4 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES @@ -5,6 +5,7 @@ README.md api/openapi.yaml bin/cli.rs docs/AdditionalPropertiesWithList.md +docs/AdditionalPropertiesWithNullable.md docs/AnotherXmlArray.md docs/AnotherXmlInner.md docs/AnotherXmlObject.md @@ -22,6 +23,7 @@ docs/Model12345AnyOfObjectAnyOf.md docs/MultigetGet201Response.md docs/MyId.md docs/MyIdList.md +docs/NullableObject.md docs/NullableTest.md docs/ObjectHeader.md docs/ObjectParam.md diff --git a/samples/server/petstore/rust-server/output/openapi-v3/README.md b/samples/server/petstore/rust-server/output/openapi-v3/README.md index c0305f46e1a..596f41f0212 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/README.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/README.md @@ -183,6 +183,7 @@ Method | HTTP request | Description ## Documentation For Models - [AdditionalPropertiesWithList](docs/AdditionalPropertiesWithList.md) + - [AdditionalPropertiesWithNullable](docs/AdditionalPropertiesWithNullable.md) - [AnotherXmlArray](docs/AnotherXmlArray.md) - [AnotherXmlInner](docs/AnotherXmlInner.md) - [AnotherXmlObject](docs/AnotherXmlObject.md) @@ -200,6 +201,7 @@ Method | HTTP request | Description - [MultigetGet201Response](docs/MultigetGet201Response.md) - [MyId](docs/MyId.md) - [MyIdList](docs/MyIdList.md) + - [NullableObject](docs/NullableObject.md) - [NullableTest](docs/NullableTest.md) - [ObjectHeader](docs/ObjectHeader.md) - [ObjectParam](docs/ObjectParam.md) diff --git a/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml b/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml index 330d38b163c..d817a8a8922 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml @@ -687,6 +687,16 @@ components: type: boolean OptionalObjectHeader: type: integer + AdditionalPropertiesWithNullable: + properties: + nullableString: + nullable: true + type: string + nullableMap: + additionalProperties: + $ref: '#/components/schemas/NullableObject' + type: object + type: object AdditionalPropertiesWithList: additionalProperties: items: @@ -694,6 +704,9 @@ components: type: array maxProperties: 1 type: object + NullableObject: + nullable: true + type: string NullableTest: properties: nullable: diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/AdditionalPropertiesWithNullable.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/AdditionalPropertiesWithNullable.md new file mode 100644 index 00000000000..100a70bb572 --- /dev/null +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/AdditionalPropertiesWithNullable.md @@ -0,0 +1,11 @@ +# AdditionalPropertiesWithNullable + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**nullable_string** | **swagger::Nullable** | | [optional] [default to None] +**nullable_map** | **std::collections::HashMap>** | | [optional] [default to None] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableObject.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableObject.md new file mode 100644 index 00000000000..8ec9beb9419 --- /dev/null +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableObject.md @@ -0,0 +1,9 @@ +# NullableObject + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md index 2512b338a5b..be0cda4a1e9 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md @@ -3,11 +3,11 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**nullable** | **String** | | -**nullable_with_null_default** | **String** | | [optional] [default to None] -**nullable_with_present_default** | **String** | | [optional] [default to Some(swagger::Nullable::Present("default".to_string()))] -**nullable_with_no_default** | **String** | | [optional] [default to None] -**nullable_array** | **Vec** | | [optional] [default to None] +**nullable** | **swagger::Nullable** | | +**nullable_with_null_default** | **swagger::Nullable** | | [optional] [default to None] +**nullable_with_present_default** | **swagger::Nullable** | | [optional] [default to Some(swagger::Nullable::Present("default".to_string()))] +**nullable_with_no_default** | **swagger::Nullable** | | [optional] [default to None] +**nullable_array** | **swagger::Nullable>** | | [optional] [default to None] **min_item_test** | **Vec** | | [optional] [default to None] **max_item_test** | **Vec** | | [optional] [default to None] **min_max_item_test** | **Vec** | | [optional] [default to None] diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md index 492045cab7c..1b668dec84f 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **required_untyped** | [***serde_json::Value**](.md) | | -**required_untyped_nullable** | [***serde_json::Value**](.md) | | +**required_untyped_nullable** | [***swagger::Nullable**](.md) | | **not_required_untyped** | [***serde_json::Value**](.md) | | [optional] [default to None] **not_required_untyped_nullable** | [***serde_json::Value**](.md) | | [optional] [default to None] diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs index 8078b1407e5..43128849de4 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs @@ -149,6 +149,192 @@ impl AdditionalPropertiesWithList { } } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct AdditionalPropertiesWithNullable { + #[serde(rename = "nullableString")] + #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] + #[serde(default = "swagger::nullable_format::default_optional_nullable")] + #[serde(skip_serializing_if="Option::is_none")] + pub nullable_string: Option>, + + #[serde(rename = "nullableMap")] + #[serde(skip_serializing_if="Option::is_none")] + pub nullable_map: Option>>, + +} + + +impl AdditionalPropertiesWithNullable { + #[allow(clippy::new_without_default)] + pub fn new() -> AdditionalPropertiesWithNullable { + AdditionalPropertiesWithNullable { + nullable_string: None, + nullable_map: None, + } + } +} + +/// Converts the AdditionalPropertiesWithNullable value to the Query Parameters representation (style=form, explode=false) +/// specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde serializer +impl std::string::ToString for AdditionalPropertiesWithNullable { + fn to_string(&self) -> String { + let params: Vec> = vec![ + self.nullable_string.as_ref().map(|nullable_string| { + [ + "nullableString".to_string(), + nullable_string.as_ref().map_or("null".to_string(), |x| x.to_string()), + ].join(",") + }), + // Skipping map nullableMap in query parameter serialization + ]; + + params.into_iter().flatten().collect::>().join(",") + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a AdditionalPropertiesWithNullable value +/// as specified in https://swagger.io/docs/specification/serialization/ +/// Should be implemented in a serde deserializer +impl std::str::FromStr for AdditionalPropertiesWithNullable { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub nullable_string: Vec>, + pub nullable_map: Vec>>, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing AdditionalPropertiesWithNullable".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + "nullableString" => return std::result::Result::Err("Parsing a nullable type in this style is not supported in AdditionalPropertiesWithNullable".to_string()), + "nullableMap" => return std::result::Result::Err("Parsing a container in this style is not supported in AdditionalPropertiesWithNullable".to_string()), + _ => return std::result::Result::Err("Unexpected key while parsing AdditionalPropertiesWithNullable".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(AdditionalPropertiesWithNullable { + nullable_string: std::result::Result::Err("Nullable types not supported in AdditionalPropertiesWithNullable".to_string())?, + nullable_map: intermediate_rep.nullable_map.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AdditionalPropertiesWithNullable - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into AdditionalPropertiesWithNullable - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + +#[cfg(feature = "server")] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {:?} into a header - {}", + hdr_values, e)) + } + } +} + +#[cfg(feature = "server")] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into AdditionalPropertiesWithNullable - {}", + hdr_value, err)) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {:?} as a string - {}", + hdr_values, e)), + } + } +} + +impl AdditionalPropertiesWithNullable { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + // Utility function for wrapping list elements when serializing xml #[allow(non_snake_case)] fn wrap_in_snake_another_xml_inner(item: &Vec, serializer: S) -> std::result::Result @@ -505,14 +691,12 @@ impl AnotherXmlObject { impl std::string::ToString for AnotherXmlObject { fn to_string(&self) -> String { let params: Vec> = vec![ - self.inner_string.as_ref().map(|inner_string| { [ "inner_string".to_string(), inner_string.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -1256,10 +1440,8 @@ impl AnyOfProperty { impl std::string::ToString for AnyOfProperty { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping requiredAnyOf in query parameter serialization - - // Skipping optionalAnyOf in query parameter serialization - + // Skipping non-primitive type requiredAnyOf in query parameter serialization + // Skipping non-primitive type optionalAnyOf in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -1441,16 +1623,13 @@ impl DuplicateXmlObject { impl std::string::ToString for DuplicateXmlObject { fn to_string(&self) -> String { let params: Vec> = vec![ - self.inner_string.as_ref().map(|inner_string| { [ "inner_string".to_string(), inner_string.to_string(), ].join(",") }), - - // Skipping inner_array in query parameter serialization - + // Skipping non-primitive type inner_array in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -2313,14 +2492,12 @@ impl MultigetGet201Response { impl std::string::ToString for MultigetGet201Response { fn to_string(&self) -> String { let params: Vec> = vec![ - self.foo.as_ref().map(|foo| { [ "foo".to_string(), foo.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2794,6 +2971,141 @@ impl MyIdList { } } +#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct NullableObject(String); + +impl std::convert::From for NullableObject { + fn from(x: String) -> Self { + NullableObject(x) + } +} + +impl std::convert::From for String { + fn from(x: NullableObject) -> Self { + x.0 + } +} + +impl std::ops::Deref for NullableObject { + type Target = String; + fn deref(&self) -> &String { + &self.0 + } +} + +impl std::ops::DerefMut for NullableObject { + fn deref_mut(&mut self) -> &mut String { + &mut self.0 + } +} + +impl std::string::ToString for NullableObject { + fn to_string(&self) -> String { + self.0.clone() + } +} + +impl std::str::FromStr for NullableObject { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(NullableObject(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for NullableObject - value: {} is invalid {}", + hdr_value, e)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into NullableObject - {}", + value, err)) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {:?} to string: {}", + hdr_value, e)) + } + } +} + +#[cfg(feature = "server")] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {:?} into a header - {}", + hdr_values, e)) + } + } +} + +#[cfg(feature = "server")] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{}' into NullableObject - {}", + hdr_value, err)) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {:?} as a string - {}", + hdr_values, e)), + } + } +} + +impl NullableObject { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct NullableTest { @@ -2870,66 +3182,50 @@ impl NullableTest { impl std::string::ToString for NullableTest { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("nullable".to_string()), Some(self.nullable.as_ref().map_or("null".to_string(), |x| x.to_string())), - - self.nullable_with_null_default.as_ref().map(|nullable_with_null_default| { [ "nullableWithNullDefault".to_string(), nullable_with_null_default.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - self.nullable_with_present_default.as_ref().map(|nullable_with_present_default| { [ "nullableWithPresentDefault".to_string(), nullable_with_present_default.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - self.nullable_with_no_default.as_ref().map(|nullable_with_no_default| { [ "nullableWithNoDefault".to_string(), nullable_with_no_default.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - self.nullable_array.as_ref().map(|nullable_array| { [ "nullableArray".to_string(), nullable_array.as_ref().map_or("null".to_string(), |x| x.iter().map(|x| x.to_string()).collect::>().join(",")), ].join(",") }), - - self.min_item_test.as_ref().map(|min_item_test| { [ "min_item_test".to_string(), min_item_test.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - - self.max_item_test.as_ref().map(|max_item_test| { [ "max_item_test".to_string(), max_item_test.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - - self.min_max_item_test.as_ref().map(|min_max_item_test| { [ "min_max_item_test".to_string(), min_max_item_test.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2947,11 +3243,11 @@ impl std::str::FromStr for NullableTest { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub nullable: Vec, - pub nullable_with_null_default: Vec, - pub nullable_with_present_default: Vec, - pub nullable_with_no_default: Vec, - pub nullable_array: Vec>, + pub nullable: Vec>, + pub nullable_with_null_default: Vec>, + pub nullable_with_present_default: Vec>, + pub nullable_with_no_default: Vec>, + pub nullable_array: Vec>>, pub min_item_test: Vec>, pub max_item_test: Vec>, pub min_max_item_test: Vec>, @@ -3124,18 +3420,14 @@ impl ObjectHeader { impl std::string::ToString for ObjectHeader { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("requiredObjectHeader".to_string()), Some(self.required_object_header.to_string()), - - self.optional_object_header.as_ref().map(|optional_object_header| { [ "optionalObjectHeader".to_string(), optional_object_header.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -3314,18 +3606,14 @@ impl ObjectParam { impl std::string::ToString for ObjectParam { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("requiredParam".to_string()), Some(self.required_param.to_string()), - - self.optional_param.as_ref().map(|optional_param| { [ "optionalParam".to_string(), optional_param.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -3513,14 +3801,10 @@ impl ObjectUntypedProps { impl std::string::ToString for ObjectUntypedProps { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping required_untyped in query parameter serialization - - // Skipping required_untyped_nullable in query parameter serialization - - // Skipping not_required_untyped in query parameter serialization - - // Skipping not_required_untyped_nullable in query parameter serialization - + // Skipping non-primitive type required_untyped in query parameter serialization + // Skipping non-primitive type required_untyped_nullable in query parameter serialization + // Skipping non-primitive type not_required_untyped in query parameter serialization + // Skipping non-primitive type not_required_untyped_nullable in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -3539,7 +3823,7 @@ impl std::str::FromStr for ObjectUntypedProps { #[allow(dead_code)] struct IntermediateRep { pub required_untyped: Vec, - pub required_untyped_nullable: Vec, + pub required_untyped_nullable: Vec>, pub not_required_untyped: Vec, pub not_required_untyped_nullable: Vec, } @@ -3702,14 +3986,12 @@ impl ObjectWithArrayOfObjects { impl std::string::ToString for ObjectWithArrayOfObjects { fn to_string(&self) -> String { let params: Vec> = vec![ - self.object_array.as_ref().map(|object_array| { [ "objectArray".to_string(), object_array.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -5327,22 +5609,18 @@ impl XmlObject { impl std::string::ToString for XmlObject { fn to_string(&self) -> String { let params: Vec> = vec![ - self.inner_string.as_ref().map(|inner_string| { [ "innerString".to_string(), inner_string.to_string(), ].join(",") }), - - self.other_inner_rename.as_ref().map(|other_inner_rename| { [ "other_inner_rename".to_string(), other_inner_rename.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs index 38da8cfdfd4..0be12ebcc51 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs @@ -36,11 +36,8 @@ impl AdditionalPropertiesClass { impl std::string::ToString for AdditionalPropertiesClass { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping map_property in query parameter serialization - - // Skipping map_of_map_property in query parameter serialization - // Skipping map_of_map_property in query parameter serialization - + // Skipping map map_property in query parameter serialization + // Skipping map map_of_map_property in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -217,18 +214,14 @@ impl Animal { impl std::string::ToString for Animal { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("className".to_string()), Some(self.class_name.to_string()), - - self.color.as_ref().map(|color| { [ "color".to_string(), color.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -596,30 +589,24 @@ impl ApiResponse { impl std::string::ToString for ApiResponse { fn to_string(&self) -> String { let params: Vec> = vec![ - self.code.as_ref().map(|code| { [ "code".to_string(), code.to_string(), ].join(",") }), - - self.r#type.as_ref().map(|r#type| { [ "type".to_string(), r#type.to_string(), ].join(",") }), - - self.message.as_ref().map(|message| { [ "message".to_string(), message.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -798,8 +785,7 @@ impl ArrayOfArrayOfNumberOnly { impl std::string::ToString for ArrayOfArrayOfNumberOnly { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping ArrayArrayNumber in query parameter serialization - + // Skipping non-primitive type ArrayArrayNumber in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -969,14 +955,12 @@ impl ArrayOfNumberOnly { impl std::string::ToString for ArrayOfNumberOnly { fn to_string(&self) -> String { let params: Vec> = vec![ - self.array_number.as_ref().map(|array_number| { [ "ArrayNumber".to_string(), array_number.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -1161,20 +1145,15 @@ impl ArrayTest { impl std::string::ToString for ArrayTest { fn to_string(&self) -> String { let params: Vec> = vec![ - self.array_of_string.as_ref().map(|array_of_string| { [ "array_of_string".to_string(), array_of_string.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - - // Skipping array_array_of_integer in query parameter serialization - - // Skipping array_array_of_model in query parameter serialization - - // Skipping array_of_enum in query parameter serialization - + // Skipping non-primitive type array_array_of_integer in query parameter serialization + // Skipping non-primitive type array_array_of_model in query parameter serialization + // Skipping non-primitive type array_of_enum in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -1379,54 +1358,42 @@ impl Capitalization { impl std::string::ToString for Capitalization { fn to_string(&self) -> String { let params: Vec> = vec![ - self.small_camel.as_ref().map(|small_camel| { [ "smallCamel".to_string(), small_camel.to_string(), ].join(",") }), - - self.capital_camel.as_ref().map(|capital_camel| { [ "CapitalCamel".to_string(), capital_camel.to_string(), ].join(",") }), - - self.small_snake.as_ref().map(|small_snake| { [ "small_Snake".to_string(), small_snake.to_string(), ].join(",") }), - - self.capital_snake.as_ref().map(|capital_snake| { [ "Capital_Snake".to_string(), capital_snake.to_string(), ].join(",") }), - - self.sca_eth_flow_points.as_ref().map(|sca_eth_flow_points| { [ "SCA_ETH_Flow_Points".to_string(), sca_eth_flow_points.to_string(), ].join(",") }), - - self.att_name.as_ref().map(|att_name| { [ "ATT_NAME".to_string(), att_name.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -1626,26 +1593,20 @@ impl Cat { impl std::string::ToString for Cat { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("className".to_string()), Some(self.class_name.to_string()), - - self.color.as_ref().map(|color| { [ "color".to_string(), color.to_string(), ].join(",") }), - - self.declawed.as_ref().map(|declawed| { [ "declawed".to_string(), declawed.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -1830,22 +1791,18 @@ impl Category { impl std::string::ToString for Category { fn to_string(&self) -> String { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - self.name.as_ref().map(|name| { [ "name".to_string(), name.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2021,14 +1978,12 @@ impl ClassModel { impl std::string::ToString for ClassModel { fn to_string(&self) -> String { let params: Vec> = vec![ - self._class.as_ref().map(|_class| { [ "_class".to_string(), _class.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2199,14 +2154,12 @@ impl Client { impl std::string::ToString for Client { fn to_string(&self) -> String { let params: Vec> = vec![ - self.client.as_ref().map(|client| { [ "client".to_string(), client.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2386,26 +2339,20 @@ impl Dog { impl std::string::ToString for Dog { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("className".to_string()), Some(self.class_name.to_string()), - - self.color.as_ref().map(|color| { [ "color".to_string(), color.to_string(), ].join(",") }), - - self.breed.as_ref().map(|breed| { [ "breed".to_string(), breed.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2585,14 +2532,12 @@ impl DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { impl std::string::ToString for DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { fn to_string(&self) -> String { let params: Vec> = vec![ - self.dollar_special_left_square_bracket_property_period_name_right_square_bracket.as_ref().map(|dollar_special_left_square_bracket_property_period_name_right_square_bracket| { [ "$special[property.name]".to_string(), dollar_special_left_square_bracket_property_period_name_right_square_bracket.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -2773,12 +2718,9 @@ impl EnumArrays { impl std::string::ToString for EnumArrays { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping just_symbol in query parameter serialization - - // Skipping array_enum in query parameter serialization - - // Skipping array_array_enum in query parameter serialization - + // Skipping non-primitive type just_symbol in query parameter serialization + // Skipping non-primitive type array_enum in query parameter serialization + // Skipping non-primitive type array_array_enum in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -3490,16 +3432,11 @@ impl EnumTest { impl std::string::ToString for EnumTest { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping enum_string in query parameter serialization - - // Skipping enum_string_required in query parameter serialization - - // Skipping enum_integer in query parameter serialization - - // Skipping enum_number in query parameter serialization - - // Skipping outerEnum in query parameter serialization - + // Skipping non-primitive type enum_string in query parameter serialization + // Skipping non-primitive type enum_string_required in query parameter serialization + // Skipping non-primitive type enum_integer in query parameter serialization + // Skipping non-primitive type enum_number in query parameter serialization + // Skipping non-primitive type outerEnum in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -4172,74 +4109,51 @@ impl FormatTest { impl std::string::ToString for FormatTest { fn to_string(&self) -> String { let params: Vec> = vec![ - self.integer.as_ref().map(|integer| { [ "integer".to_string(), integer.to_string(), ].join(",") }), - - self.int32.as_ref().map(|int32| { [ "int32".to_string(), int32.to_string(), ].join(",") }), - - self.int64.as_ref().map(|int64| { [ "int64".to_string(), int64.to_string(), ].join(",") }), - - Some("number".to_string()), Some(self.number.to_string()), - - self.float.as_ref().map(|float| { [ "float".to_string(), float.to_string(), ].join(",") }), - - self.double.as_ref().map(|double| { [ "double".to_string(), double.to_string(), ].join(",") }), - - self.string.as_ref().map(|string| { [ "string".to_string(), string.to_string(), ].join(",") }), - - // Skipping byte in query parameter serialization - // Skipping byte in query parameter serialization - - // Skipping binary in query parameter serialization - // Skipping binary in query parameter serialization - - // Skipping date in query parameter serialization - - // Skipping dateTime in query parameter serialization - - // Skipping uuid in query parameter serialization - - + // Skipping byte array byte in query parameter serialization + // Skipping binary data binary in query parameter serialization + // Skipping non-primitive type date in query parameter serialization + // Skipping non-primitive type dateTime in query parameter serialization + // Skipping non-primitive type uuid in query parameter serialization Some("password".to_string()), Some(self.password.to_string()), - ]; params.into_iter().flatten().collect::>().join(",") @@ -4461,22 +4375,18 @@ impl HasOnlyReadOnly { impl std::string::ToString for HasOnlyReadOnly { fn to_string(&self) -> String { let params: Vec> = vec![ - self.bar.as_ref().map(|bar| { [ "bar".to_string(), bar.to_string(), ].join(",") }), - - self.foo.as_ref().map(|foo| { [ "foo".to_string(), foo.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -4651,14 +4561,12 @@ impl List { impl std::string::ToString for List { fn to_string(&self) -> String { let params: Vec> = vec![ - self.param_123_list.as_ref().map(|param_123_list| { [ "123-list".to_string(), param_123_list.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -4839,15 +4747,9 @@ impl MapTest { impl std::string::ToString for MapTest { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping map_map_of_string in query parameter serialization - // Skipping map_map_of_string in query parameter serialization - - // Skipping map_map_of_enum in query parameter serialization - // Skipping map_map_of_enum in query parameter serialization - - // Skipping map_of_enum_string in query parameter serialization - // Skipping map_of_enum_string in query parameter serialization - + // Skipping map map_map_of_string in query parameter serialization + // Skipping map map_map_of_enum in query parameter serialization + // Skipping map map_of_enum_string in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -5161,13 +5063,9 @@ impl MixedPropertiesAndAdditionalPropertiesClass { impl std::string::ToString for MixedPropertiesAndAdditionalPropertiesClass { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping uuid in query parameter serialization - - // Skipping dateTime in query parameter serialization - - // Skipping map in query parameter serialization - // Skipping map in query parameter serialization - + // Skipping non-primitive type uuid in query parameter serialization + // Skipping non-primitive type dateTime in query parameter serialization + // Skipping map map in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -5352,22 +5250,18 @@ impl Model200Response { impl std::string::ToString for Model200Response { fn to_string(&self) -> String { let params: Vec> = vec![ - self.name.as_ref().map(|name| { [ "name".to_string(), name.to_string(), ].join(",") }), - - self.class.as_ref().map(|class| { [ "class".to_string(), class.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -5558,34 +5452,26 @@ impl Name { impl std::string::ToString for Name { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("name".to_string()), Some(self.name.to_string()), - - self.snake_case.as_ref().map(|snake_case| { [ "snake_case".to_string(), snake_case.to_string(), ].join(",") }), - - self.property.as_ref().map(|property| { [ "property".to_string(), property.to_string(), ].join(",") }), - - self.param_123_number.as_ref().map(|param_123_number| { [ "123Number".to_string(), param_123_number.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -5768,14 +5654,12 @@ impl NumberOnly { impl std::string::ToString for NumberOnly { fn to_string(&self) -> String { let params: Vec> = vec![ - self.just_number.as_ref().map(|just_number| { [ "JustNumber".to_string(), just_number.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -5946,8 +5830,7 @@ impl ObjectContainingObjectWithOnlyAdditionalProperties { impl std::string::ToString for ObjectContainingObjectWithOnlyAdditionalProperties { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping inner in query parameter serialization - + // Skipping non-primitive type inner in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -6287,42 +6170,32 @@ impl Order { impl std::string::ToString for Order { fn to_string(&self) -> String { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - self.pet_id.as_ref().map(|pet_id| { [ "petId".to_string(), pet_id.to_string(), ].join(",") }), - - self.quantity.as_ref().map(|quantity| { [ "quantity".to_string(), quantity.to_string(), ].join(",") }), - - // Skipping shipDate in query parameter serialization - - // Skipping status in query parameter serialization - - + // Skipping non-primitive type shipDate in query parameter serialization + // Skipping non-primitive type status in query parameter serialization self.complete.as_ref().map(|complete| { [ "complete".to_string(), complete.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -6801,30 +6674,24 @@ impl OuterComposite { impl std::string::ToString for OuterComposite { fn to_string(&self) -> String { let params: Vec> = vec![ - self.my_number.as_ref().map(|my_number| { [ "my_number".to_string(), my_number.to_string(), ].join(",") }), - - self.my_string.as_ref().map(|my_string| { [ "my_string".to_string(), my_string.to_string(), ].join(",") }), - - self.my_boolean.as_ref().map(|my_boolean| { [ "my_boolean".to_string(), my_boolean.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -7439,28 +7306,19 @@ impl Pet { impl std::string::ToString for Pet { fn to_string(&self) -> String { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - // Skipping category in query parameter serialization - - + // Skipping non-primitive type category in query parameter serialization Some("name".to_string()), Some(self.name.to_string()), - - Some("photoUrls".to_string()), Some(self.photo_urls.iter().map(|x| x.to_string()).collect::>().join(",")), - - // Skipping tags in query parameter serialization - - // Skipping status in query parameter serialization - + // Skipping non-primitive type tags in query parameter serialization + // Skipping non-primitive type status in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -7787,22 +7645,18 @@ impl ReadOnlyFirst { impl std::string::ToString for ReadOnlyFirst { fn to_string(&self) -> String { let params: Vec> = vec![ - self.bar.as_ref().map(|bar| { [ "bar".to_string(), bar.to_string(), ].join(",") }), - - self.baz.as_ref().map(|baz| { [ "baz".to_string(), baz.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -7979,14 +7833,12 @@ impl Return { impl std::string::ToString for Return { fn to_string(&self) -> String { let params: Vec> = vec![ - self.r#return.as_ref().map(|r#return| { [ "return".to_string(), r#return.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -8163,22 +8015,18 @@ impl Tag { impl std::string::ToString for Tag { fn to_string(&self) -> String { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - self.name.as_ref().map(|name| { [ "name".to_string(), name.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -9039,70 +8887,54 @@ impl User { impl std::string::ToString for User { fn to_string(&self) -> String { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - self.username.as_ref().map(|username| { [ "username".to_string(), username.to_string(), ].join(",") }), - - self.first_name.as_ref().map(|first_name| { [ "firstName".to_string(), first_name.to_string(), ].join(",") }), - - self.last_name.as_ref().map(|last_name| { [ "lastName".to_string(), last_name.to_string(), ].join(",") }), - - self.email.as_ref().map(|email| { [ "email".to_string(), email.to_string(), ].join(",") }), - - self.password.as_ref().map(|password| { [ "password".to_string(), password.to_string(), ].join(",") }), - - self.phone.as_ref().map(|phone| { [ "phone".to_string(), phone.to_string(), ].join(",") }), - - self.user_status.as_ref().map(|user_status| { [ "userStatus".to_string(), user_status.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") diff --git a/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md b/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md index faa29c8e238..883546f323e 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md +++ b/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md @@ -3,8 +3,8 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**nullable_thing** | **String** | | [optional] [default to None] -**required_nullable_thing** | **String** | | +**nullable_thing** | **swagger::Nullable** | | [optional] [default to None] +**required_nullable_thing** | **swagger::Nullable** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs index 1d6e6f7be63..0e86f9a1267 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs @@ -37,18 +37,14 @@ impl ANullableContainer { impl std::string::ToString for ANullableContainer { fn to_string(&self) -> String { let params: Vec> = vec![ - self.nullable_thing.as_ref().map(|nullable_thing| { [ "NullableThing".to_string(), nullable_thing.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - Some("RequiredNullableThing".to_string()), Some(self.required_nullable_thing.as_ref().map_or("null".to_string(), |x| x.to_string())), - ]; params.into_iter().flatten().collect::>().join(",") @@ -66,8 +62,8 @@ impl std::str::FromStr for ANullableContainer { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub nullable_thing: Vec, - pub required_nullable_thing: Vec, + pub nullable_thing: Vec>, + pub required_nullable_thing: Vec>, } let mut intermediate_rep = IntermediateRep::default(); @@ -352,22 +348,18 @@ impl AllOfObject { impl std::string::ToString for AllOfObject { fn to_string(&self) -> String { let params: Vec> = vec![ - self.sample_property.as_ref().map(|sample_property| { [ "sampleProperty".to_string(), sample_property.to_string(), ].join(",") }), - - self.sample_base_property.as_ref().map(|sample_base_property| { [ "sampleBaseProperty".to_string(), sample_base_property.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -533,14 +525,12 @@ impl BaseAllOf { impl std::string::ToString for BaseAllOf { fn to_string(&self) -> String { let params: Vec> = vec![ - self.sample_base_property.as_ref().map(|sample_base_property| { [ "sampleBaseProperty".to_string(), sample_base_property.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -706,18 +696,14 @@ impl DummyPutRequest { impl std::string::ToString for DummyPutRequest { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("id".to_string()), Some(self.id.to_string()), - - self.password.as_ref().map(|password| { [ "password".to_string(), password.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -885,14 +871,12 @@ impl GetYamlResponse { impl std::string::ToString for GetYamlResponse { fn to_string(&self) -> String { let params: Vec> = vec![ - self.value.as_ref().map(|value| { [ "value".to_string(), value.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",") @@ -1055,8 +1039,7 @@ impl ObjectOfObjects { impl std::string::ToString for ObjectOfObjects { fn to_string(&self) -> String { let params: Vec> = vec![ - // Skipping inner in query parameter serialization - + // Skipping non-primitive type inner in query parameter serialization ]; params.into_iter().flatten().collect::>().join(",") @@ -1222,18 +1205,14 @@ impl ObjectOfObjectsInner { impl std::string::ToString for ObjectOfObjectsInner { fn to_string(&self) -> String { let params: Vec> = vec![ - Some("required_thing".to_string()), Some(self.required_thing.to_string()), - - self.optional_thing.as_ref().map(|optional_thing| { [ "optional_thing".to_string(), optional_thing.to_string(), ].join(",") }), - ]; params.into_iter().flatten().collect::>().join(",")