Skip to content

Commit a5982f8

Browse files
committed
Added double option support
1 parent 9f3c11b commit a5982f8

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,9 +605,18 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
605605
additionalProperties.put("serdeWith", true);
606606
}
607607

608+
// Add a field for checking if a field is with optional or required in templates.
609+
// This is useful in Mustache templates as it's not possible to do OR logic between variables.
610+
property.vendorExtensions.put("isMandatory", !property.isNullable && property.required);
611+
608612
// If a property is a base64-encoded byte array, use `serde_with` for deserialization.
609613
if (property.isByteArray) {
610614
additionalProperties.put("serdeWith", true);
615+
// If a byte array is both nullable and not required we need to include our own
616+
// custom double option as serde_as does not work with serde_with's double_option.
617+
if (property.isNullable && !property.required) {
618+
additionalProperties.put("serdeAsDoubleOption", true);
619+
}
611620
}
612621
}
613622

modules/openapi-generator/src/main/resources/rust/model.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub struct {{{classname}}} {
129129
/// {{{.}}}
130130
{{/description}}
131131
{{#isByteArray}}
132-
{{#required}}#[serde_as(as = "serde_with::base64::Base64")]{{/required}}{{^required}}#[serde_as(as = "{{#isNullable}}Option<{{/isNullable}}Option<serde_with::base64::Base64>{{#isNullable}}>{{/isNullable}}")]{{/required}}
132+
{{#vendorExtensions.isMandatory}}#[serde_as(as = "serde_with::base64::Base64")]{{/vendorExtensions.isMandatory}}{{^vendorExtensions.isMandatory}}#[serde_as(as = "{{^serdeAsDoubleOption}}Option{{/serdeAsDoubleOption}}{{#serdeAsDoubleOption}}super::DoubleOption{{/serdeAsDoubleOption}}<serde_with::base64::Base64>")]{{/vendorExtensions.isMandatory}}
133133
{{/isByteArray}}
134134
#[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default{{^isByteArray}}, with = "::serde_with::rust::double_option"{{/isByteArray}}{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})]
135135
pub {{{name}}}: {{!

modules/openapi-generator/src/main/resources/rust/model_mod.mustache

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,42 @@ pub mod {{{classFilename}}};
44
pub use self::{{{classFilename}}}::{{{classname}}};
55
{{/model}}
66
{{/models}}
7+
{{#serdeAsDoubleOption}}
8+
use serde::{Deserialize, Deserializer, Serializer};
9+
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
10+
use std::marker::PhantomData;
11+
12+
pub(crate) struct DoubleOption<T>(PhantomData<T>);
13+
14+
impl<T, TAs> SerializeAs<Option<Option<T>>> for DoubleOption<TAs>
15+
where
16+
TAs: SerializeAs<T>,
17+
{
18+
fn serialize_as<S>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
19+
where
20+
S: Serializer,
21+
{
22+
match values {
23+
None => serializer.serialize_unit(),
24+
Some(None) => serializer.serialize_none(),
25+
Some(Some(v)) => serializer.serialize_some(&SerializeAsWrap::<T, TAs>::new(v)),
26+
}
27+
}
28+
}
29+
30+
impl<'de, T, TAs> DeserializeAs<'de, Option<Option<T>>> for DoubleOption<TAs>
31+
where
32+
TAs: DeserializeAs<'de, T>,
33+
T: std::fmt::Debug,
34+
{
35+
fn deserialize_as<D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
36+
where
37+
D: Deserializer<'de>,
38+
{
39+
Ok(Some(
40+
DeserializeAsWrap::<Option<T>, Option<TAs>>::deserialize(deserializer)?
41+
.into_inner(),
42+
))
43+
}
44+
}
45+
{{/serdeAsDoubleOption}}

0 commit comments

Comments
 (0)