Optimize event enum deserialization

Criterion reports ~25% improved performance
This commit is contained in:
Jonas Platte 2020-06-16 00:29:00 +02:00
parent 0381190bdb
commit f2f283c965
No known key found for this signature in database
GPG Key ID: 7D261D771D915378

View File

@ -1,9 +1,9 @@
use ruma_events_macros::event_content_enum; use ruma_events_macros::event_content_enum;
use serde::{ use serde::{
de::{self, Error as _}, de::{self, DeserializeOwned, Error as _},
Serialize, Deserialize, Serialize,
}; };
use serde_json::{from_value as from_json_value, Value as JsonValue}; use serde_json::value::RawValue as RawJsonValue;
use crate::{ use crate::{
event_kinds::{ event_kinds::{
@ -12,7 +12,6 @@ use crate::{
}, },
presence::PresenceEvent, presence::PresenceEvent,
room::redaction::{RedactionEvent, RedactionEventStub}, room::redaction::{RedactionEvent, RedactionEventStub},
util,
}; };
event_content_enum! { event_content_enum! {
@ -162,6 +161,20 @@ pub enum AnyRoomEventStub {
State(AnyStateEventStub), State(AnyStateEventStub),
} }
#[derive(Deserialize)]
struct EventDeHelper {
#[serde(rename = "type")]
ev_type: String,
}
fn from_raw_json_value<T, E>(val: &RawJsonValue) -> Result<T, E>
where
T: DeserializeOwned,
E: de::Error,
{
serde_json::from_str(val.get()).map_err(E::custom)
}
// FIXME `#[serde(untagged)]` deserialization fails for these enums which // FIXME `#[serde(untagged)]` deserialization fails for these enums which
// is odd as we are doing basically the same thing here, investigate? // is odd as we are doing basically the same thing here, investigate?
impl<'de> de::Deserialize<'de> for AnyEvent { impl<'de> de::Deserialize<'de> for AnyEvent {
@ -169,27 +182,23 @@ impl<'de> de::Deserialize<'de> for AnyEvent {
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
{ {
let json = JsonValue::deserialize(deserializer)?; let json = <&RawJsonValue>::deserialize(deserializer)?;
let ev_type: String = util::get_field(&json, "type")?; let EventDeHelper { ev_type } = from_raw_json_value(json)?;
match ev_type.as_str() { match ev_type.as_str() {
"m.room.redaction" => { "m.room.redaction" => Ok(AnyEvent::Redaction(from_raw_json_value(json)?)),
Ok(AnyEvent::Redaction(from_json_value(json).map_err(D::Error::custom)?)) "m.presence" => Ok(AnyEvent::Presence(from_raw_json_value(json)?)),
}
"m.presence" => {
Ok(AnyEvent::Presence(from_json_value(json).map_err(D::Error::custom)?))
}
ev_type if AnyBasicEventContent::is_compatible(ev_type) => { ev_type if AnyBasicEventContent::is_compatible(ev_type) => {
Ok(AnyEvent::Basic(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyEvent::Basic(from_raw_json_value(json)?))
} }
ev_type if AnyEphemeralRoomEventContent::is_compatible(ev_type) => { ev_type if AnyEphemeralRoomEventContent::is_compatible(ev_type) => {
Ok(AnyEvent::Ephemeral(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyEvent::Ephemeral(from_raw_json_value(json)?))
} }
ev_type if AnyMessageEventContent::is_compatible(ev_type) => { ev_type if AnyMessageEventContent::is_compatible(ev_type) => {
Ok(AnyEvent::Message(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyEvent::Message(from_raw_json_value(json)?))
} }
ev_type if AnyStateEventContent::is_compatible(ev_type) => { ev_type if AnyStateEventContent::is_compatible(ev_type) => {
Ok(AnyEvent::State(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyEvent::State(from_raw_json_value(json)?))
} }
_ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))), _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))),
} }
@ -201,18 +210,16 @@ impl<'de> de::Deserialize<'de> for AnyRoomEvent {
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
{ {
let json = JsonValue::deserialize(deserializer)?; let json = <&RawJsonValue>::deserialize(deserializer)?;
let ev_type: String = util::get_field(&json, "type")?; let EventDeHelper { ev_type } = from_raw_json_value(json)?;
match ev_type.as_str() { match ev_type.as_str() {
"m.room.redaction" => { "m.room.redaction" => Ok(AnyRoomEvent::Redaction(from_raw_json_value(json)?)),
Ok(AnyRoomEvent::Redaction(from_json_value(json).map_err(D::Error::custom)?))
}
ev_type if AnyMessageEventContent::is_compatible(ev_type) => { ev_type if AnyMessageEventContent::is_compatible(ev_type) => {
Ok(AnyRoomEvent::Message(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyRoomEvent::Message(from_raw_json_value(json)?))
} }
ev_type if AnyStateEventContent::is_compatible(ev_type) => { ev_type if AnyStateEventContent::is_compatible(ev_type) => {
Ok(AnyRoomEvent::State(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyRoomEvent::State(from_raw_json_value(json)?))
} }
_ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))), _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))),
} }
@ -224,18 +231,16 @@ impl<'de> de::Deserialize<'de> for AnyRoomEventStub {
where where
D: de::Deserializer<'de>, D: de::Deserializer<'de>,
{ {
let json = JsonValue::deserialize(deserializer)?; let json = <&RawJsonValue>::deserialize(deserializer)?;
let ev_type: String = util::get_field(&json, "type")?; let EventDeHelper { ev_type } = from_raw_json_value(json)?;
match ev_type.as_str() { match ev_type.as_str() {
"m.room.redaction" => { "m.room.redaction" => Ok(AnyRoomEventStub::Redaction(from_raw_json_value(json)?)),
Ok(AnyRoomEventStub::Redaction(from_json_value(json).map_err(D::Error::custom)?))
}
ev_type if AnyMessageEventContent::is_compatible(ev_type) => { ev_type if AnyMessageEventContent::is_compatible(ev_type) => {
Ok(AnyRoomEventStub::Message(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyRoomEventStub::Message(from_raw_json_value(json)?))
} }
ev_type if AnyStateEventContent::is_compatible(ev_type) => { ev_type if AnyStateEventContent::is_compatible(ev_type) => {
Ok(AnyRoomEventStub::State(from_json_value(json).map_err(D::Error::custom)?)) Ok(AnyRoomEventStub::State(from_raw_json_value(json)?))
} }
_ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))), _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))),
} }