Merge pull request #2570 from dtolnay/remotenonexhaustive
Treat unmatched non-exhaustive remote variant as serde(skip)
This commit is contained in:
commit
5e56c9fba8
@ -1370,3 +1370,16 @@ impl Serialize for AdjacentlyTaggedEnumVariant {
|
|||||||
serializer.serialize_unit_variant(self.enum_name, self.variant_index, self.variant_name)
|
serializer.serialize_unit_variant(self.enum_name, self.variant_index, self.variant_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error when Serialize for a non_exhaustive remote enum encounters a variant
|
||||||
|
// that is not recognized.
|
||||||
|
pub struct CannotSerializeVariant<T>(pub T);
|
||||||
|
|
||||||
|
impl<T> Display for CannotSerializeVariant<T>
|
||||||
|
where
|
||||||
|
T: Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(formatter, "enum variant cannot be serialized: {:?}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -221,6 +221,7 @@ pub struct Container {
|
|||||||
is_packed: bool,
|
is_packed: bool,
|
||||||
/// Error message generated when type can't be deserialized
|
/// Error message generated when type can't be deserialized
|
||||||
expecting: Option<String>,
|
expecting: Option<String>,
|
||||||
|
non_exhaustive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Styles of representing an enum.
|
/// Styles of representing an enum.
|
||||||
@ -306,9 +307,12 @@ impl Container {
|
|||||||
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
|
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
|
||||||
let mut serde_path = Attr::none(cx, CRATE);
|
let mut serde_path = Attr::none(cx, CRATE);
|
||||||
let mut expecting = Attr::none(cx, EXPECTING);
|
let mut expecting = Attr::none(cx, EXPECTING);
|
||||||
|
let mut non_exhaustive = false;
|
||||||
|
|
||||||
for attr in &item.attrs {
|
for attr in &item.attrs {
|
||||||
if attr.path() != SERDE {
|
if attr.path() != SERDE {
|
||||||
|
non_exhaustive |=
|
||||||
|
matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,6 +591,7 @@ impl Container {
|
|||||||
serde_path: serde_path.get(),
|
serde_path: serde_path.get(),
|
||||||
is_packed,
|
is_packed,
|
||||||
expecting: expecting.get(),
|
expecting: expecting.get(),
|
||||||
|
non_exhaustive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,6 +677,10 @@ impl Container {
|
|||||||
pub fn expecting(&self) -> Option<&str> {
|
pub fn expecting(&self) -> Option<&str> {
|
||||||
self.expecting.as_ref().map(String::as_ref)
|
self.expecting.as_ref().map(String::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn non_exhaustive(&self) -> bool {
|
||||||
|
self.non_exhaustive
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decide_tag(
|
fn decide_tag(
|
||||||
|
@ -19,6 +19,7 @@ pub const FLATTEN: Symbol = Symbol("flatten");
|
|||||||
pub const FROM: Symbol = Symbol("from");
|
pub const FROM: Symbol = Symbol("from");
|
||||||
pub const GETTER: Symbol = Symbol("getter");
|
pub const GETTER: Symbol = Symbol("getter");
|
||||||
pub const INTO: Symbol = Symbol("into");
|
pub const INTO: Symbol = Symbol("into");
|
||||||
|
pub const NON_EXHAUSTIVE: Symbol = Symbol("non_exhaustive");
|
||||||
pub const OTHER: Symbol = Symbol("other");
|
pub const OTHER: Symbol = Symbol("other");
|
||||||
pub const REMOTE: Symbol = Symbol("remote");
|
pub const REMOTE: Symbol = Symbol("remote");
|
||||||
pub const RENAME: Symbol = Symbol("rename");
|
pub const RENAME: Symbol = Symbol("rename");
|
||||||
|
@ -401,7 +401,7 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
|
|||||||
|
|
||||||
let self_var = ¶ms.self_var;
|
let self_var = ¶ms.self_var;
|
||||||
|
|
||||||
let arms: Vec<_> = variants
|
let mut arms: Vec<_> = variants
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(variant_index, variant)| {
|
.map(|(variant_index, variant)| {
|
||||||
@ -409,6 +409,12 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
if cattrs.non_exhaustive() {
|
||||||
|
arms.push(quote! {
|
||||||
|
unrecognized => _serde::__private::Err(_serde::ser::Error::custom(_serde::__private::ser::CannotSerializeVariant(unrecognized))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
quote_expr! {
|
quote_expr! {
|
||||||
match *#self_var {
|
match *#self_var {
|
||||||
#(#arms)*
|
#(#arms)*
|
||||||
|
@ -125,6 +125,9 @@ struct Test {
|
|||||||
|
|
||||||
#[serde(with = "EnumConcrete")]
|
#[serde(with = "EnumConcrete")]
|
||||||
enum_concrete: remote::EnumGeneric<u8>,
|
enum_concrete: remote::EnumGeneric<u8>,
|
||||||
|
|
||||||
|
#[serde(with = "ErrorKindDef")]
|
||||||
|
io_error_kind: std::io::ErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@ -197,6 +200,15 @@ enum EnumConcrete {
|
|||||||
Variant(u8),
|
Variant(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(remote = "std::io::ErrorKind")]
|
||||||
|
#[non_exhaustive]
|
||||||
|
enum ErrorKindDef {
|
||||||
|
NotFound,
|
||||||
|
PermissionDenied,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
impl From<PrimitivePrivDef> for remote::PrimitivePriv {
|
impl From<PrimitivePrivDef> for remote::PrimitivePriv {
|
||||||
fn from(def: PrimitivePrivDef) -> Self {
|
fn from(def: PrimitivePrivDef) -> Self {
|
||||||
remote::PrimitivePriv::new(def.0)
|
remote::PrimitivePriv::new(def.0)
|
||||||
|
Loading…
Reference in New Issue
Block a user