Remove manual Serialize impl, use derive macro instead
This commit is contained in:
parent
8ea971b082
commit
f09ab98f17
@ -6,7 +6,7 @@ use syn::{
|
|||||||
parse_quote,
|
parse_quote,
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
Attribute, Field, Ident, LitStr, Token, Type,
|
Attribute, Field, Ident, LitStr, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::parse::{Content, EventKind, RumaEventInput};
|
use crate::parse::{Content, EventKind, RumaEventInput};
|
||||||
@ -89,7 +89,6 @@ impl ToTokens for RumaEvent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let name = &self.name;
|
let name = &self.name;
|
||||||
let name_str = format!("{}", name);
|
|
||||||
let content_docstring = format!("The payload for `{}`.", name);
|
let content_docstring = format!("The payload for `{}`.", name);
|
||||||
|
|
||||||
let content = match &self.content {
|
let content = match &self.content {
|
||||||
@ -126,60 +125,6 @@ impl ToTokens for RumaEvent {
|
|||||||
Content::Typedef(_) => TokenStream::new(),
|
Content::Typedef(_) => TokenStream::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only custom events will already have an event_type field, since we don't handle
|
|
||||||
// custom events we start at one.
|
|
||||||
let mut base_field_count: usize = 1;
|
|
||||||
|
|
||||||
// Keep track of all the optional fields, because we'll need to check at runtime if they
|
|
||||||
// are `Some` in order to increase the number of fields we tell serde to serialize.
|
|
||||||
let mut optional_field_idents = Vec::with_capacity(event_fields.len());
|
|
||||||
|
|
||||||
let mut serialize_field_calls: Vec<TokenStream> = Vec::with_capacity(event_fields.len());
|
|
||||||
|
|
||||||
for field in event_fields {
|
|
||||||
let ident = field.ident.clone().unwrap();
|
|
||||||
|
|
||||||
let ident_str = if ident == "event_type" {
|
|
||||||
"type".to_string()
|
|
||||||
} else {
|
|
||||||
format!("{}", ident)
|
|
||||||
};
|
|
||||||
|
|
||||||
let span = field.span();
|
|
||||||
|
|
||||||
// Does the same thing as #[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
let serialize_field_call = if is_option(&field.ty) {
|
|
||||||
optional_field_idents.push(ident.clone());
|
|
||||||
|
|
||||||
quote_spanned! {span=>
|
|
||||||
if self.#ident.is_some() {
|
|
||||||
state.serialize_field(#ident_str, &self.#ident)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
base_field_count += 1;
|
|
||||||
|
|
||||||
quote_spanned! {span=>
|
|
||||||
state.serialize_field(#ident_str, &self.#ident)?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
serialize_field_calls.push(serialize_field_call);
|
|
||||||
}
|
|
||||||
|
|
||||||
let increment_struct_len_statements: Vec<TokenStream> = optional_field_idents
|
|
||||||
.iter()
|
|
||||||
.map(|ident| {
|
|
||||||
let span = ident.span();
|
|
||||||
|
|
||||||
quote_spanned! {span=>
|
|
||||||
if self.#ident.is_some() {
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let impl_room_event = match self.kind {
|
let impl_room_event = match self.kind {
|
||||||
EventKind::RoomEvent | EventKind::StateEvent => {
|
EventKind::RoomEvent | EventKind::StateEvent => {
|
||||||
quote! {
|
quote! {
|
||||||
@ -269,42 +214,19 @@ impl ToTokens for RumaEvent {
|
|||||||
TokenStream::new()
|
TokenStream::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let stripped_fields = event_fields
|
let event_type_name = self.event_type.value();
|
||||||
.iter()
|
|
||||||
.map(|event_field| strip_serde_attrs(event_field));
|
|
||||||
|
|
||||||
let output = quote!(
|
let output = quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#[derive(Clone, PartialEq, Debug, ruma_events_macros::FromRaw)]
|
#[derive(Clone, PartialEq, Debug, serde::Serialize, ruma_events_macros::FromRaw)]
|
||||||
|
#[serde(rename = #event_type_name, tag = "type")]
|
||||||
pub struct #name {
|
pub struct #name {
|
||||||
#(#stripped_fields),*
|
#(#event_fields),*
|
||||||
}
|
}
|
||||||
|
|
||||||
#content
|
#content
|
||||||
|
|
||||||
#impl_event_result_compatible_for_content
|
#impl_event_result_compatible_for_content
|
||||||
|
|
||||||
impl serde::Serialize for #name {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer
|
|
||||||
{
|
|
||||||
use serde::ser::SerializeStruct as _;
|
|
||||||
use ::ruma_events::Event as _;
|
|
||||||
|
|
||||||
let mut len = #base_field_count;
|
|
||||||
|
|
||||||
#(#increment_struct_len_statements)*
|
|
||||||
|
|
||||||
let mut state = serializer.serialize_struct(#name_str, len)?;
|
|
||||||
|
|
||||||
#(#serialize_field_calls)*
|
|
||||||
state.serialize_field("type", &self.event_type())?;
|
|
||||||
|
|
||||||
state.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::ruma_events::Event for #name {
|
impl ::ruma_events::Event for #name {
|
||||||
/// The type of this event's `content` field.
|
/// The type of this event's `content` field.
|
||||||
type Content = #content_name;
|
type Content = #content_name;
|
||||||
@ -367,12 +289,14 @@ fn populate_room_event_fields(content_name: Ident, fields: Vec<Field>) -> Vec<Fi
|
|||||||
pub origin_server_ts: js_int::UInt,
|
pub origin_server_ts: js_int::UInt,
|
||||||
|
|
||||||
/// The unique identifier for the room associated with this event.
|
/// The unique identifier for the room associated with this event.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub room_id: Option<ruma_identifiers::RoomId>,
|
pub room_id: Option<ruma_identifiers::RoomId>,
|
||||||
|
|
||||||
/// The unique identifier for the user who sent this event.
|
/// The unique identifier for the user who sent this event.
|
||||||
pub sender: ruma_identifiers::UserId,
|
pub sender: ruma_identifiers::UserId,
|
||||||
|
|
||||||
/// Additional key-value pairs not signed by the homeserver.
|
/// Additional key-value pairs not signed by the homeserver.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub unsigned: Option<serde_json::Value>,
|
pub unsigned: Option<serde_json::Value>,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -387,6 +311,7 @@ fn populate_state_fields(content_name: Ident, fields: Vec<Field>) -> Vec<Field>
|
|||||||
|
|
||||||
let punctuated_fields: Punctuated<ParsableNamedField, Token![,]> = parse_quote! {
|
let punctuated_fields: Punctuated<ParsableNamedField, Token![,]> = parse_quote! {
|
||||||
/// The previous content for this state key, if any.
|
/// The previous content for this state key, if any.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub prev_content: Option<#content_name>,
|
pub prev_content: Option<#content_name>,
|
||||||
|
|
||||||
/// A key that determines which piece of room state the event represents.
|
/// A key that determines which piece of room state the event represents.
|
||||||
@ -398,15 +323,6 @@ fn populate_state_fields(content_name: Ident, fields: Vec<Field>) -> Vec<Field>
|
|||||||
fields
|
fields
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a type is an `Option`.
|
|
||||||
fn is_option(ty: &Type) -> bool {
|
|
||||||
if let Type::Path(ref type_path) = ty {
|
|
||||||
type_path.path.segments.first().unwrap().ident == "Option"
|
|
||||||
} else {
|
|
||||||
panic!("struct field had unexpected non-path type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Splits the given `event_type` string on `.` and `_` removing the `m.` then
|
/// Splits the given `event_type` string on `.` and `_` removing the `m.` then
|
||||||
/// camel casing to give the `EventType` variant.
|
/// camel casing to give the `EventType` variant.
|
||||||
fn to_camel_case(name: String) -> String {
|
fn to_camel_case(name: String) -> String {
|
||||||
@ -433,10 +349,3 @@ impl Parse for ParsableNamedField {
|
|||||||
Ok(Self { field })
|
Ok(Self { field })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes `serde` attributes from struct fields.
|
|
||||||
pub fn strip_serde_attrs(field: &Field) -> Field {
|
|
||||||
let mut field = field.clone();
|
|
||||||
field.attrs.retain(|attr| !attr.path.is_ident("serde"));
|
|
||||||
field
|
|
||||||
}
|
|
||||||
|
@ -43,7 +43,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string(&event).unwrap(),
|
to_string(&event).unwrap(),
|
||||||
format!(
|
format!(
|
||||||
r#"{{"content":{{"{}":["{}"]}},"type":"m.direct"}}"#,
|
r#"{{"type":"m.direct","content":{{"{}":["{}"]}}}}"#,
|
||||||
alice.to_string(),
|
alice.to_string(),
|
||||||
room[0].to_string()
|
room[0].to_string()
|
||||||
)
|
)
|
||||||
@ -60,8 +60,8 @@ mod tests {
|
|||||||
|
|
||||||
let json_data = format!(
|
let json_data = format!(
|
||||||
r#"{{
|
r#"{{
|
||||||
"content": {{ "{}": ["{}", "{}"] }},
|
"type": "m.direct",
|
||||||
"type": "m.direct"
|
"content": {{ "{}": ["{}", "{}"] }}
|
||||||
}}"#,
|
}}"#,
|
||||||
alice.to_string(),
|
alice.to_string(),
|
||||||
rooms[0].to_string(),
|
rooms[0].to_string(),
|
||||||
|
@ -34,7 +34,7 @@ mod tests {
|
|||||||
let dummy_event = DummyEvent { content: Empty };
|
let dummy_event = DummyEvent { content: Empty };
|
||||||
|
|
||||||
let actual = serde_json::to_string(&dummy_event).unwrap();
|
let actual = serde_json::to_string(&dummy_event).unwrap();
|
||||||
let expected = r#"{"content":{},"type":"m.dummy"}"#;
|
let expected = r#"{"type":"m.dummy","content":{}}"#;
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ mod tests {
|
|||||||
sender: UserId::try_from("@example:localhost").unwrap(),
|
sender: UserId::try_from("@example:localhost").unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = r#"{"content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"sender":"@example:localhost","type":"m.presence"}"#;
|
let json = r#"{"type":"m.presence","content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"sender":"@example:localhost"}"#;
|
||||||
|
|
||||||
assert_eq!(to_string(&event).unwrap(), json);
|
assert_eq!(to_string(&event).unwrap(), json);
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ mod tests {
|
|||||||
sender: UserId::try_from("@example:localhost").unwrap(),
|
sender: UserId::try_from("@example:localhost").unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = r#"{"content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"sender":"@example:localhost","type":"m.presence"}"#;
|
let json = r#"{"type":"m.presence","content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"sender":"@example:localhost"}"#;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serde_json::from_str::<EventResult<PresenceEvent>>(json)
|
serde_json::from_str::<EventResult<PresenceEvent>>(json)
|
||||||
|
@ -249,6 +249,7 @@ mod tests {
|
|||||||
prev_content: None,
|
prev_content: None,
|
||||||
};
|
};
|
||||||
let json = json!({
|
let json = json!({
|
||||||
|
"type": "m.room.member",
|
||||||
"content": {
|
"content": {
|
||||||
"membership": "join"
|
"membership": "join"
|
||||||
},
|
},
|
||||||
@ -256,8 +257,7 @@ mod tests {
|
|||||||
"origin_server_ts": 1,
|
"origin_server_ts": 1,
|
||||||
"room_id": "!n8f893n9:example.com",
|
"room_id": "!n8f893n9:example.com",
|
||||||
"sender": "@carl:example.com",
|
"sender": "@carl:example.com",
|
||||||
"state_key": "example.com",
|
"state_key": "example.com"
|
||||||
"type": "m.room.member"
|
|
||||||
});
|
});
|
||||||
serde_json_eq_try_from_raw(event, json);
|
serde_json_eq_try_from_raw(event, json);
|
||||||
}
|
}
|
||||||
@ -287,6 +287,7 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let json = json!({
|
let json = json!({
|
||||||
|
"type": "m.room.member",
|
||||||
"content": {
|
"content": {
|
||||||
"membership": "join"
|
"membership": "join"
|
||||||
},
|
},
|
||||||
@ -297,8 +298,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
"room_id": "!n8f893n9:example.com",
|
"room_id": "!n8f893n9:example.com",
|
||||||
"sender": "@carl:example.com",
|
"sender": "@carl:example.com",
|
||||||
"state_key": "example.com",
|
"state_key": "example.com"
|
||||||
"type": "m.room.member"
|
|
||||||
});
|
});
|
||||||
serde_json_eq_try_from_raw(event, json);
|
serde_json_eq_try_from_raw(event, json);
|
||||||
}
|
}
|
||||||
@ -337,6 +337,7 @@ mod tests {
|
|||||||
prev_content: None,
|
prev_content: None,
|
||||||
};
|
};
|
||||||
let json = json!({
|
let json = json!({
|
||||||
|
"type": "m.room.member",
|
||||||
"content": {
|
"content": {
|
||||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||||
"displayname": "Alice Margatroid",
|
"displayname": "Alice Margatroid",
|
||||||
@ -359,8 +360,7 @@ mod tests {
|
|||||||
"origin_server_ts":233,
|
"origin_server_ts":233,
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@alice:example.org",
|
"sender": "@alice:example.org",
|
||||||
"state_key": "@alice:example.org",
|
"state_key": "@alice:example.org"
|
||||||
"type": "m.room.member"
|
|
||||||
});
|
});
|
||||||
serde_json_eq_try_from_raw(event, json);
|
serde_json_eq_try_from_raw(event, json);
|
||||||
}
|
}
|
||||||
@ -405,6 +405,7 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
let json = json!({
|
let json = json!({
|
||||||
|
"type": "m.room.member",
|
||||||
"content": {
|
"content": {
|
||||||
"membership": "join"
|
"membership": "join"
|
||||||
},
|
},
|
||||||
@ -430,8 +431,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
"sender": "@alice:example.org",
|
"sender": "@alice:example.org",
|
||||||
"state_key": "@alice:example.org",
|
"state_key": "@alice:example.org"
|
||||||
"type": "m.room.member"
|
|
||||||
});
|
});
|
||||||
serde_json_eq_try_from_raw(event, json);
|
serde_json_eq_try_from_raw(event, json);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user