Remove special handling of custom events
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
This commit is contained in:
parent
2a11207a9d
commit
539dd5f31d
@ -30,9 +30,6 @@ pub struct RumaEvent {
|
||||
/// Struct fields of the event.
|
||||
fields: Vec<Field>,
|
||||
|
||||
/// Whether or not the event type is `EventType::Custom`.
|
||||
is_custom: bool,
|
||||
|
||||
/// The kind of event.
|
||||
kind: EventKind,
|
||||
|
||||
@ -46,24 +43,18 @@ impl From<RumaEventInput> for RumaEvent {
|
||||
let name = input.name;
|
||||
let content_name = format_ident!("{}Content", name, span = Span::call_site());
|
||||
let event_type = input.event_type;
|
||||
let is_custom = is_custom_event_type(&event_type);
|
||||
|
||||
let mut fields = match kind {
|
||||
EventKind::Event => populate_event_fields(
|
||||
is_custom,
|
||||
content_name.clone(),
|
||||
input.fields.unwrap_or_else(Vec::new),
|
||||
),
|
||||
EventKind::Event => {
|
||||
populate_event_fields(content_name.clone(), input.fields.unwrap_or_else(Vec::new))
|
||||
}
|
||||
EventKind::RoomEvent => populate_room_event_fields(
|
||||
is_custom,
|
||||
content_name.clone(),
|
||||
input.fields.unwrap_or_else(Vec::new),
|
||||
),
|
||||
EventKind::StateEvent => populate_state_fields(
|
||||
is_custom,
|
||||
content_name.clone(),
|
||||
input.fields.unwrap_or_else(Vec::new),
|
||||
),
|
||||
EventKind::StateEvent => {
|
||||
populate_state_fields(content_name.clone(), input.fields.unwrap_or_else(Vec::new))
|
||||
}
|
||||
};
|
||||
|
||||
fields.sort_unstable_by_key(|field| field.ident.clone().unwrap());
|
||||
@ -74,7 +65,6 @@ impl From<RumaEventInput> for RumaEvent {
|
||||
content_name,
|
||||
event_type,
|
||||
fields,
|
||||
is_custom,
|
||||
kind,
|
||||
name,
|
||||
}
|
||||
@ -90,13 +80,8 @@ impl ToTokens for RumaEvent {
|
||||
let content_name = &self.content_name;
|
||||
let event_fields = &self.fields;
|
||||
|
||||
let event_type = if self.is_custom {
|
||||
quote! {
|
||||
::ruma_events::EventType::Custom(self.event_type.clone())
|
||||
}
|
||||
} else {
|
||||
let event_type = {
|
||||
let event_type = &self.event_type;
|
||||
|
||||
quote! {
|
||||
#event_type
|
||||
}
|
||||
@ -140,9 +125,9 @@ impl ToTokens for RumaEvent {
|
||||
Content::Typedef(_) => TokenStream::new(),
|
||||
};
|
||||
|
||||
// Custom events will already have an event_type field. All other events need to account
|
||||
// for this field being manually inserted in `Serialize` impls.
|
||||
let mut base_field_count: usize = if self.is_custom { 0 } else { 1 };
|
||||
// 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.
|
||||
@ -181,23 +166,6 @@ impl ToTokens for RumaEvent {
|
||||
serialize_field_calls.push(serialize_field_call);
|
||||
}
|
||||
|
||||
let (manually_serialize_type_field, import_event_in_serialize_impl) = if self.is_custom {
|
||||
(TokenStream::new(), TokenStream::new())
|
||||
} else {
|
||||
let manually_serialize_type_field = quote! {
|
||||
state.serialize_field("type", &self.event_type())?;
|
||||
};
|
||||
|
||||
let import_event_in_serialize_impl = quote! {
|
||||
use ::ruma_events::Event as _;
|
||||
};
|
||||
|
||||
(
|
||||
manually_serialize_type_field,
|
||||
import_event_in_serialize_impl,
|
||||
)
|
||||
};
|
||||
|
||||
let increment_struct_len_statements: Vec<TokenStream> = optional_field_idents
|
||||
.iter()
|
||||
.map(|ident| {
|
||||
@ -321,8 +289,7 @@ impl ToTokens for RumaEvent {
|
||||
S: serde::Serializer
|
||||
{
|
||||
use serde::ser::SerializeStruct as _;
|
||||
|
||||
#import_event_in_serialize_impl
|
||||
use ::ruma_events::Event as _;
|
||||
|
||||
let mut len = #base_field_count;
|
||||
|
||||
@ -331,7 +298,7 @@ impl ToTokens for RumaEvent {
|
||||
let mut state = serializer.serialize_struct(#name_str, len)?;
|
||||
|
||||
#(#serialize_field_calls)*
|
||||
#manually_serialize_type_field
|
||||
state.serialize_field("type", &self.event_type())?;
|
||||
|
||||
state.end()
|
||||
}
|
||||
@ -375,25 +342,10 @@ impl ToTokens for RumaEvent {
|
||||
}
|
||||
|
||||
/// Fills in the event's struct definition with fields common to all basic events.
|
||||
fn populate_event_fields(
|
||||
is_custom: bool,
|
||||
content_name: Ident,
|
||||
mut fields: Vec<Field>,
|
||||
) -> Vec<Field> {
|
||||
let punctuated_fields: Punctuated<ParsableNamedField, Token![,]> = if is_custom {
|
||||
parse_quote! {
|
||||
/// The event's content.
|
||||
pub content: #content_name,
|
||||
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
}
|
||||
} else {
|
||||
parse_quote! {
|
||||
/// The event's content.
|
||||
pub content: #content_name,
|
||||
}
|
||||
fn populate_event_fields(content_name: Ident, mut fields: Vec<Field>) -> Vec<Field> {
|
||||
let punctuated_fields: Punctuated<ParsableNamedField, Token![,]> = parse_quote! {
|
||||
/// The event's content.
|
||||
pub content: #content_name,
|
||||
};
|
||||
|
||||
fields.extend(punctuated_fields.into_iter().map(|p| p.field));
|
||||
@ -402,12 +354,8 @@ fn populate_event_fields(
|
||||
}
|
||||
|
||||
/// Fills in the event's struct definition with fields common to all room events.
|
||||
fn populate_room_event_fields(
|
||||
is_custom: bool,
|
||||
content_name: Ident,
|
||||
fields: Vec<Field>,
|
||||
) -> Vec<Field> {
|
||||
let mut fields = populate_event_fields(is_custom, content_name, fields);
|
||||
fn populate_room_event_fields(content_name: Ident, fields: Vec<Field>) -> Vec<Field> {
|
||||
let mut fields = populate_event_fields(content_name, fields);
|
||||
|
||||
let punctuated_fields: Punctuated<ParsableNamedField, Token![,]> = parse_quote! {
|
||||
/// The unique identifier for the event.
|
||||
@ -433,8 +381,8 @@ fn populate_room_event_fields(
|
||||
}
|
||||
|
||||
/// Fills in the event's struct definition with fields common to all state events.
|
||||
fn populate_state_fields(is_custom: bool, content_name: Ident, fields: Vec<Field>) -> Vec<Field> {
|
||||
let mut fields = populate_room_event_fields(is_custom, content_name.clone(), fields);
|
||||
fn populate_state_fields(content_name: Ident, fields: Vec<Field>) -> Vec<Field> {
|
||||
let mut fields = populate_room_event_fields(content_name.clone(), fields);
|
||||
|
||||
let punctuated_fields: Punctuated<ParsableNamedField, Token![,]> = parse_quote! {
|
||||
/// The previous content for this state key, if any.
|
||||
@ -449,11 +397,6 @@ fn populate_state_fields(is_custom: bool, content_name: Ident, fields: Vec<Field
|
||||
fields
|
||||
}
|
||||
|
||||
/// Checks if the given `Path` refers to `EventType::Custom`.
|
||||
fn is_custom_event_type(event_type: &Path) -> bool {
|
||||
event_type.segments.last().unwrap().ident == "Custom"
|
||||
}
|
||||
|
||||
/// Checks if a type is an `Option`.
|
||||
fn is_option(ty: &Type) -> bool {
|
||||
if let Type::Path(ref type_path) = ty {
|
||||
|
268
src/lib.rs
268
src/lib.rs
@ -406,53 +406,265 @@ pub trait StateEvent: RoomEvent {
|
||||
fn state_key(&self) -> &str;
|
||||
}
|
||||
|
||||
/// A basic custom event outside of the Matrix specification.
|
||||
mod custom {
|
||||
use ruma_events_macros::ruma_event;
|
||||
use super::{Event, EventType};
|
||||
|
||||
use ruma_events_macros::FromRaw;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
ruma_event! {
|
||||
/// A custom basic event not covered by the Matrix specification.
|
||||
CustomEvent {
|
||||
kind: Event,
|
||||
event_type: Custom,
|
||||
content_type_alias: {
|
||||
/// The payload for `CustomEvent`.
|
||||
Value
|
||||
},
|
||||
/// A custom event not covered by the Matrix specification.
|
||||
#[derive(Clone, Debug, FromRaw, PartialEq, Serialize)]
|
||||
pub struct CustomEvent {
|
||||
/// The event's content.
|
||||
pub content: CustomEventContent,
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
}
|
||||
|
||||
/// The payload for `CustomEvent`.
|
||||
pub type CustomEventContent = Value;
|
||||
|
||||
impl Event for CustomEvent {
|
||||
/// The type of this event's `content` field.
|
||||
type Content = CustomEventContent;
|
||||
/// The event's content.
|
||||
fn content(&self) -> &Self::Content {
|
||||
&self.content
|
||||
}
|
||||
/// The type of the event.
|
||||
fn event_type(&self) -> EventType {
|
||||
EventType::Custom(self.event_type.clone())
|
||||
}
|
||||
}
|
||||
|
||||
/// "Raw" versions of the event and its content which implement `serde::Deserialize`.
|
||||
pub mod raw {
|
||||
use super::*;
|
||||
|
||||
/// A custom event not covered by the Matrix specification.
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct CustomEvent {
|
||||
/// The event's content.
|
||||
pub content: CustomEventContent,
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod custom_room {
|
||||
use ruma_events_macros::ruma_event;
|
||||
use super::{Event, EventType, RoomEvent};
|
||||
|
||||
use ruma_events_macros::FromRaw;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
ruma_event! {
|
||||
/// A custom room event not covered by the Matrix specification.
|
||||
#[derive(Clone, Debug, FromRaw, PartialEq, Serialize)]
|
||||
pub struct CustomRoomEvent {
|
||||
/// The event's content.
|
||||
pub content: CustomRoomEventContent,
|
||||
/// The unique identifier for the event.
|
||||
pub event_id: ruma_identifiers::EventId,
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
|
||||
/// event was sent.
|
||||
pub origin_server_ts: js_int::UInt,
|
||||
/// The unique identifier for the room associated with this event.
|
||||
pub room_id: Option<ruma_identifiers::RoomId>,
|
||||
/// The unique identifier for the user who sent this event.
|
||||
pub sender: ruma_identifiers::UserId,
|
||||
/// Additional key-value pairs not signed by the homeserver.
|
||||
pub unsigned: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
/// The payload for `CustomRoomEvent`.
|
||||
pub type CustomRoomEventContent = Value;
|
||||
|
||||
impl Event for CustomRoomEvent {
|
||||
/// The type of this event's `content` field.
|
||||
type Content = CustomRoomEventContent;
|
||||
/// The event's content.
|
||||
fn content(&self) -> &Self::Content {
|
||||
&self.content
|
||||
}
|
||||
/// The type of the event.
|
||||
fn event_type(&self) -> EventType {
|
||||
EventType::Custom(self.event_type.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl RoomEvent for CustomRoomEvent {
|
||||
/// The unique identifier for the event.
|
||||
fn event_id(&self) -> &ruma_identifiers::EventId {
|
||||
&self.event_id
|
||||
}
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this event was
|
||||
/// sent.
|
||||
fn origin_server_ts(&self) -> js_int::UInt {
|
||||
self.origin_server_ts
|
||||
}
|
||||
/// The unique identifier for the room associated with this event.
|
||||
///
|
||||
/// This can be `None` if the event came from a context where there is
|
||||
/// no ambiguity which room it belongs to, like a `/sync` response for example.
|
||||
fn room_id(&self) -> Option<&ruma_identifiers::RoomId> {
|
||||
self.room_id.as_ref()
|
||||
}
|
||||
/// The unique identifier for the user who sent this event.
|
||||
fn sender(&self) -> &ruma_identifiers::UserId {
|
||||
&self.sender
|
||||
}
|
||||
/// Additional key-value pairs not signed by the homeserver.
|
||||
fn unsigned(&self) -> Option<&serde_json::Value> {
|
||||
self.unsigned.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub mod raw {
|
||||
use super::*;
|
||||
|
||||
/// A custom room event not covered by the Matrix specification.
|
||||
CustomRoomEvent {
|
||||
kind: RoomEvent,
|
||||
event_type: Custom,
|
||||
content_type_alias: {
|
||||
/// The payload for `CustomRoomEvent`.
|
||||
Value
|
||||
},
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct CustomRoomEvent {
|
||||
/// The event's content.
|
||||
pub content: CustomRoomEventContent,
|
||||
/// The unique identifier for the event.
|
||||
pub event_id: ruma_identifiers::EventId,
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
|
||||
/// event was sent.
|
||||
pub origin_server_ts: js_int::UInt,
|
||||
/// The unique identifier for the room associated with this event.
|
||||
pub room_id: Option<ruma_identifiers::RoomId>,
|
||||
/// The unique identifier for the user who sent this event.
|
||||
pub sender: ruma_identifiers::UserId,
|
||||
/// Additional key-value pairs not signed by the homeserver.
|
||||
pub unsigned: Option<serde_json::Value>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod custom_state {
|
||||
use ruma_events_macros::ruma_event;
|
||||
use super::{Event, EventType, RoomEvent, StateEvent};
|
||||
|
||||
use ruma_events_macros::FromRaw;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
ruma_event! {
|
||||
/// A custom state event not covered by the Matrix specification.
|
||||
#[derive(Clone, Debug, FromRaw, PartialEq, Serialize)]
|
||||
pub struct CustomStateEvent {
|
||||
/// The event's content.
|
||||
pub content: CustomStateEventContent,
|
||||
/// The unique identifier for the event.
|
||||
pub event_id: ruma_identifiers::EventId,
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
|
||||
/// event was sent.
|
||||
pub origin_server_ts: js_int::UInt,
|
||||
/// The previous content for this state key, if any.
|
||||
pub prev_content: Option<CustomStateEventContent>,
|
||||
/// The unique identifier for the room associated with this event.
|
||||
pub room_id: Option<ruma_identifiers::RoomId>,
|
||||
/// The unique identifier for the user who sent this event.
|
||||
pub sender: ruma_identifiers::UserId,
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
pub state_key: String,
|
||||
/// Additional key-value pairs not signed by the homeserver.
|
||||
pub unsigned: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
/// The payload for `CustomStateEvent`.
|
||||
pub type CustomStateEventContent = Value;
|
||||
|
||||
impl Event for CustomStateEvent {
|
||||
/// The type of this event's `content` field.
|
||||
type Content = CustomStateEventContent;
|
||||
/// The event's content.
|
||||
fn content(&self) -> &Self::Content {
|
||||
&self.content
|
||||
}
|
||||
/// The type of the event.
|
||||
fn event_type(&self) -> EventType {
|
||||
EventType::Custom(self.event_type.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl RoomEvent for CustomStateEvent {
|
||||
/// The unique identifier for the event.
|
||||
fn event_id(&self) -> &ruma_identifiers::EventId {
|
||||
&self.event_id
|
||||
}
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this event was
|
||||
/// sent.
|
||||
fn origin_server_ts(&self) -> js_int::UInt {
|
||||
self.origin_server_ts
|
||||
}
|
||||
/// The unique identifier for the room associated with this event.
|
||||
///
|
||||
/// This can be `None` if the event came from a context where there is
|
||||
/// no ambiguity which room it belongs to, like a `/sync` response for example.
|
||||
fn room_id(&self) -> Option<&ruma_identifiers::RoomId> {
|
||||
self.room_id.as_ref()
|
||||
}
|
||||
/// The unique identifier for the user who sent this event.
|
||||
fn sender(&self) -> &ruma_identifiers::UserId {
|
||||
&self.sender
|
||||
}
|
||||
/// Additional key-value pairs not signed by the homeserver.
|
||||
fn unsigned(&self) -> Option<&serde_json::Value> {
|
||||
self.unsigned.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl StateEvent for CustomStateEvent {
|
||||
/// The previous content for this state key, if any.
|
||||
fn prev_content(&self) -> Option<&Self::Content> {
|
||||
self.prev_content.as_ref()
|
||||
}
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
fn state_key(&self) -> &str {
|
||||
&self.state_key
|
||||
}
|
||||
}
|
||||
|
||||
pub mod raw {
|
||||
use super::*;
|
||||
|
||||
/// A custom state event not covered by the Matrix specification.
|
||||
CustomStateEvent {
|
||||
kind: StateEvent,
|
||||
event_type: Custom,
|
||||
content_type_alias: {
|
||||
/// The payload for `CustomStateEvent`.
|
||||
Value
|
||||
},
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct CustomStateEvent {
|
||||
/// The event's content.
|
||||
pub content: CustomStateEventContent,
|
||||
/// The unique identifier for the event.
|
||||
pub event_id: ruma_identifiers::EventId,
|
||||
/// The custom type of the event.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: String,
|
||||
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
|
||||
/// event was sent.
|
||||
pub origin_server_ts: js_int::UInt,
|
||||
/// The previous content for this state key, if any.
|
||||
pub prev_content: Option<CustomStateEventContent>,
|
||||
/// The unique identifier for the room associated with this event.
|
||||
pub room_id: Option<ruma_identifiers::RoomId>,
|
||||
/// The unique identifier for the user who sent this event.
|
||||
pub sender: ruma_identifiers::UserId,
|
||||
/// A key that determines which piece of room state the event represents.
|
||||
pub state_key: String,
|
||||
/// Additional key-value pairs not signed by the homeserver.
|
||||
pub unsigned: Option<serde_json::Value>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,55 +119,6 @@ mod common_case {
|
||||
}
|
||||
}
|
||||
|
||||
mod custom_event_type {
|
||||
use super::*;
|
||||
|
||||
ruma_event! {
|
||||
/// A custom event.
|
||||
CustomEvent {
|
||||
kind: Event,
|
||||
event_type: Custom,
|
||||
content_type_alias: {
|
||||
/// The payload for `CustomEvent`.
|
||||
Value
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_is_not_null() {
|
||||
// Hint: serde_json::Value with default feature is sort
|
||||
// alphabetically rather than preserve the sequence of json kv
|
||||
// pairs. Check:
|
||||
// + https://github.com/serde-rs/json/pull/80
|
||||
// + https://github.com/serde-rs/json/blob/17d9a5ea9b8e11f01b0fcf13933c4a12d3f8db45/tests/map.rs.
|
||||
let event = CustomEvent {
|
||||
content: { serde_json::from_str::<Value>(r#"{"alice":["foo", "bar"]}"#).unwrap() },
|
||||
event_type: "foo.bar".to_owned(),
|
||||
};
|
||||
let json = json!({
|
||||
"content": {
|
||||
"alice": ["foo", "bar"]
|
||||
},
|
||||
"type": "foo.bar"
|
||||
});
|
||||
serde_json_eq_try_from_raw(event, json);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_is_null() {
|
||||
let event = CustomEvent {
|
||||
content: { Value::Null },
|
||||
event_type: "foo.bar".to_owned(),
|
||||
};
|
||||
let json = json!({
|
||||
"content": null,
|
||||
"type": "foo.bar"
|
||||
});
|
||||
serde_json_eq_try_from_raw(event, json);
|
||||
}
|
||||
}
|
||||
|
||||
mod extra_fields {
|
||||
use super::*;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user