Permalink
Browse files

Add IntoOption trait to allow returning () from an event handler

  • Loading branch information...
antoyo committed May 20, 2017
1 parent 04cb3ab commit f4c4a48ee30b8c3aeabdf32a5af949b08416f309
Showing with 77 additions and 9 deletions.
  1. +6 −0 examples/communication-attribute.rs
  2. +22 −0 relm-derive/src/lib.rs
  3. +2 −0 src/lib.rs
  4. +9 −9 src/macros.rs
  5. +38 −0 src/option.rs
@@ -166,6 +166,7 @@ impl Widget for Win {
#[name="counter1"]
Counter {
Increment => counter2@Decrement,
Increment => log_increment(),
},
#[name="counter2"]
Counter,
@@ -182,6 +183,11 @@ impl Widget for Win {
}
}
fn log_increment() {
println!("Increment");
}
impl Win {
fn inc(&mut self) -> Option<CounterMsg> {
Some(Increment)
View
@@ -47,6 +47,7 @@ fn impl_simple_msg(ast: &MacroInput) -> Tokens {
let clone = derive_clone(ast);
let display = derive_display_variant(ast);
let into_option = derive_into_option(ast);
let generics = &ast.generics;
let generics_without_bound = remove_generic_bounds(generics);
@@ -58,6 +59,7 @@ fn impl_simple_msg(ast: &MacroInput) -> Tokens {
quote! {
#clone
#display
#into_option
impl #generics FnOnce<((),)> for #typ #where_clause {
type Output = #typ;
@@ -92,10 +94,12 @@ pub fn msg(input: TokenStream) -> TokenStream {
fn impl_msg(ast: &MacroInput) -> Tokens {
let clone = derive_clone(ast);
let display = derive_display_variant(ast);
let into_option = derive_into_option(ast);
quote! {
#clone
#display
#into_option
}
}
@@ -175,6 +179,24 @@ fn derive_clone_enum(name: &Ident, typ: Tokens, mut generics: Generics, variants
}
}
fn derive_into_option(ast: &MacroInput) -> Tokens {
let generics = &ast.generics;
let name = &ast.ident;
let generics_without_bound = remove_generic_bounds(generics);
let typ = quote! {
#name #generics_without_bound
};
let where_clause = gen_where_clause(&generics);
quote! {
impl #generics ::relm::IntoOption<#typ> for #typ #where_clause {
fn into_option(self) -> Option<#typ> {
Some(self)
}
}
}
}
fn derive_clone_struct(name: &Ident, typ: Tokens, generics: &Generics, fields: &[Field]) -> Tokens {
let idents: Vec<_> = fields.iter().map(|field| field.ident.clone().unwrap()).collect();
let idents1 = &idents;
View
@@ -85,6 +85,7 @@ extern crate relm_core;
mod component;
mod container;
mod macros;
mod option;
mod stream;
mod widget;
@@ -109,6 +110,7 @@ pub use relm_core::EventStream;
pub use container::{Container, ContainerWidget, RelmContainer};
pub use component::Component;
pub use option::IntoOption;
use stream::ToStream;
pub use widget::Widget;
View
@@ -29,8 +29,8 @@ macro_rules! check_recursion {
to the same widget.\nInspect the stack trace to determine which call it is.\nThen you can either \
refactor your code to avoid a cyclic event dependency or block events from being emitted by doing \
the following:\n{\n let _lock = self.model.relm.stream().lock();\n // Your panicking call.\n}\
\nSee this example:\
https://github.com/antoyo/relm/blob/feature/futures-glib/examples/checkboxes.rs#L88\n
\nSee this example: \
https://github.com/antoyo/relm/blob/feature/futures-glib/examples/checkboxes.rs#L88\
This issue can also happen when emitting a signal to the same widget, in which case you need to\
refactor your code to avoid this cyclic event dependency.");
}
@@ -60,7 +60,7 @@ macro_rules! connect {
($widget:expr, $event:ident($($args:pat),*), $other_component:expr, $msg:expr) => {
let stream = $other_component.stream().clone();
$widget.$event(move |$($args),*| {
let msg: Option<_> = $msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option($msg);
if let Some(msg) = msg {
stream.emit(msg);
}
@@ -75,7 +75,7 @@ macro_rules! connect {
let stream = $relm.stream().clone();
$widget.$event(move |$($args),*| {
let (msg, return_value) = $msg;
let msg: Option<_> = msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option(msg);
if let Some(msg) = msg {
stream.emit(msg);
}
@@ -97,7 +97,7 @@ macro_rules! connect {
check_recursion!($widget_clone);
let mut $widget_clone = $widget_clone.borrow_mut();
let (msg, return_value) = $msg;
let msg: Option<_> = msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option(msg);
if let Some(msg) = msg {
stream.emit(msg);
}
@@ -117,7 +117,7 @@ macro_rules! connect {
let $widget_clone = $widget_clone.upgrade().expect("upgrade should always work");
check_recursion!($widget_clone);
let mut $widget_clone = $widget_clone.borrow_mut();
let msg: Option<_> = $msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option($msg);
if let Some(msg) = msg {
stream.emit(msg);
}
@@ -136,7 +136,7 @@ macro_rules! connect {
let $widget = $widget.upgrade().expect("upgrade should always work");
check_recursion!($widget);
let mut $widget = $widget.borrow_mut();
let msg: Option<_> = $msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option($msg);
if let Some(msg) = msg {
stream.emit(msg);
}
@@ -150,7 +150,7 @@ macro_rules! connect {
($relm:expr, $widget:expr, $event:ident($($args:pat),*), $msg:expr) => {{
let stream = $relm.stream().clone();
$widget.$event(move |$($args),*| {
let msg: Option<_> = $msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option($msg);
if let Some(msg) = msg {
stream.emit(msg);
}
@@ -165,7 +165,7 @@ macro_rules! connect {
#[allow(unreachable_patterns)]
match msg {
$message => {
let msg: Option<_> = $msg.into();
let msg: Option<_> = ::relm::IntoOption::into_option($msg);
if let Some(msg) = msg {
stream.emit(msg);
}
View
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
*
* 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.
*/
#[doc(hidden)]
pub trait IntoOption<T> {
#[doc(hidden)]
fn into_option(self) -> Option<T>;
}
impl<T> IntoOption<T> for Option<T> {
fn into_option(self) -> Option<T> {
self
}
}
impl<T> IntoOption<T> for () {
fn into_option(self) -> Option<T> {
None
}
}

0 comments on commit f4c4a48

Please sign in to comment.