events: Add a compat workaround for prev_content in unsigned

This commit is contained in:
Jonas Platte 2021-08-15 01:31:57 +02:00
parent 1907ce1e91
commit 098339056b
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
5 changed files with 107 additions and 7 deletions

View File

@ -18,6 +18,9 @@ version = "0.24.3"
[lib]
proc-macro = true
[features]
compat = []
[dependencies]
proc-macro-crate = "1.0.0"
proc-macro2 = "1.0.24"

View File

@ -44,7 +44,7 @@ pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> {
};
let serialize_impl = expand_serialize_event(&input, &var, &fields, &ruma_events);
let deserialize_impl = expand_deserialize_event(&input, &var, &fields, &ruma_events)?;
let deserialize_impl = expand_deserialize_event(&input, &kind, &var, &fields, &ruma_events)?;
let conversion_impl = expand_from_into(&input, &kind, &var, &fields, &ruma_events);
let eq_impl = expand_eq_ord_event(&input, &fields);
@ -120,6 +120,7 @@ fn expand_serialize_event(
fn expand_deserialize_event(
input: &DeriveInput,
_kind: &EventKind,
var: &EventKindVariation,
fields: &[Field],
ruma_events: &TokenStream,
@ -154,12 +155,30 @@ fn expand_deserialize_event(
let ty = &field.ty;
if name == "content" || name == "prev_content" {
if is_generic {
quote! { Box<#serde_json::value::RawValue> }
quote! { ::std::boxed::Box<#serde_json::value::RawValue> }
} else {
quote! { #content_type }
}
} else {
quote! { #ty }
#[allow(unused_mut)]
let mut ty = quote! { #ty };
#[cfg(feature = "compat")]
if matches!(_kind, EventKind::State) && name == "unsigned" {
match var {
EventKindVariation::Full | EventKindVariation::Sync => {
ty = quote! { #ruma_events::UnsignedWithPrevContent };
}
EventKindVariation::Redacted | EventKindVariation::RedactedSync => {
ty = quote! { #ruma_events::RedactedUnsignedWithPrevContent };
}
EventKindVariation::Stripped
| EventKindVariation::Initial
| EventKindVariation::RedactedStripped => unreachable!(),
}
}
ty
}
})
.collect();
@ -207,16 +226,43 @@ fn expand_deserialize_event(
}
} else if name == "prev_content" {
if is_generic {
quote! {
#[allow(unused_mut)]
let mut res = quote! {
let prev_content = prev_content.map(|json| {
C::from_parts(&event_type, &json).map_err(A::Error::custom)
}).transpose()?;
}
};
#[cfg(feature = "compat")]
if let EventKind::State = _kind {
res = quote! {
let prev_content = prev_content
.or_else(|| unsigned.as_mut().and_then(|u| u.prev_content.take()));
#res
};
};
res
} else {
TokenStream::new()
}
} else if name == "unsigned" {
quote! { let unsigned = unsigned.unwrap_or_default(); }
#[allow(unused_mut)]
let mut res = quote! {
let unsigned = unsigned.unwrap_or_default();
};
#[cfg(feature = "compat")]
if matches!(_kind, EventKind::State) {
res = quote! {
let unsigned = unsigned.map_or_else(
::std::default::Default::default,
::std::convert::From::from,
);
};
}
res
} else {
let attrs: Vec<_> = field
.attrs

View File

@ -16,7 +16,7 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[features]
compat = []
compat = ["ruma-events-macros/compat"]
markdown = ["pulldown-cmark"]
unstable-exhaustive-types = []

View File

@ -194,6 +194,10 @@ pub use self::{
unsigned::{RedactedUnsigned, Unsigned},
};
#[doc(hidden)]
#[cfg(feature = "compat")]
pub use unsigned::{RedactedUnsignedWithPrevContent, UnsignedWithPrevContent};
/// The base trait that all event content types implement.
///
/// Implementing this trait allows content types to be serialized as well as deserialized.

View File

@ -74,3 +74,50 @@ impl RedactedUnsigned {
self.redacted_because.is_none()
}
}
#[doc(hidden)]
#[cfg(feature = "compat")]
#[derive(Deserialize)]
pub struct UnsignedWithPrevContent {
#[serde(skip_serializing_if = "Option::is_none")]
age: Option<Int>,
#[serde(skip_serializing_if = "Option::is_none")]
transaction_id: Option<String>,
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
relations: Option<Relations>,
pub prev_content: Option<Box<serde_json::value::RawValue>>,
}
#[cfg(feature = "compat")]
impl From<UnsignedWithPrevContent> for Unsigned {
fn from(u: UnsignedWithPrevContent) -> Self {
Self {
age: u.age,
transaction_id: u.transaction_id,
#[cfg(feature = "unstable-pre-spec")]
relations: u.relations,
}
}
}
#[doc(hidden)]
#[cfg(feature = "compat")]
#[derive(Deserialize)]
pub struct RedactedUnsignedWithPrevContent {
#[serde(skip_serializing_if = "Option::is_none")]
redacted_because: Option<Box<SyncRedactionEvent>>,
pub prev_content: Option<Box<serde_json::value::RawValue>>,
}
#[cfg(feature = "compat")]
impl From<RedactedUnsignedWithPrevContent> for RedactedUnsigned {
fn from(u: RedactedUnsignedWithPrevContent) -> Self {
Self { redacted_because: u.redacted_because }
}
}