macros: Finish support for variable event types

This commit is contained in:
Jonas Platte 2022-03-22 19:22:22 +01:00 committed by Jonas Platte
parent 316d1423e8
commit 7fbb28f223
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
8 changed files with 140 additions and 35 deletions

View File

@ -86,8 +86,8 @@ pub mod v3 {
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
let room_id_percent = utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC); let room_id_percent = utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC);
let event_type_percent = let event_type = self.event_type.to_string();
utf8_percent_encode(self.event_type.as_str(), NON_ALPHANUMERIC); let event_type_percent = utf8_percent_encode(&event_type, NON_ALPHANUMERIC);
let mut url = format!( let mut url = format!(
"{}{}", "{}{}",

View File

@ -114,8 +114,8 @@ pub mod v3 {
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
let room_id_percent = utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC); let room_id_percent = utf8_percent_encode(self.room_id.as_str(), NON_ALPHANUMERIC);
let event_type_percent = let event_type = self.event_type.to_string();
utf8_percent_encode(self.event_type.as_str(), NON_ALPHANUMERIC); let event_type_percent = utf8_percent_encode(&event_type, NON_ALPHANUMERIC);
let mut url = format!( let mut url = format!(
"{}{}", "{}{}",

View File

@ -306,7 +306,7 @@ fn alias_event_field_access() {
} else { } else {
panic!("the `Any*Event` enum's accessor methods may have been altered") panic!("the `Any*Event` enum's accessor methods may have been altered")
} }
assert_eq!(deser.event_type().as_str(), "m.room.aliases"); assert_eq!(deser.event_type().to_string(), "m.room.aliases");
} }
#[test] #[test]

View File

@ -12,7 +12,7 @@ fn main() {
use ruma_common::events::EventContent; use ruma_common::events::EventContent;
assert_eq!( assert_eq!(
MacroTestContent { frag: "foo".to_owned() }.event_type().as_str(), MacroTestContent { frag: "foo".to_owned() }.event_type().to_string(),
"m.macro.test.foo" "m.macro.test.foo"
); );
} }

View File

@ -119,14 +119,13 @@ fn expand_serialize_event(
{ {
use #serde::ser::{SerializeStruct as _, Error as _}; use #serde::ser::{SerializeStruct as _, Error as _};
let event_type = #ruma_common::events::EventContent::event_type(&self.content);
let event_type =
::std::convert::AsRef::<::std::primitive::str>::as_ref(&event_type);
let mut state = serializer.serialize_struct(stringify!(#ident), 7)?; let mut state = serializer.serialize_struct(stringify!(#ident), 7)?;
state.serialize_field("type", event_type)?; let event_type = #ruma_common::events::EventContent::event_type(&self.content);
state.serialize_field("type", &event_type)?;
#( #serialize_fields )* #( #serialize_fields )*
state.end() state.end()
} }
} }

View File

@ -474,9 +474,13 @@ fn generate_event_content_impl<'a>(
ty: ::std::option::Option<crate::PrivOwnedStr>, ty: ::std::option::Option<crate::PrivOwnedStr>,
} }
impl ::std::convert::AsRef<::std::primitive::str> for #i { impl #serde::Serialize for #i {
fn as_ref(&self) -> &::std::primitive::str { fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
self.ty.as_ref().map(|t| &t.0[..]).unwrap_or(#event_type) where
S: #serde::Serializer,
{
let s = self.ty.as_ref().map(|t| &t.0[..]).unwrap_or(#event_type);
serializer.serialize_str(s)
} }
} }
}); });

View File

@ -240,7 +240,7 @@ fn expand_into_full_event(
/// Create a content enum from `EventEnumInput`. /// Create a content enum from `EventEnumInput`.
fn expand_content_enum( fn expand_content_enum(
kind: EventKind, kind: EventKind,
events: &[LitStr], event_types: &[LitStr],
attrs: &[Attribute], attrs: &[Attribute],
variants: &[EventEnumVariant], variants: &[EventEnumVariant],
ruma_common: &TokenStream, ruma_common: &TokenStream,
@ -251,13 +251,18 @@ fn expand_content_enum(
let ident = kind.to_content_enum(); let ident = kind.to_content_enum();
let event_type_enum = kind.to_event_type_enum(); let event_type_enum = kind.to_event_type_enum();
let event_type_str = events;
let content: Vec<_> = let content: Vec<_> =
events.iter().map(|ev| to_event_content_path(kind, ev, None, ruma_common)).collect(); event_types.iter().map(|ev| to_event_content_path(kind, ev, None, ruma_common)).collect();
let event_type_match_arms = event_types.iter().map(|s| {
if let Some(prefix) = s.value().strip_suffix(".*") {
quote! { _s if _s.starts_with(#prefix) }
} else {
quote! { #s }
}
});
let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>(); let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>();
let variant_attrs = variants.iter().map(|v| { let variant_attrs = variants.iter().map(|v| {
let attrs = &v.attrs; let attrs = &v.attrs;
quote! { #(#attrs)* } quote! { #(#attrs)* }
@ -278,7 +283,7 @@ fn expand_content_enum(
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident { pub enum #ident {
#( #(
#[doc = #event_type_str] #[doc = #event_types]
#variant_decls(#content), #variant_decls(#content),
)* )*
#[doc(hidden)] #[doc(hidden)]
@ -305,7 +310,7 @@ fn expand_content_enum(
) -> #serde_json::Result<Self> { ) -> #serde_json::Result<Self> {
match event_type { match event_type {
#( #(
#variant_attrs #event_type_str => { #variant_attrs #event_type_match_arms => {
let content = #content::from_parts(event_type, input)?; let content = #content::from_parts(event_type, input)?;
::std::result::Result::Ok(#variant_ctors(content)) ::std::result::Result::Ok(#variant_ctors(content))
} }
@ -434,7 +439,9 @@ fn expand_accessor_methods(
event.unsigned._map_prev_unsigned(|c| #content_enum::_Custom { event.unsigned._map_prev_unsigned(|c| #content_enum::_Custom {
event_type: crate::PrivOwnedStr( event_type: crate::PrivOwnedStr(
::std::convert::From::from( ::std::convert::From::from(
#ruma_common::events::EventContent::event_type(c).as_str() ::std::string::ToString::to_string(
&#ruma_common::events::EventContent::event_type(c)
)
), ),
), ),
}) })
@ -467,8 +474,9 @@ fn expand_accessor_methods(
Self::_Custom(event) => #content_enum::_Custom { Self::_Custom(event) => #content_enum::_Custom {
event_type: crate::PrivOwnedStr( event_type: crate::PrivOwnedStr(
::std::convert::From::from( ::std::convert::From::from(
#ruma_common::events::EventContent::event_type(&event.content) ::std::string::ToString::to_string(
.as_str(), &#ruma_common::events::EventContent::event_type(&event.content)
)
), ),
), ),
}, },
@ -627,9 +635,14 @@ impl EventEnumVariant {
} }
impl EventEnumEntry { impl EventEnumEntry {
pub(crate) fn has_type_fragment(&self) -> bool {
self.ev_type.value().ends_with(".*")
}
pub(crate) fn to_variant(&self) -> syn::Result<EventEnumVariant> { pub(crate) fn to_variant(&self) -> syn::Result<EventEnumVariant> {
let attrs = self.attrs.clone(); let attrs = self.attrs.clone();
let ident = m_prefix_name_to_type_name(&self.ev_type)?; let ident = m_prefix_name_to_type_name(&self.ev_type)?;
Ok(EventEnumVariant { attrs, ident }) Ok(EventEnumVariant { attrs, ident })
} }
} }

View File

@ -61,8 +61,7 @@ fn generate_enum(
input: &[&Vec<EventEnumEntry>], input: &[&Vec<EventEnumEntry>],
ruma_common: &TokenStream, ruma_common: &TokenStream,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let str_doc = format!("Creates a string slice from this `{}`.", ident); let serde = quote! { #ruma_common::exports::serde };
let byte_doc = format!("Creates a byte slice from this `{}`.", ident);
let enum_doc = format!("The type of `{}` this is.", ident.strip_suffix("Type").unwrap()); let enum_doc = format!("The type of `{}` this is.", ident.strip_suffix("Type").unwrap());
let deprecated_attr = (ident == "EventType").then(|| { let deprecated_attr = (ident == "EventType").then(|| {
@ -86,8 +85,57 @@ fn generate_enum(
} }
let event_types = deduped.iter().map(|e| &e.ev_type); let event_types = deduped.iter().map(|e| &e.ev_type);
let variants =
deduped.iter().map(|e| Ok(e.to_variant()?.decl())).collect::<syn::Result<Vec<_>>>()?; let variants: Vec<_> = deduped
.iter()
.map(|e| {
let start = e.to_variant()?.decl();
let data = e.has_type_fragment().then(|| quote! { (::std::string::String) });
Ok(quote! {
#start #data
})
})
.collect::<syn::Result<_>>()?;
let to_cow_str_match_arms: Vec<_> = deduped
.iter()
.map(|e| {
let v = e.to_variant()?;
let start = v.match_arm(quote! { Self });
let ev_type = &e.ev_type;
Ok(if let Some(prefix) = ev_type.value().strip_suffix(".*") {
let fstr = prefix.to_owned() + "{}";
quote! { #start(_s) => ::std::borrow::Cow::Owned(::std::format!(#fstr, _s)) }
} else {
quote! { #start => ::std::borrow::Cow::Borrowed(#ev_type) }
})
})
.collect::<syn::Result<_>>()?;
let from_str_match_arms: Vec<_> = deduped
.iter()
.map(|e| {
let v = e.to_variant()?;
let ctor = v.ctor(quote! { Self });
let match_arm = if let Some(prefix) = e.ev_type.value().strip_suffix('*') {
quote! {
// Use if-let guard once available
_s if _s.starts_with(#prefix) => {
#ctor(::std::convert::From::from(_s.strip_prefix(#prefix).unwrap()))
}
}
} else {
let t = &e.ev_type;
quote! { #t => #ctor }
};
let attrs = &e.attrs;
Ok(quote! { #(#attrs)* #match_arm })
})
.collect::<syn::Result<_>>()?;
Ok(quote! { Ok(quote! {
#[doc = #enum_doc] #[doc = #enum_doc]
@ -95,12 +143,11 @@ fn generate_enum(
/// This type can hold an arbitrary string. To check for events that are not available as a /// This type can hold an arbitrary string. To check for events that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`. /// documented variant here, use its string representation, obtained through `.as_str()`.
#deprecated_attr #deprecated_attr
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, #ruma_common::serde::StringEnum)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident { pub enum #ident {
#( #(
#[doc = #event_types] #[doc = #event_types]
#[ruma_enum(rename = #event_types)]
#variants, #variants,
)* )*
#[doc(hidden)] #[doc(hidden)]
@ -109,14 +156,56 @@ fn generate_enum(
#[allow(deprecated)] #[allow(deprecated)]
impl #ident { impl #ident {
#[doc = #str_doc] fn to_cow_str(&self) -> ::std::borrow::Cow<'_, ::std::primitive::str> {
pub fn as_str(&self) -> &str { match self {
self.as_ref() #(#to_cow_str_match_arms,)*
Self::_Custom(crate::PrivOwnedStr(s)) => ::std::borrow::Cow::Borrowed(s),
}
}
} }
#[doc = #byte_doc] #[allow(deprecated)]
pub fn as_bytes(&self) -> &[u8] { impl ::std::fmt::Display for #ident {
self.as_str().as_bytes() fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
self.to_cow_str().fmt(f)
}
}
#[allow(deprecated)]
impl ::std::convert::From<&::std::primitive::str> for #ident {
fn from(s: &::std::primitive::str) -> Self {
match s {
#(#from_str_match_arms,)*
_ => Self::_Custom(crate::PrivOwnedStr(::std::convert::From::from(s))),
}
}
}
#[allow(deprecated)]
impl ::std::convert::From<::std::string::String> for #ident {
fn from(s: ::std::string::String) -> Self {
::std::convert::From::from(s.as_str())
}
}
#[allow(deprecated)]
impl<'de> #serde::Deserialize<'de> for #ident {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: #serde::Deserializer<'de>
{
let s = #ruma_common::serde::deserialize_cow_str(deserializer)?;
Ok(::std::convert::From::from(&s[..]))
}
}
#[allow(deprecated)]
impl #serde::Serialize for #ident {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where
S: #serde::Serializer,
{
self.to_cow_str().serialize(serializer)
} }
} }
}) })