events: Allow customizing the unsigned type of state events
This commit is contained in:
		
							parent
							
								
									35d8bdd5a1
								
							
						
					
					
						commit
						aa8e48d1c3
					
				| @ -6,7 +6,7 @@ use super::{ | ||||
|     GlobalAccountDataEventType, HasDeserializeFields, MessageLikeEventContent, | ||||
|     MessageLikeEventType, RedactContent, RedactedEventContent, RedactedMessageLikeEventContent, | ||||
|     RedactedStateEventContent, RoomAccountDataEventContent, RoomAccountDataEventType, | ||||
|     StateEventContent, StateEventType, ToDeviceEventContent, ToDeviceEventType, | ||||
|     StateEventContent, StateEventType, StateUnsigned, ToDeviceEventContent, ToDeviceEventType, | ||||
| }; | ||||
| use crate::RoomVersionId; | ||||
| 
 | ||||
| @ -80,6 +80,7 @@ impl RedactedMessageLikeEventContent for CustomMessageLikeEventContent {} | ||||
| custom_room_event_content!(CustomStateEventContent, StateEventType); | ||||
| impl StateEventContent for CustomStateEventContent { | ||||
|     type StateKey = String; | ||||
|     type Unsigned = StateUnsigned<Self>; | ||||
| } | ||||
| impl RedactedStateEventContent for CustomStateEventContent {} | ||||
| 
 | ||||
|  | ||||
| @ -3,11 +3,11 @@ use std::fmt; | ||||
| use serde::{de::DeserializeOwned, Serialize}; | ||||
| use serde_json::value::RawValue as RawJsonValue; | ||||
| 
 | ||||
| use crate::serde::Raw; | ||||
| use crate::serde::{CanBeEmpty, Raw}; | ||||
| 
 | ||||
| use super::{ | ||||
|     EphemeralRoomEventType, GlobalAccountDataEventType, MessageLikeEventType, | ||||
|     RoomAccountDataEventType, StateEventType, ToDeviceEventType, | ||||
|     RoomAccountDataEventType, StateEventType, StateUnsignedFromParts, ToDeviceEventType, | ||||
| }; | ||||
| 
 | ||||
| /// The base trait that all event content types implement.
 | ||||
| @ -158,6 +158,9 @@ pub trait RedactedMessageLikeEventContent: MessageLikeEventContent + RedactedEve | ||||
| pub trait StateEventContent: EventContent<EventType = StateEventType> { | ||||
|     /// The type of the event's `state_key` field.
 | ||||
|     type StateKey: AsRef<str> + Clone + fmt::Debug + DeserializeOwned + Serialize; | ||||
| 
 | ||||
|     /// The type of the event's `unsigned` field.
 | ||||
|     type Unsigned: Clone + fmt::Debug + Default + CanBeEmpty + StateUnsignedFromParts + Serialize; | ||||
| } | ||||
| 
 | ||||
| /// Content of a non-redacted state event.
 | ||||
|  | ||||
| @ -9,7 +9,7 @@ use super::{ | ||||
|     GlobalAccountDataEventContent, MessageLikeEventContent, MessageLikeEventType, | ||||
|     MessageLikeUnsigned, Redact, RedactContent, RedactedMessageLikeEventContent, | ||||
|     RedactedStateEventContent, RedactedUnsigned, RedactionDeHelper, RoomAccountDataEventContent, | ||||
|     StateEventContent, StateEventType, StateUnsigned, ToDeviceEventContent, | ||||
|     StateEventContent, StateEventType, ToDeviceEventContent, | ||||
| }; | ||||
| use crate::{ | ||||
|     serde::from_raw_json_value, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, | ||||
| @ -205,7 +205,7 @@ pub struct OriginalStateEvent<C: StateEventContent> { | ||||
|     pub state_key: C::StateKey, | ||||
| 
 | ||||
|     /// Additional key-value pairs not signed by the homeserver.
 | ||||
|     pub unsigned: StateUnsigned<C>, | ||||
|     pub unsigned: C::Unsigned, | ||||
| } | ||||
| 
 | ||||
| /// An unredacted state event without a `room_id`.
 | ||||
| @ -233,7 +233,7 @@ pub struct OriginalSyncStateEvent<C: StateEventContent> { | ||||
|     pub state_key: C::StateKey, | ||||
| 
 | ||||
|     /// Additional key-value pairs not signed by the homeserver.
 | ||||
|     pub unsigned: StateUnsigned<C>, | ||||
|     pub unsigned: C::Unsigned, | ||||
| } | ||||
| 
 | ||||
| /// A stripped-down state event, used for previews of rooms the user has been invited to.
 | ||||
|  | ||||
| @ -7,7 +7,7 @@ use serde_json::value::RawValue as RawJsonValue; | ||||
| use crate::{ | ||||
|     events::{ | ||||
|         EventContent, HasDeserializeFields, RedactContent, RedactedEventContent, | ||||
|         RedactedStateEventContent, StateEventContent, StateEventType, | ||||
|         RedactedStateEventContent, StateEventContent, StateEventType, StateUnsigned, | ||||
|     }, | ||||
|     OwnedRoomAliasId, OwnedServerName, RoomVersionId, | ||||
| }; | ||||
| @ -97,6 +97,8 @@ impl EventContent for RedactedRoomAliasesEventContent { | ||||
| 
 | ||||
| impl StateEventContent for RedactedRoomAliasesEventContent { | ||||
|     type StateKey = OwnedServerName; | ||||
|     // FIXME: Not actually used
 | ||||
|     type Unsigned = StateUnsigned<Self>; | ||||
| } | ||||
| 
 | ||||
| impl RedactedStateEventContent for RedactedRoomAliasesEventContent {} | ||||
|  | ||||
| @ -11,7 +11,7 @@ use serde_json::value::RawValue as RawJsonValue; | ||||
| use crate::{ | ||||
|     events::{ | ||||
|         EventContent, HasDeserializeFields, RedactContent, RedactedEventContent, | ||||
|         RedactedStateEventContent, StateEventContent, StateEventType, | ||||
|         RedactedStateEventContent, StateEventContent, StateEventType, StateUnsigned, | ||||
|     }, | ||||
|     serde::StringEnum, | ||||
|     OwnedMxcUri, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, PrivOwnedStr, | ||||
| @ -202,6 +202,8 @@ impl EventContent for RedactedRoomMemberEventContent { | ||||
| 
 | ||||
| impl StateEventContent for RedactedRoomMemberEventContent { | ||||
|     type StateKey = OwnedUserId; | ||||
|     // FIXME: Not actually used
 | ||||
|     type Unsigned = StateUnsigned<Self>; | ||||
| } | ||||
| 
 | ||||
| impl RedactedStateEventContent for RedactedRoomMemberEventContent {} | ||||
|  | ||||
| @ -6,7 +6,7 @@ error: no event type attribute found, add `#[ruma_event(type = "any.room.event", | ||||
|   | | ||||
|   = note: this error originates in the derive macro `EventContent` (in Nightly builds, run with -Z macro-backtrace for more info) | ||||
| 
 | ||||
| error: expected one of: `type`, `kind`, `custom_redacted`, `state_key_type`, `alias` | ||||
| error: expected one of: `type`, `kind`, `custom_redacted`, `state_key_type`, `unsigned_type`, `alias` | ||||
|   --> tests/events/ui/03-invalid-event-type.rs:11:14 | ||||
|    | | ||||
| 11 | #[ruma_event(event = "m.macro.test", kind = State)] | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| //! Implementations of the EventContent derive macro.
 | ||||
| #![allow(clippy::too_many_arguments)] // FIXME
 | ||||
| 
 | ||||
| use std::borrow::Cow; | ||||
| 
 | ||||
| @ -23,6 +24,8 @@ mod kw { | ||||
|     syn::custom_keyword!(type_fragment); | ||||
|     // The type to use for a state events' `state_key` field.
 | ||||
|     syn::custom_keyword!(state_key_type); | ||||
|     // The type to use for a state events' `unsigned` field.
 | ||||
|     syn::custom_keyword!(unsigned_type); | ||||
|     // Another type string accepted for deserialization.
 | ||||
|     syn::custom_keyword!(alias); | ||||
| } | ||||
| @ -42,6 +45,8 @@ enum EventStructMeta { | ||||
| 
 | ||||
|     StateKeyType(Box<Type>), | ||||
| 
 | ||||
|     UnsignedType(Box<Type>), | ||||
| 
 | ||||
|     /// Variant that holds alternate event type accepted for deserialization.
 | ||||
|     Alias(LitStr), | ||||
| } | ||||
| @ -68,6 +73,13 @@ impl EventStructMeta { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn get_unsigned_type(&self) -> Option<&Type> { | ||||
|         match self { | ||||
|             Self::UnsignedType(ty) => Some(ty), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn get_alias(&self) -> Option<&LitStr> { | ||||
|         match self { | ||||
|             Self::Alias(t) => Some(t), | ||||
| @ -94,6 +106,10 @@ impl Parse for EventStructMeta { | ||||
|             let _: kw::state_key_type = input.parse()?; | ||||
|             let _: Token![=] = input.parse()?; | ||||
|             input.parse().map(EventStructMeta::StateKeyType) | ||||
|         } else if lookahead.peek(kw::unsigned_type) { | ||||
|             let _: kw::unsigned_type = input.parse()?; | ||||
|             let _: Token![=] = input.parse()?; | ||||
|             input.parse().map(EventStructMeta::UnsignedType) | ||||
|         } else if lookahead.peek(kw::alias) { | ||||
|             let _: kw::alias = input.parse()?; | ||||
|             let _: Token![=] = input.parse()?; | ||||
| @ -151,6 +167,10 @@ impl MetaAttrs { | ||||
|         self.0.iter().find_map(|a| a.get_state_key_type()) | ||||
|     } | ||||
| 
 | ||||
|     fn get_unsigned_type(&self) -> Option<&Type> { | ||||
|         self.0.iter().find_map(|a| a.get_unsigned_type()) | ||||
|     } | ||||
| 
 | ||||
|     fn get_aliases(&self) -> impl Iterator<Item = &LitStr> { | ||||
|         self.0.iter().filter_map(|a| a.get_alias()) | ||||
|     } | ||||
| @ -191,7 +211,7 @@ pub fn expand_event_content( | ||||
|         _ => { | ||||
|             return Err(syn::Error::new( | ||||
|                 Span::call_site(), | ||||
|                 "multiple event type attribute found, there can only be one", | ||||
|                 "multiple event type attributes found, there can only be one", | ||||
|             )); | ||||
|         } | ||||
|     }; | ||||
| @ -204,7 +224,7 @@ pub fn expand_event_content( | ||||
|         _ => { | ||||
|             return Err(syn::Error::new( | ||||
|                 Span::call_site(), | ||||
|                 "multiple event kind attribute found, there can only be one", | ||||
|                 "multiple event kind attributes found, there can only be one", | ||||
|             )); | ||||
|         } | ||||
|     }; | ||||
| @ -234,6 +254,19 @@ pub fn expand_event_content( | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let unsigned_types: Vec<_> = | ||||
|         content_attr.iter().filter_map(|attrs| attrs.get_unsigned_type()).collect(); | ||||
|     let unsigned_type = match unsigned_types.as_slice() { | ||||
|         [] => None, | ||||
|         [ty] => Some(quote! { #ty }), | ||||
|         _ => { | ||||
|             return Err(syn::Error::new( | ||||
|                 Span::call_site(), | ||||
|                 "multiple unsigned attributes found, there can only be one", | ||||
|             )); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let ident = &input.ident; | ||||
|     let fields = match &input.data { | ||||
|         syn::Data::Struct(syn::DataStruct { fields, .. }) => fields.iter(), | ||||
| @ -280,6 +313,7 @@ pub fn expand_event_content( | ||||
|             event_type, | ||||
|             event_kind, | ||||
|             state_key_type.as_ref(), | ||||
|             unsigned_type.clone(), | ||||
|             &aliases, | ||||
|             ruma_common, | ||||
|         ) | ||||
| @ -292,6 +326,7 @@ pub fn expand_event_content( | ||||
|         event_type, | ||||
|         event_kind, | ||||
|         state_key_type.as_ref(), | ||||
|         unsigned_type, | ||||
|         &aliases, | ||||
|         ruma_common, | ||||
|     ) | ||||
| @ -317,6 +352,7 @@ fn generate_redacted_event_content<'a>( | ||||
|     event_type: &LitStr, | ||||
|     event_kind: Option<EventKind>, | ||||
|     state_key_type: Option<&TokenStream>, | ||||
|     unsigned_type: Option<TokenStream>, | ||||
|     aliases: &[&LitStr], | ||||
|     ruma_common: &TokenStream, | ||||
| ) -> syn::Result<TokenStream> { | ||||
| @ -402,6 +438,7 @@ fn generate_redacted_event_content<'a>( | ||||
|         event_type, | ||||
|         event_kind, | ||||
|         state_key_type, | ||||
|         unsigned_type, | ||||
|         aliases, | ||||
|         ruma_common, | ||||
|     ) | ||||
| @ -536,6 +573,7 @@ fn generate_event_content_impl<'a>( | ||||
|     event_type: &LitStr, | ||||
|     event_kind: Option<EventKind>, | ||||
|     state_key_type: Option<&TokenStream>, | ||||
|     unsigned_type: Option<TokenStream>, | ||||
|     aliases: &[&'a LitStr], | ||||
|     ruma_common: &TokenStream, | ||||
| ) -> syn::Result<TokenStream> { | ||||
| @ -621,8 +659,12 @@ fn generate_event_content_impl<'a>( | ||||
| 
 | ||||
|         let state_event_content_impl = (event_kind == Some(EventKind::State)).then(|| { | ||||
|             assert!(state_key_type.is_some()); | ||||
|             let unsigned_type = unsigned_type | ||||
|                 .unwrap_or_else(|| quote! { #ruma_common::events::StateUnsigned<Self> }); | ||||
| 
 | ||||
|             quote! { | ||||
|                 type StateKey = #state_key_type; | ||||
|                 type Unsigned = #unsigned_type; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|  | ||||
| @ -361,8 +361,13 @@ fn expand_content_enum( | ||||
|     let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::<Vec<_>>(); | ||||
| 
 | ||||
|     let sub_trait_name = format_ident!("{kind}Content"); | ||||
|     let state_event_content_impl = | ||||
|         (kind == EventKind::State).then(|| quote! { type StateKey = String; }); | ||||
|     let state_event_content_impl = (kind == EventKind::State).then(|| { | ||||
|         quote! { | ||||
|             type StateKey = String; | ||||
|             // FIXME: Not actually used
 | ||||
|             type Unsigned = #ruma_common::events::StateUnsigned<Self>; | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     let from_impl = expand_from_impl(&ident, &content, variants); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user