Skip to content

Commit

Permalink
more conformance fixes to oneof handling and nan/inf serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
cynecx committed Nov 22, 2024
1 parent a52d4fc commit a544538
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 6 deletions.
6 changes: 6 additions & 0 deletions conformance/failing_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto2.JsonInput.FieldNameExtension.Validator
Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
Recommended.Proto3.JsonInput.NullValueInOtherOneofOldFormat.Validator

# These just aren't possible right now, because we can't represent unknown
# enum values in the message struct (they are stored as i32).
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInMapValue.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInOptionalField.ProtobufOutput
Recommended.Proto3.JsonInput.IgnoreUnknownEnumStringValueInRepeatedField.ProtobufOutput
15 changes: 12 additions & 3 deletions prost-derive/src/serde/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,24 @@ pub fn impl_for_message(
field_matches.push(quote! {
__Field::#field_variant_ident(key) => {
if _private::Option::is_some(&#field_variant_ident) {
return _private::Err(
<__A::Error as _serde::de::Error>::duplicate_field(#field_ident_str)
let __val = _serde::de::MapAccess::next_value_seed(
&mut __map,
_private::DesIntoWithConfig::<_private::NullDeserializer, ()>::new(
__config
),
);
match __val {
_private::Ok(()) => continue,
_private::Err(_) => return _private::Err(
<__A::Error as _serde::de::Error>::duplicate_field(#field_ident_str)
),
}
}
let __val = _serde::de::MapAccess::next_value_seed(
&mut __map,
_private::OneOfDeserializer(key, __config),
)?;
if __val.is_some() {
if _private::Option::is_some(&__val) {
#field_variant_ident = _private::Some(__val);
}
}
Expand Down
9 changes: 8 additions & 1 deletion prost-types/src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,14 @@ impl CustomSerialize for Value {
{
match self.kind.as_ref() {
Some(value::Kind::NullValue(_)) | None => serializer.serialize_none(),
Some(value::Kind::NumberValue(val)) => serializer.serialize_f64(*val),
Some(value::Kind::NumberValue(val)) => {
if val.is_nan() || val.is_infinite() {
return Err(serde::ser::Error::custom(format!(
"serializing a value::Kind::NumberValue, which is {val}, is not possible"
)));
}
serializer.serialize_f64(*val)
}
Some(value::Kind::StringValue(val)) => serializer.serialize_str(val),
Some(value::Kind::BoolValue(val)) => serializer.serialize_bool(*val),
Some(value::Kind::StructValue(val)) => {
Expand Down
2 changes: 1 addition & 1 deletion prost/src/serde/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ pub use forward::ForwardDeserializer;
pub use map::MapDeserializer;
pub use message::MessageDeserializer;
pub use oneof::{DeserializeOneOf, OneOfDeserializer};
pub use option::OptionDeserializer;
pub use option::{NullDeserializer, OptionDeserializer};
pub use r#enum::{DeserializeEnum, EnumDeserializer};
pub use scalar::{BoolDeserializer, FloatDeserializer, IntDeserializer};
pub use vec::VecDeserializer;
Expand Down
43 changes: 43 additions & 0 deletions prost/src/serde/de/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,46 @@ where
true
}
}

pub struct NullDeserializer;

impl DeserializeInto<()> for NullDeserializer {
#[inline]
fn deserialize_into<'de, D: serde::Deserializer<'de>>(
deserializer: D,
_config: &DeserializerConfig,
) -> Result<(), D::Error> {
struct Visitor;

impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = ();

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a null value")
}

#[inline]
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(())
}

#[inline]
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(())
}
}

deserializer.deserialize_option(Visitor)
}

#[inline]
fn can_deserialize_null() -> bool {
true
}
}
2 changes: 1 addition & 1 deletion prost/src/serde/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ pub use super::de::{
BoolDeserializer, BytesDeserializer, CustomDeserialize, DefaultDeserializer, DesIntoWithConfig,
DesWithConfig, DeserializeEnum, DeserializeInto, DeserializeOneOf, EnumDeserializer,
FloatDeserializer, ForwardDeserializer, IntDeserializer, MapDeserializer, MessageDeserializer,
OneOfDeserializer, OptionDeserializer, VecDeserializer,
NullDeserializer, OneOfDeserializer, OptionDeserializer, VecDeserializer,
};

0 comments on commit a544538

Please sign in to comment.