diff --git a/ruma-api-macros/src/api.rs b/ruma-api-macros/src/api.rs index 15484dc6..9865845e 100644 --- a/ruma-api-macros/src/api.rs +++ b/ruma-api-macros/src/api.rs @@ -170,7 +170,10 @@ impl ToTokens for Api { TokenStream::new() }; quote! { - let request_body: ::Incoming = + let request_body: < + RequestBody #body_lifetimes + as #ruma_api_import::exports::ruma_common::Outgoing + >::Incoming = #ruma_api_import::try_deserialize!( request, #ruma_api_import::exports::serde_json::from_slice(request.body().as_slice()) @@ -202,7 +205,10 @@ impl ToTokens for Api { || self.response.newtype_body_field().is_some() { quote! { - let response_body: ::Incoming = + let response_body: < + ResponseBody + as #ruma_api_import::exports::ruma_common::Outgoing + >::Incoming = #ruma_api_import::try_deserialize!( response, #ruma_api_import::exports::serde_json::from_slice(response.body().as_slice()), @@ -328,7 +334,8 @@ impl ToTokens for Api { for Request #request_lifetimes { type EndpointError = #error; - type IncomingResponse = ::Incoming; + type IncomingResponse = + ::Incoming; #[doc = #metadata_doc] const METADATA: #ruma_api_import::Metadata = __METADATA; diff --git a/ruma-api-macros/src/api/request.rs b/ruma-api-macros/src/api/request.rs index 5f31f18b..ba80a7c1 100644 --- a/ruma-api-macros/src/api/request.rs +++ b/ruma-api-macros/src/api/request.rs @@ -470,7 +470,7 @@ impl ToTokens for Request { /// Data in the request body. #[derive( Debug, - #import_path::Outgoing, + #import_path::exports::ruma_common::Outgoing, #import_path::exports::serde::Serialize, #derive_deserialize )] @@ -490,7 +490,7 @@ impl ToTokens for Request { /// Data in the request's query string. #[derive( Debug, - #import_path::Outgoing, + #import_path::exports::ruma_common::Outgoing, #import_path::exports::serde::Serialize, #derive_deserialize )] @@ -508,7 +508,7 @@ impl ToTokens for Request { /// Data in the request's query string. #[derive( Debug, - #import_path::Outgoing, + #import_path::exports::ruma_common::Outgoing, #import_path::exports::serde::Serialize, #derive_deserialize )] @@ -521,7 +521,7 @@ impl ToTokens for Request { }; let request = quote! { - #[derive(Debug, Clone, #import_path::Outgoing)] + #[derive(Debug, Clone, #import_path::exports::ruma_common::Outgoing)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[incoming_derive(!Deserialize)] #( #struct_attributes )* diff --git a/ruma-api-macros/src/api/response.rs b/ruma-api-macros/src/api/response.rs index ece0c751..7a3a4ce1 100644 --- a/ruma-api-macros/src/api/response.rs +++ b/ruma-api-macros/src/api/response.rs @@ -310,7 +310,7 @@ impl ToTokens for Response { /// Data in the response body. #[derive( Debug, - #import_path::Outgoing, + #import_path::exports::ruma_common::Outgoing, #import_path::exports::serde::Deserialize, #import_path::exports::serde::Serialize, )] @@ -318,7 +318,7 @@ impl ToTokens for Response { }; let response = quote! { - #[derive(Debug, Clone, #import_path::Outgoing)] + #[derive(Debug, Clone, #import_path::exports::ruma_common::Outgoing)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[incoming_derive(!Deserialize)] #( #struct_attributes )* diff --git a/ruma-api-macros/src/lib.rs b/ruma-api-macros/src/lib.rs index f83be65d..076defa9 100644 --- a/ruma-api-macros/src/lib.rs +++ b/ruma-api-macros/src/lib.rs @@ -15,15 +15,11 @@ use std::convert::TryFrom as _; use proc_macro::TokenStream; use quote::ToTokens; -use syn::{parse_macro_input, DeriveInput}; +use syn::parse_macro_input; -use self::{ - api::{Api, RawApi}, - derive_outgoing::expand_derive_outgoing, -}; +use self::api::{Api, RawApi}; mod api; -mod derive_outgoing; mod util; #[proc_macro] @@ -34,50 +30,3 @@ pub fn ruma_api(input: TokenStream) -> TokenStream { Err(err) => err.to_compile_error().into(), } } - -/// Derive the `Outgoing` trait, possibly generating an 'Incoming' version of the struct this -/// derive macro is used on. Specifically, if no lifetime variables are used on any of the fields -/// of the struct, this simple implementation will be generated: -/// -/// ```ignore -/// impl Outgoing for MyType { -/// type Incoming = Self; -/// } -/// ``` - -/* TODO: Extend docs. Previously: - -If, however, `#[wrap_incoming]` is used (which is the only reason you should ever use this -derive macro manually), a new struct `IncomingT` (where `T` is the type this derive is used on) -is generated, with all of the fields with `#[wrap_incoming]` replaced: - -```ignore -#[derive(Outgoing)] -struct MyType { - pub foo: Foo, - #[wrap_incoming] - pub bar: Bar, - #[wrap_incoming(Baz)] - pub baz: Option, - #[wrap_incoming(with EventResult)] - pub x: XEvent, - #[wrap_incoming(YEvent with EventResult)] - pub ys: Vec, -} - -// generated -struct IncomingMyType { - pub foo: Foo, - pub bar: IncomingBar, - pub baz: Option, - pub x: EventResult, - pub ys: Vec>, -} -``` - -*/ -#[proc_macro_derive(Outgoing, attributes(incoming_derive))] -pub fn derive_outgoing(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - expand_derive_outgoing(input).unwrap_or_else(|err| err.to_compile_error()).into() -} diff --git a/ruma-api-macros/src/util.rs b/ruma-api-macros/src/util.rs index e43d9ad3..6c542ef5 100644 --- a/ruma-api-macros/src/util.rs +++ b/ruma-api-macros/src/util.rs @@ -285,7 +285,10 @@ pub(crate) fn extract_request_query(request: &Request, import_path: &TokenStream } } else if request.has_query_fields() { quote! { - let request_query: ::Incoming = + let request_query: < + RequestQuery + as #import_path::exports::ruma_common::Outgoing + >::Incoming = #import_path::try_deserialize!( request, #import_path::exports::ruma_serde::urlencoded::from_str( diff --git a/ruma-api/Cargo.toml b/ruma-api/Cargo.toml index 56e3c31e..796880ea 100644 --- a/ruma-api/Cargo.toml +++ b/ruma-api/Cargo.toml @@ -19,6 +19,7 @@ edition = "2018" http = "0.2.1" percent-encoding = "2.1.0" ruma-api-macros = { version = "=0.17.0-alpha.1", path = "../ruma-api-macros" } +ruma-common = { version = "0.2.0", path = "../ruma-common" } ruma-identifiers = { version = "0.17.4", path = "../ruma-identifiers" } ruma-serde = { version = "0.2.3", path = "../ruma-serde" } serde = { version = "1.0.114", features = ["derive"] } diff --git a/ruma-api/src/lib.rs b/ruma-api/src/lib.rs index efa8431d..02014d11 100644 --- a/ruma-api/src/lib.rs +++ b/ruma-api/src/lib.rs @@ -204,11 +204,9 @@ use http::Method; /// All request and response types also derive [`Outgoing`][Outgoing]. As such, to allow fallible /// deserialization, you can use the `#[wrap_incoming]` attribute. For details, see the /// documentation for [the derive macro](derive.Outgoing.html). -// TODO: Explain the concept of fallible deserialization before jumping to `ruma_api::Outgoing` +// TODO: Explain the concept of fallible deserialization before jumping to `ruma_common::Outgoing` pub use ruma_api_macros::ruma_api; -pub use ruma_api_macros::Outgoing; - pub mod error; /// This module is used to support the generated code from ruma-api-macros. /// It is not considered part of ruma-api's public API. @@ -216,6 +214,7 @@ pub mod error; pub mod exports { pub use http; pub use percent_encoding; + pub use ruma_common; pub use ruma_serde; pub use serde; pub use serde_json; @@ -223,18 +222,6 @@ pub mod exports { use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError}; -/// A type that can be sent to another party that understands the matrix protocol. If any of the -/// fields of `Self` don't implement serde's `Deserialize`, you can derive this trait to generate a -/// corresponding 'Incoming' type that supports deserialization. This is useful for things like -/// ruma_events' `EventResult` type. For more details, see the [derive macro's documentation][doc]. -/// -/// [doc]: derive.Outgoing.html -// TODO: Better explain how this trait relates to serde's traits -pub trait Outgoing { - /// The 'Incoming' variant of `Self`. - type Incoming; -} - /// Gives users the ability to define their own serializable / deserializable errors. pub trait EndpointError: StdError + Sized + 'static { /// Tries to construct `Self` from an `http::Response`. diff --git a/ruma-api/tests/manual_endpoint_impl.rs b/ruma-api/tests/manual_endpoint_impl.rs index 9dda6efd..69fdfd8a 100644 --- a/ruma-api/tests/manual_endpoint_impl.rs +++ b/ruma-api/tests/manual_endpoint_impl.rs @@ -3,16 +3,16 @@ use std::{convert::TryFrom, ops::Deref}; use http::{header::CONTENT_TYPE, method::Method}; -use ruma_identifiers::{RoomAliasId, RoomId}; -use serde::{Deserialize, Serialize}; - use ruma_api::{ error::{ FromHttpRequestError, FromHttpResponseError, IntoHttpError, RequestDeserializationError, ResponseDeserializationError, ServerError, Void, }, - AuthScheme, IncomingRequest, Metadata, Outgoing, OutgoingRequest, + AuthScheme, IncomingRequest, Metadata, OutgoingRequest, }; +use ruma_common::Outgoing; +use ruma_identifiers::{RoomAliasId, RoomId}; +use serde::{Deserialize, Serialize}; /// A request to create a new room alias. #[derive(Debug)] diff --git a/ruma-api/tests/ruma_api_lifetime.rs b/ruma-api/tests/ruma_api_lifetime.rs index 8bede5af..8586de88 100644 --- a/ruma-api/tests/ruma_api_lifetime.rs +++ b/ruma-api/tests/ruma_api_lifetime.rs @@ -1,5 +1,5 @@ #[allow(unused)] -#[derive(Copy, Clone, Debug, ruma_api::Outgoing, serde::Serialize)] +#[derive(Copy, Clone, Debug, ruma_common::Outgoing, serde::Serialize)] pub struct OtherThing<'t> { some: &'t str, t: &'t [u8], diff --git a/ruma-client-api/src/r0/account.rs b/ruma-client-api/src/r0/account.rs index f8f9151f..796f1123 100644 --- a/ruma-client-api/src/r0/account.rs +++ b/ruma-client-api/src/r0/account.rs @@ -18,7 +18,7 @@ pub mod unbind_3pid; pub mod whoami; -use ruma_api::Outgoing; +use ruma_common::Outgoing; use serde::{Deserialize, Serialize}; /// Additional authentication information for requestToken endpoints. diff --git a/ruma-client-api/src/r0/filter.rs b/ruma-client-api/src/r0/filter.rs index 1f30acae..a3b6fc29 100644 --- a/ruma-client-api/src/r0/filter.rs +++ b/ruma-client-api/src/r0/filter.rs @@ -6,7 +6,7 @@ pub mod get_filter; use std::fmt; use js_int::UInt; -use ruma_api::Outgoing; +use ruma_common::Outgoing; use ruma_identifiers::{RoomId, UserId}; use serde::{ de::{MapAccess, Visitor}, diff --git a/ruma-client-api/src/r0/membership.rs b/ruma-client-api/src/r0/membership.rs index bb2b68da..2b28eac1 100644 --- a/ruma-client-api/src/r0/membership.rs +++ b/ruma-client-api/src/r0/membership.rs @@ -14,8 +14,8 @@ pub mod unban_user; use std::collections::BTreeMap; -use ruma_api::Outgoing; use ruma_common::thirdparty::Medium; +use ruma_common::Outgoing; use ruma_identifiers::{ServerKeyId, ServerNameBox}; use serde::Serialize; diff --git a/ruma-client-api/src/r0/membership/invite_user.rs b/ruma-client-api/src/r0/membership/invite_user.rs index 6ed79510..4683e0b6 100644 --- a/ruma-client-api/src/r0/membership/invite_user.rs +++ b/ruma-client-api/src/r0/membership/invite_user.rs @@ -7,7 +7,8 @@ //! [invite-by-user-id]: https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-invite //! [invite-by-3pid]: https://matrix.org/docs/spec/client_server/r0.6.0#id101 -use ruma_api::{ruma_api, Outgoing}; +use ruma_api::ruma_api; +use ruma_common::Outgoing; use ruma_identifiers::{RoomId, UserId}; use serde::Serialize; diff --git a/ruma-client-api/src/r0/message/send_message_event.rs b/ruma-client-api/src/r0/message/send_message_event.rs index 4781083e..428164ad 100644 --- a/ruma-client-api/src/r0/message/send_message_event.rs +++ b/ruma-client-api/src/r0/message/send_message_event.rs @@ -7,8 +7,9 @@ use ruma_api::{ FromHttpRequestError, FromHttpResponseError, IntoHttpError, RequestDeserializationError, ResponseDeserializationError, ServerError, }, - AuthScheme, EndpointError, Metadata, Outgoing, + AuthScheme, EndpointError, Metadata, }; +use ruma_common::Outgoing; use ruma_events::{AnyMessageEventContent, EventContent as _}; use ruma_identifiers::{EventId, RoomId}; use serde::{Deserialize, Serialize}; diff --git a/ruma-client-api/src/r0/search/search_events.rs b/ruma-client-api/src/r0/search/search_events.rs index f17e62a6..d1048216 100644 --- a/ruma-client-api/src/r0/search/search_events.rs +++ b/ruma-client-api/src/r0/search/search_events.rs @@ -3,8 +3,8 @@ use std::collections::BTreeMap; use js_int::{uint, UInt}; -use ruma_api::{ruma_api, Outgoing}; -use ruma_common::Raw; +use ruma_api::ruma_api; +use ruma_common::{Outgoing, Raw}; use ruma_events::{AnyRoomEvent, AnyStateEvent}; use ruma_identifiers::{EventId, RoomId, UserId}; use serde::{Deserialize, Serialize}; diff --git a/ruma-client-api/src/r0/session/login.rs b/ruma-client-api/src/r0/session/login.rs index ef893250..25ad4526 100644 --- a/ruma-client-api/src/r0/session/login.rs +++ b/ruma-client-api/src/r0/session/login.rs @@ -1,7 +1,7 @@ //! [POST /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login) -use ruma_api::{ruma_api, Outgoing}; -use ruma_common::thirdparty::Medium; +use ruma_api::ruma_api; +use ruma_common::{thirdparty::Medium, Outgoing}; use ruma_identifiers::{DeviceId, DeviceIdBox, ServerNameBox, UserId}; use serde::{Deserialize, Serialize}; diff --git a/ruma-client-api/src/r0/session/login/user_serde.rs b/ruma-client-api/src/r0/session/login/user_serde.rs index 7e92275c..bfea0dac 100644 --- a/ruma-client-api/src/r0/session/login/user_serde.rs +++ b/ruma-client-api/src/r0/session/login/user_serde.rs @@ -1,8 +1,8 @@ //! Helper module for the Serialize / Deserialize impl's for the User struct //! in the parent module. -use ruma_api::Outgoing; use ruma_common::thirdparty::Medium; +use ruma_common::Outgoing; use serde::Serialize; // The following three structs could just be used in place of the one in the parent module, but diff --git a/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs b/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs index b3de09f6..cbc2271f 100644 --- a/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs +++ b/ruma-client-api/src/r0/state/send_state_event_for_empty_key.rs @@ -7,8 +7,9 @@ use ruma_api::{ FromHttpRequestError, FromHttpResponseError, IntoHttpError, RequestDeserializationError, ResponseDeserializationError, ServerError, }, - AuthScheme, EndpointError, Metadata, Outgoing, + AuthScheme, EndpointError, Metadata, }; +use ruma_common::Outgoing; use ruma_events::{AnyStateEventContent, EventContent as _}; use ruma_identifiers::{EventId, RoomId}; use serde::{Deserialize, Serialize}; diff --git a/ruma-client-api/src/r0/state/send_state_event_for_key.rs b/ruma-client-api/src/r0/state/send_state_event_for_key.rs index 5e5fd4b7..6689f31b 100644 --- a/ruma-client-api/src/r0/state/send_state_event_for_key.rs +++ b/ruma-client-api/src/r0/state/send_state_event_for_key.rs @@ -7,8 +7,9 @@ use ruma_api::{ FromHttpRequestError, FromHttpResponseError, IntoHttpError, RequestDeserializationError, ResponseDeserializationError, ServerError, }, - AuthScheme, EndpointError, Metadata, Outgoing, + AuthScheme, EndpointError, Metadata, }; +use ruma_common::Outgoing; use ruma_events::{AnyStateEventContent, EventContent as _}; use ruma_identifiers::{EventId, RoomId}; use serde::{Deserialize, Serialize}; diff --git a/ruma-client-api/src/r0/sync/sync_events.rs b/ruma-client-api/src/r0/sync/sync_events.rs index 8e30ee79..7b473c08 100644 --- a/ruma-client-api/src/r0/sync/sync_events.rs +++ b/ruma-client-api/src/r0/sync/sync_events.rs @@ -3,8 +3,8 @@ use std::{collections::BTreeMap, time::Duration}; use js_int::UInt; -use ruma_api::{ruma_api, Outgoing}; -use ruma_common::{presence::PresenceState, Raw}; +use ruma_api::ruma_api; +use ruma_common::{presence::PresenceState, Outgoing, Raw}; use ruma_events::{ presence::PresenceEvent, AnyBasicEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncRoomEvent, AnySyncStateEvent, AnyToDeviceEvent, diff --git a/ruma-client-api/src/r0/uiaa.rs b/ruma-client-api/src/r0/uiaa.rs index 4b617f51..8a9b9b0c 100644 --- a/ruma-client-api/src/r0/uiaa.rs +++ b/ruma-client-api/src/r0/uiaa.rs @@ -5,7 +5,8 @@ use std::{ fmt::{self, Display, Formatter}, }; -use ruma_api::{error::ResponseDeserializationError, EndpointError, Outgoing}; +use ruma_api::{error::ResponseDeserializationError, EndpointError}; +use ruma_common::Outgoing; use serde::{Deserialize, Serialize}; use serde_json::{ from_slice as from_json_slice, to_vec as to_json_vec, value::RawValue as RawJsonValue, diff --git a/ruma-common-macros/Cargo.toml b/ruma-common-macros/Cargo.toml new file mode 100644 index 00000000..e1a10fb5 --- /dev/null +++ b/ruma-common-macros/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["Jonas Platte ",] +categories = ["api-bindings", "web-programming"] +description = "Procedural macros for ruma-common." +homepage = "https://www.ruma.io/" +keywords = ["matrix", "chat", "messaging", "ruma"] +license = "MIT" +name = "ruma-common-macros" +readme = "README.md" +repository = "https://github.com/ruma/ruma" +version = "0.2.0" +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.19" +quote = "1.0.7" +syn = { version = "1.0.38", features = ["full", "extra-traits"] } +proc-macro-crate = "0.1.5" diff --git a/ruma-common-macros/LICENSE b/ruma-common-macros/LICENSE new file mode 100644 index 00000000..f0d48ccb --- /dev/null +++ b/ruma-common-macros/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020 Jonas Platte + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ruma-common-macros/src/lib.rs b/ruma-common-macros/src/lib.rs new file mode 100644 index 00000000..408d89d3 --- /dev/null +++ b/ruma-common-macros/src/lib.rs @@ -0,0 +1,55 @@ +use proc_macro::TokenStream; +use syn::{parse_macro_input, DeriveInput}; + +use outgoing::expand_derive_outgoing; + +mod outgoing; +mod util; + +/// Derive the `Outgoing` trait, possibly generating an 'Incoming' version of the struct this +/// derive macro is used on. Specifically, if no lifetime variables are used on any of the fields +/// of the struct, this simple implementation will be generated: +/// +/// ```ignore +/// impl Outgoing for MyType { +/// type Incoming = Self; +/// } +/// ``` +/* + +TODO: Extend docs. Previously: + +If, however, `#[wrap_incoming]` is used (which is the only reason you should ever use this +derive macro manually), a new struct `IncomingT` (where `T` is the type this derive is used on) +is generated, with all of the fields with `#[wrap_incoming]` replaced: + +```ignore +#[derive(Outgoing)] +struct MyType { + pub foo: Foo, + #[wrap_incoming] + pub bar: Bar, + #[wrap_incoming(Baz)] + pub baz: Option, + #[wrap_incoming(with EventResult)] + pub x: XEvent, + #[wrap_incoming(YEvent with EventResult)] + pub ys: Vec, +} + +// generated +struct IncomingMyType { + pub foo: Foo, + pub bar: IncomingBar, + pub baz: Option, + pub x: EventResult, + pub ys: Vec>, +} +``` + +*/ +#[proc_macro_derive(Outgoing, attributes(incoming_derive))] +pub fn derive_outgoing(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + expand_derive_outgoing(input).unwrap_or_else(|err| err.to_compile_error()).into() +} diff --git a/ruma-api-macros/src/derive_outgoing.rs b/ruma-common-macros/src/outgoing.rs similarity index 95% rename from ruma-api-macros/src/derive_outgoing.rs rename to ruma-common-macros/src/outgoing.rs index 2df1ff1a..609901e0 100644 --- a/ruma-api-macros/src/derive_outgoing.rs +++ b/ruma-common-macros/src/outgoing.rs @@ -9,7 +9,7 @@ use syn::{ Token, Type, TypeGenerics, TypePath, TypeReference, TypeSlice, Variant, }; -use crate::util::import_ruma_api; +use crate::util::import_ruma_common; enum StructKind { Struct, @@ -23,7 +23,7 @@ enum DataKind { } pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { - let import_path = import_ruma_api(); + let ruma_common = import_ruma_common(); let mut derives = vec![quote! { Debug }]; let mut derive_deserialize = true; @@ -46,7 +46,7 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { }), ); if derive_deserialize { - derives.push(quote! { #import_path::exports::serde::Deserialize }); + derives.push(quote! { #ruma_common::exports::serde::Deserialize }); } let input_attrs = @@ -67,7 +67,7 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { }; match data { - DataKind::Unit => Ok(impl_outgoing_with_incoming_self(&input, &import_path)), + DataKind::Unit => Ok(impl_outgoing_with_incoming_self(&input, &ruma_common)), DataKind::Enum(mut vars) => { let mut found_lifetime = false; for var in &mut vars { @@ -82,7 +82,7 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl(); if !found_lifetime { - return Ok(impl_outgoing_with_incoming_self(&input, &import_path)); + return Ok(impl_outgoing_with_incoming_self(&input, &ruma_common)); } let vis = input.vis; @@ -98,7 +98,7 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { #( #input_attrs )* #vis enum #incoming_ident #ty_gen { #( #vars, )* } - impl #original_impl_gen #import_path::Outgoing for #original_ident #original_ty_gen { + impl #original_impl_gen #ruma_common::Outgoing for #original_ident #original_ty_gen { type Incoming = #incoming_ident #impl_gen; } }) @@ -115,7 +115,7 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { let (original_impl_gen, original_ty_gen, _) = input.generics.split_for_impl(); if !found_lifetime { - return Ok(impl_outgoing_with_incoming_self(&input, &import_path)); + return Ok(impl_outgoing_with_incoming_self(&input, &ruma_common)); } let vis = input.vis; @@ -136,7 +136,7 @@ pub fn expand_derive_outgoing(input: DeriveInput) -> syn::Result { #( #input_attrs )* #vis struct #incoming_ident #ty_gen #struct_def - impl #original_impl_gen #import_path::Outgoing for #original_ident #original_ty_gen { + impl #original_impl_gen #ruma_common::Outgoing for #original_ident #original_ty_gen { type Incoming = #incoming_ident #impl_gen; } }) @@ -150,12 +150,12 @@ fn filter_input_attrs(attr: &Attribute) -> bool { attr.path.is_ident("serde") || attr.path.is_ident("non_exhaustive") } -fn impl_outgoing_with_incoming_self(input: &DeriveInput, import_path: &TokenStream) -> TokenStream { +fn impl_outgoing_with_incoming_self(input: &DeriveInput, ruma_common: &TokenStream) -> TokenStream { let ident = &input.ident; let (impl_gen, ty_gen, _) = input.generics.split_for_impl(); quote! { - impl #impl_gen #import_path::Outgoing for #ident #ty_gen { + impl #impl_gen #ruma_common::Outgoing for #ident #ty_gen { type Incoming = Self; } } diff --git a/ruma-common-macros/src/util.rs b/ruma-common-macros/src/util.rs new file mode 100644 index 00000000..511db937 --- /dev/null +++ b/ruma-common-macros/src/util.rs @@ -0,0 +1,15 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use proc_macro_crate::crate_name; +use quote::quote; + +pub fn import_ruma_common() -> TokenStream { + if let Ok(possibly_renamed) = crate_name("ruma-common") { + let import = Ident::new(&possibly_renamed, Span::call_site()); + quote! { ::#import } + } else if let Ok(possibly_renamed) = crate_name("ruma") { + let import = Ident::new(&possibly_renamed, Span::call_site()); + quote! { ::#import } + } else { + quote! { ::ruma_common } + } +} diff --git a/ruma-common/Cargo.toml b/ruma-common/Cargo.toml index 977dd839..5f4ca3d7 100644 --- a/ruma-common/Cargo.toml +++ b/ruma-common/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] js_int = { version = "0.1.9", features = ["serde"] } -ruma-api = { version = "=0.17.0-alpha.1", path = "../ruma-api" } +ruma-common-macros = { version = "=0.2.0", path = "../ruma-common-macros" } ruma-identifiers = { version = "0.17.4", path = "../ruma-identifiers" } ruma-serde = { version = "0.2.3", path = "../ruma-serde" } serde = { version = "1.0.114", features = ["derive"] } diff --git a/ruma-common/src/directory.rs b/ruma-common/src/directory.rs index 64e7a768..70bd31e4 100644 --- a/ruma-common/src/directory.rs +++ b/ruma-common/src/directory.rs @@ -3,16 +3,16 @@ use std::fmt; use js_int::UInt; -use ruma_api::Outgoing; use ruma_identifiers::{RoomAliasId, RoomId}; use serde::{ de::{Error, MapAccess, Visitor}, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer, }; - use serde_json::Value as JsonValue; +use crate::Outgoing; + /// A chunk of a room list response, describing one room. /// /// To create an instance of this type, first create a `PublicRoomsChunkInit` and convert it via diff --git a/ruma-common/src/lib.rs b/ruma-common/src/lib.rs index 049c44c2..6318bd01 100644 --- a/ruma-common/src/lib.rs +++ b/ruma-common/src/lib.rs @@ -9,4 +9,29 @@ pub mod push; mod raw; pub mod thirdparty; +pub use ruma_common_macros::Outgoing; + pub use self::raw::Raw; + +/// A type that can be sent to another party that understands the matrix protocol. If any of the +/// fields of `Self` don't implement serde's `Deserialize`, you can derive this trait to generate a +/// corresponding 'Incoming' type that supports deserialization. This is useful for things like +/// ruma_events' `EventResult` type. For more details, see the [derive macro's documentation][doc]. +/// +/// [doc]: derive.Outgoing.html +// TODO: Better explain how this trait relates to serde's traits +pub trait Outgoing { + /// The 'Incoming' variant of `Self`. + type Incoming; +} + +// Hack to allow both ruma-common itself and external crates (or tests) to use procedural macros +// that expect `ruma_common` to exist in the prelude. +extern crate self as ruma_common; + +/// This module is used to support the generated code from ruma-api-macros. +/// It is not considered part of ruma-common's public API. +#[doc(hidden)] +pub mod exports { + pub use serde; +} diff --git a/ruma-api/tests/outgoing.rs b/ruma-common/tests/outgoing.rs similarity index 97% rename from ruma-api/tests/outgoing.rs rename to ruma-common/tests/outgoing.rs index ff4b4c5a..be076576 100644 --- a/ruma-api/tests/outgoing.rs +++ b/ruma-common/tests/outgoing.rs @@ -1,4 +1,4 @@ -use ruma_api::Outgoing; +use ruma_common::Outgoing; use ruma_identifiers::UserId; #[allow(unused)] diff --git a/ruma-push-gateway-api/src/send_event_notification/v1.rs b/ruma-push-gateway-api/src/send_event_notification/v1.rs index 367c61fe..604eb863 100644 --- a/ruma-push-gateway-api/src/send_event_notification/v1.rs +++ b/ruma-push-gateway-api/src/send_event_notification/v1.rs @@ -1,8 +1,11 @@ //! [POST /_matrix/push/v1/notify](https://matrix.org/docs/spec/push_gateway/r0.1.1#post-matrix-push-v1-notify) use js_int::UInt; -use ruma_api::{ruma_api, Outgoing}; -use ruma_common::push::{PusherData, Tweak}; +use ruma_api::ruma_api; +use ruma_common::{ + push::{PusherData, Tweak}, + Outgoing, +}; use ruma_events::EventType; use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId}; use serde::{Deserialize, Serialize};