forked from loafle/openapi-generator-original
[rust] Fixed nullable byte arrays (#20720)
* [rust] fixed nullable byte arrays * Updated tests and samples * updated type test * Added double option support * updated samples
This commit is contained in:
parent
e767496357
commit
caf22add95
@ -605,9 +605,18 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}}{{!
|
||||
|
@ -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}}
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -34,6 +34,9 @@ pub struct FooTypeTesting {
|
||||
#[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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl FooTypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -42,3 +42,40 @@ pub mod foo_user;
|
||||
pub use self::foo_user::FooUser;
|
||||
pub mod foo_vehicle;
|
||||
pub use self::foo_vehicle::FooVehicle;
|
||||
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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
@ -50,6 +53,7 @@ impl TypeTesting {
|
||||
boolean,
|
||||
uuid,
|
||||
bytes,
|
||||
nullable_bytes: None,
|
||||
decimal,
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ fn test_types() {
|
||||
boolean: true,
|
||||
uuid: Uuid::new_v4(),
|
||||
bytes: vec![1, 2, 3, 4],
|
||||
nullable_bytes: Some(Some(vec![1, 2, 3, 4])),
|
||||
decimal: String::from("foo"),
|
||||
};
|
||||
assert_eq!(type_of(tt.int32), "i32");
|
||||
|
Loading…
x
Reference in New Issue
Block a user