Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -605,9 +605,18 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
additionalProperties.put("serdeWith", true);
}

// Add a field for checking if a field is with optional or required in templates.
// This is useful in Mustache templates as it's not possible to do OR logic between variables.
property.vendorExtensions.put("isMandatory", !property.isNullable && property.required);

// If a property is a base64-encoded byte array, use `serde_with` for deserialization.
if (property.isByteArray) {
additionalProperties.put("serdeWith", true);
// If a byte array is both nullable and not required we need to include our own
// custom double option as serde_as does not work with serde_with's double_option.
if (property.isNullable && !property.required) {
additionalProperties.put("serdeAsDoubleOption", true);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ pub struct {{{classname}}} {
/// {{{.}}}
{{/description}}
{{#isByteArray}}
{{#required}}#[serde_as(as = "serde_with::base64::Base64")]{{/required}}{{^required}}#[serde_as(as = "Option<serde_with::base64::Base64>")]{{/required}}
{{#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}}
{{/isByteArray}}
#[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default, with = "::serde_with::rust::double_option"{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})]
#[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}})]
pub {{{name}}}: {{!
### Option Start
}}{{#isNullable}}Option<{{/isNullable}}{{^required}}Option<{{/required}}{{!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,42 @@ pub mod {{{classFilename}}};
pub use self::{{{classFilename}}}::{{{classname}}};
{{/model}}
{{/models}}
{{#serdeAsDoubleOption}}
use serde::{Deserialize, Deserializer, Serializer};
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
use std::marker::PhantomData;

pub(crate) struct DoubleOption<T>(PhantomData<T>);

impl<T, TAs> SerializeAs<Option<Option<T>>> for DoubleOption<TAs>
where
TAs: SerializeAs<T>,
{
fn serialize_as<S>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match values {
None => serializer.serialize_unit(),
Some(None) => serializer.serialize_none(),
Some(Some(v)) => serializer.serialize_some(&SerializeAsWrap::<T, TAs>::new(v)),
}
}
}

impl<'de, T, TAs> DeserializeAs<'de, Option<Option<T>>> for DoubleOption<TAs>
where
TAs: DeserializeAs<'de, T>,
T: std::fmt::Debug,
{
fn deserialize_as<D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
{
Ok(Some(
DeserializeAsWrap::<Option<T>, Option<TAs>>::deserialize(deserializer)?
.into_inner(),
))
}
}
{{/serdeAsDoubleOption}}
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,10 @@ components:
bytes:
type: string
format: byte
nullableBytes: # Regression test for bug report in #20500
type: string
format: byte
nullable: true
decimal:
type: string
format: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Name | Type | Description | Notes
**boolean** | **bool** | |
**uuid** | [**uuid::Uuid**](uuid::Uuid.md) | |
**bytes** | **String** | |
**nullable_bytes** | Option<**String**> | | [optional]
**decimal** | **String** | |

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
Expand Down
37 changes: 37 additions & 0 deletions samples/client/petstore/rust/hyper/petstore/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,40 @@ pub mod user;
pub use self::user::User;
pub mod vehicle;
pub use self::vehicle::Vehicle;
use serde::{Deserialize, Deserializer, Serializer};
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
use std::marker::PhantomData;

pub(crate) struct DoubleOption<T>(PhantomData<T>);

impl<T, TAs> SerializeAs<Option<Option<T>>> for DoubleOption<TAs>
where
TAs: SerializeAs<T>,
{
fn serialize_as<S>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match values {
None => serializer.serialize_unit(),
Some(None) => serializer.serialize_none(),
Some(Some(v)) => serializer.serialize_some(&SerializeAsWrap::<T, TAs>::new(v)),
}
}
}

impl<'de, T, TAs> DeserializeAs<'de, Option<Option<T>>> for DoubleOption<TAs>
where
TAs: DeserializeAs<'de, T>,
T: std::fmt::Debug,
{
fn deserialize_as<D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
{
Ok(Some(
DeserializeAsWrap::<Option<T>, Option<TAs>>::deserialize(deserializer)?
.into_inner(),
))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct TypeTesting {
#[serde_as(as = "serde_with::base64::Base64")]
#[serde(rename = "bytes")]
pub bytes: Vec<u8>,
#[serde_as(as = "super::DoubleOption<serde_with::base64::Base64>")]
#[serde(rename = "nullableBytes", default, skip_serializing_if = "Option::is_none")]
pub nullable_bytes: Option<Option<Vec<u8>>>,
#[serde(rename = "decimal")]
pub decimal: String,
}
Expand All @@ -50,6 +53,7 @@ impl TypeTesting {
boolean,
uuid,
bytes,
nullable_bytes: None,
decimal,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Name | Type | Description | Notes
**boolean** | **bool** | |
**uuid** | [**uuid::Uuid**](uuid::Uuid.md) | |
**bytes** | **String** | |
**nullable_bytes** | Option<**String**> | | [optional]
**decimal** | **String** | |

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
Expand Down
37 changes: 37 additions & 0 deletions samples/client/petstore/rust/hyper0x/petstore/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,40 @@ pub mod user;
pub use self::user::User;
pub mod vehicle;
pub use self::vehicle::Vehicle;
use serde::{Deserialize, Deserializer, Serializer};
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
use std::marker::PhantomData;

pub(crate) struct DoubleOption<T>(PhantomData<T>);

impl<T, TAs> SerializeAs<Option<Option<T>>> for DoubleOption<TAs>
where
TAs: SerializeAs<T>,
{
fn serialize_as<S>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match values {
None => serializer.serialize_unit(),
Some(None) => serializer.serialize_none(),
Some(Some(v)) => serializer.serialize_some(&SerializeAsWrap::<T, TAs>::new(v)),
}
}
}

impl<'de, T, TAs> DeserializeAs<'de, Option<Option<T>>> for DoubleOption<TAs>
where
TAs: DeserializeAs<'de, T>,
T: std::fmt::Debug,
{
fn deserialize_as<D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
{
Ok(Some(
DeserializeAsWrap::<Option<T>, Option<TAs>>::deserialize(deserializer)?
.into_inner(),
))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct TypeTesting {
#[serde_as(as = "serde_with::base64::Base64")]
#[serde(rename = "bytes")]
pub bytes: Vec<u8>,
#[serde_as(as = "super::DoubleOption<serde_with::base64::Base64>")]
#[serde(rename = "nullableBytes", default, skip_serializing_if = "Option::is_none")]
pub nullable_bytes: Option<Option<Vec<u8>>>,
#[serde(rename = "decimal")]
pub decimal: String,
}
Expand All @@ -50,6 +53,7 @@ impl TypeTesting {
boolean,
uuid,
bytes,
nullable_bytes: None,
decimal,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Name | Type | Description | Notes
**boolean** | **bool** | |
**uuid** | [**uuid::Uuid**](uuid::Uuid.md) | |
**bytes** | **String** | |
**nullable_bytes** | Option<**String**> | | [optional]
**decimal** | **String** | |

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,40 @@ pub mod user;
pub use self::user::User;
pub mod vehicle;
pub use self::vehicle::Vehicle;
use serde::{Deserialize, Deserializer, Serializer};
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
use std::marker::PhantomData;

pub(crate) struct DoubleOption<T>(PhantomData<T>);

impl<T, TAs> SerializeAs<Option<Option<T>>> for DoubleOption<TAs>
where
TAs: SerializeAs<T>,
{
fn serialize_as<S>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match values {
None => serializer.serialize_unit(),
Some(None) => serializer.serialize_none(),
Some(Some(v)) => serializer.serialize_some(&SerializeAsWrap::<T, TAs>::new(v)),
}
}
}

impl<'de, T, TAs> DeserializeAs<'de, Option<Option<T>>> for DoubleOption<TAs>
where
TAs: DeserializeAs<'de, T>,
T: std::fmt::Debug,
{
fn deserialize_as<D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
{
Ok(Some(
DeserializeAsWrap::<Option<T>, Option<TAs>>::deserialize(deserializer)?
.into_inner(),
))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct TypeTesting {
#[serde_as(as = "serde_with::base64::Base64")]
#[serde(rename = "bytes")]
pub bytes: Vec<u8>,
#[serde_as(as = "super::DoubleOption<serde_with::base64::Base64>")]
#[serde(rename = "nullableBytes", default, skip_serializing_if = "Option::is_none")]
pub nullable_bytes: Option<Option<Vec<u8>>>,
#[serde(rename = "decimal")]
pub decimal: String,
}
Expand All @@ -50,6 +53,7 @@ impl TypeTesting {
boolean,
uuid,
bytes,
nullable_bytes: None,
decimal,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Name | Type | Description | Notes
**boolean** | **bool** | |
**uuid** | [**uuid::Uuid**](uuid::Uuid.md) | |
**bytes** | **String** | |
**nullable_bytes** | Option<**String**> | | [optional]
**decimal** | **String** | |

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,40 @@ pub mod user;
pub use self::user::User;
pub mod vehicle;
pub use self::vehicle::Vehicle;
use serde::{Deserialize, Deserializer, Serializer};
use serde_with::{de::DeserializeAsWrap, ser::SerializeAsWrap, DeserializeAs, SerializeAs};
use std::marker::PhantomData;

pub(crate) struct DoubleOption<T>(PhantomData<T>);

impl<T, TAs> SerializeAs<Option<Option<T>>> for DoubleOption<TAs>
where
TAs: SerializeAs<T>,
{
fn serialize_as<S>(values: &Option<Option<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match values {
None => serializer.serialize_unit(),
Some(None) => serializer.serialize_none(),
Some(Some(v)) => serializer.serialize_some(&SerializeAsWrap::<T, TAs>::new(v)),
}
}
}

impl<'de, T, TAs> DeserializeAs<'de, Option<Option<T>>> for DoubleOption<TAs>
where
TAs: DeserializeAs<'de, T>,
T: std::fmt::Debug,
{
fn deserialize_as<D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
D: Deserializer<'de>,
{
Ok(Some(
DeserializeAsWrap::<Option<T>, Option<TAs>>::deserialize(deserializer)?
.into_inner(),
))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct TypeTesting {
#[serde_as(as = "serde_with::base64::Base64")]
#[serde(rename = "bytes")]
pub bytes: Vec<u8>,
#[serde_as(as = "super::DoubleOption<serde_with::base64::Base64>")]
#[serde(rename = "nullableBytes", default, skip_serializing_if = "Option::is_none")]
pub nullable_bytes: Option<Option<Vec<u8>>>,
#[serde(rename = "decimal")]
pub decimal: String,
}
Expand All @@ -50,6 +53,7 @@ impl TypeTesting {
boolean,
uuid,
bytes,
nullable_bytes: None,
decimal,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Name | Type | Description | Notes
**boolean** | **bool** | |
**uuid** | [**uuid::Uuid**](uuid::Uuid.md) | |
**bytes** | **String** | |
**nullable_bytes** | Option<**String**> | | [optional]
**decimal** | **String** | |

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
Expand Down
Loading
Loading