Skip to content

Commit

Permalink
Merge pull request #4 from piegamesde/master
Browse files Browse the repository at this point in the history
Allow to build multiple actors from a BuilderUtilizer
  • Loading branch information
idanarye authored Feb 6, 2021
2 parents 9c38b6f + 7e84500 commit f88a8c8
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 181 deletions.
36 changes: 21 additions & 15 deletions examples/example_actor_per_row.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[derive(woab::Factories)]
pub struct Factories {
#[factory(extra(buf_sum))]
win_app: woab::Factory<WindowActor, WindowWidgets, WindowSignal>,
win_app: woab::BuilderFactory,
#[factory(extra(buf_addend))]
row_addend: woab::Factory<AddendActor, AddendWidgets, AddendSignal>,
row_addend: woab::BuilderFactory,
}

#[derive(woab::WidgetsFromBuilder)]
Expand Down Expand Up @@ -46,14 +46,16 @@ impl actix::StreamHandler<WindowSignal> for WindowActor {
use gtk::prelude::*;;
match signal {
WindowSignal::ClickButton => {
let addend = self.factories.row_addend.build().actor(|_, widgets| {
self.widgets.lst_addition.add(&widgets.row_addend);
AddendActor {
widgets,
window: ctx.address(),
number: Some(0),
}
}).unwrap();
let addend = self.factories.row_addend.instantiate()
.new_actor(|builder_ctx| {
let widgets: AddendWidgets = builder_ctx.connect_widgets().unwrap();
self.widgets.lst_addition.add(&widgets.row_addend);
AddendActor {
widgets,
window: ctx.address(),
number: Some(0),
}
});
self.addends.push(addend);
ctx.address().do_send(Recalculate);
}
Expand Down Expand Up @@ -162,11 +164,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?;
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.build().actor(|_, widgets| WindowActor {
widgets,
factories,
addends: Vec::new(),
})?;
factories.win_app.instantiate()
.new_actor(|ctx| {
ctx.connect_signals::<WindowSignal>();
WindowActor {
widgets: ctx.connect_widgets().unwrap(),
factories,
addends: Vec::new(),
}
});

gtk::main();
Ok(())
Expand Down
16 changes: 10 additions & 6 deletions examples/example_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::{Instant, Duration};
#[derive(woab::Factories)]
pub struct Factories {
#[factory(extra(buf_count_pressed_time))]
win_app: woab::Factory<WindowActor, WindowWidgets, WindowSignal>,
win_app: woab::BuilderFactory,
}

#[derive(woab::WidgetsFromBuilder)]
Expand Down Expand Up @@ -88,11 +88,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?;
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.build().actor(|_, widgets| WindowActor {
widgets,
press_times: Default::default(),
total_durations: Default::default(),
})?;
factories.win_app.instantiate()
.new_actor(|ctx| {
ctx.connect_signals::<WindowSignal>();
WindowActor {
widgets: ctx.connect_widgets().unwrap(),
press_times: Default::default(),
total_durations: Default::default(),
}
});

gtk::main();
Ok(())
Expand Down
26 changes: 15 additions & 11 deletions examples/example_taggged_signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use gtk::prelude::*;
#[derive(woab::Factories)]
pub struct Factories {
#[factory(extra(buf_sum))]
win_app: woab::Factory<WindowActor, WindowWidgets, WindowSignal>,
win_app: woab::BuilderFactory,
#[factory(extra(buf_addend))]
row_addend: woab::Factory<(), AddendWidgets, AddendSignal>,
row_addend: woab::BuilderFactory,
}

#[derive(woab::WidgetsFromBuilder)]
Expand Down Expand Up @@ -46,9 +46,9 @@ impl actix::StreamHandler<WindowSignal> for WindowActor {
WindowSignal::ClickButton => {
let addend_id = self.next_addend_id;
self.next_addend_id += 1;
let widgets = self.factories.row_addend.build()
.connect_tagged_builder_signals(ctx, addend_id)
.widgets().unwrap();
let mut builder = self.factories.row_addend.instantiate();
builder.connect_signals_tagged(addend_id, ctx);
let widgets = builder.connect_widgets::<AddendWidgets>().unwrap();
self.widgets.lst_addition.add(&widgets.row_addend);
self.addends.insert(addend_id, (widgets, Some(0)));
self.recalculate();
Expand Down Expand Up @@ -111,12 +111,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?;
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.build().actor(|_, widgets| WindowActor {
widgets,
factories,
next_addend_id: 0,
addends: Default::default(),
})?;
factories.win_app.instantiate()
.new_actor(|ctx| {
ctx.connect_signals::<WindowSignal>();
WindowActor {
widgets: ctx.connect_widgets().unwrap(),
factories,
next_addend_id: 0,
addends: Default::default(),
}
});

gtk::main();
Ok(())
Expand Down
45 changes: 30 additions & 15 deletions macros/src/builder_signal_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
return Err(Error::new_spanned(ast, "BuilderSignal only supports enums"));
};
let enum_ident = &ast.ident;
let match_arms = data_enum.variants.iter().map(|variant| {
let vec_of_tuples = data_enum.variants.iter().map(|variant| {
let mut ret = None;
iter_attrs_parameters(&variant.attrs, "signal", |name, value| {
match path_to_single_string(&name)?.as_str() {
Expand Down Expand Up @@ -92,29 +92,44 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
syn::Fields::Unit => quote!(#enum_ident::#variant_ident),
syn::Fields::Named(_) => return Err(Error::new_spanned(variant, "BuilderSignal only supports unit or tuple variants (even if they are empty)")),
};
Ok(quote! {
#ident_as_str => Some(Box::new(move |args| {
match tx.clone().try_send(#msg_construction) {
Ok(_) => #signal_return_value,
Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
panic!("Unable to send {} signal - channel is closed", #ident_as_str);
},
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
panic!("Unable to send {} signal - channel is full", #ident_as_str);
},
}
})),
})
Ok((
/* Match arms */
quote! {
#ident_as_str => Some(Box::new(move |args| {
match tx.clone().try_send(#msg_construction) {
Ok(_) => #signal_return_value,
Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
panic!("Unable to send {} signal - channel is closed", #ident_as_str);
},
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
panic!("Unable to send {} signal - channel is full", #ident_as_str);
},
}
})),
},
/* Signal names */
quote! {
#ident_as_str,
},
))
}).collect::<Result<Vec<_>, Error>>()?;
/* We cannot use unzip with error handling, so here's a workaround */
let (match_arms, signal_names) = vec_of_tuples.into_iter().unzip::<_, _, Vec<_>, Vec<_>>();
Ok(quote! {
impl woab::BuilderSignal for #enum_ident {
fn transmit_signal_in_stream_function(signal: &str, tx: tokio::sync::mpsc::Sender<Self>) -> Option<Box<dyn Fn(&[glib::Value]) -> Option<glib::Value>>> {
fn bridge_signal(signal: &str, tx: tokio::sync::mpsc::Sender<Self>) -> Option<woab::RawSignalCallback> {
use tokio::sync::mpsc::error::TrySendError;
match signal {
#(#match_arms)*
_ => None,
}
}

fn list_signals() -> &'static [&'static str] {
&[
#(#signal_names)*
]
}
}
})
}
2 changes: 1 addition & 1 deletion macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod factories_derive;
mod removable_derive;
mod util;

#[proc_macro_derive(WidgetsFromBuilder)]
#[proc_macro_derive(WidgetsFromBuilder, attributes(widget))]
pub fn derive_widgets_from_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
match widgets_from_builder_derive::impl_widgets_from_builder_derive(&input) {
Expand Down
33 changes: 32 additions & 1 deletion macros/src/widgets_from_builder_derive.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use syn::parse::Error;
use syn::spanned::Spanned;
use quote::quote;
use crate::util::{iter_attrs_parameters, path_to_single_string};

pub fn impl_widgets_from_builder_derive(ast: &syn::DeriveInput) -> Result<proc_macro2::TokenStream, Error> {
let fields = if let syn::Data::Struct(syn::DataStruct {
Expand All @@ -13,9 +14,31 @@ pub fn impl_widgets_from_builder_derive(ast: &syn::DeriveInput) -> Result<proc_m
};
let struct_ident = &ast.ident;
let ctor_arms = fields.named.iter().map(|field| {
/* Handle renaming */
let mut name = None;
iter_attrs_parameters(&field.attrs, "widget", |attr_name, value| {
match path_to_single_string(&attr_name)?.as_str() {
"name" => {
let value = value.ok_or_else(|| Error::new_spanned(attr_name, "attribute `name` must have a value"))?;
if name.is_some() {
return Err(Error::new_spanned(value, "attribute `name` can only be specified once"));
}
name = Some(value);
},
_ => {
return Err(Error::new_spanned(attr_name, "unknown attribute"));
},
}
Ok(())
})?;

let field_ident = field.ident.as_ref().ok_or_else(|| Error::new(field.span(), "Nameless field"))?;
let field_type = &field.ty;
let ident_as_str = syn::LitStr::new(&field_ident.to_string(), field_ident.span());
let ident_as_str = match name {
Some(syn::Expr::Lit(syn::ExprLit {lit: syn::Lit::Str(name), ..})) => name,
None => syn::LitStr::new(&field_ident.to_string(), field_ident.span()),
_ => return Err(Error::new_spanned(name, "`name` attribute must have a string literal value")),
};
Ok(quote!{
#field_ident: builder.get_object(#ident_as_str).ok_or_else(|| {
if let Some(object) = builder.get_object::<glib::Object>(#ident_as_str) {
Expand All @@ -42,5 +65,13 @@ pub fn impl_widgets_from_builder_derive(ast: &syn::DeriveInput) -> Result<proc_m
})
}
}

impl std::convert::TryFrom<gtk::Builder> for #struct_ident {
type Error = woab::Error;

fn try_from(builder: gtk::Builder) -> Result<Self, Self::Error> {
<Self as std::convert::TryFrom<&gtk::Builder>>::try_from(&builder)
}
}
})
}
Loading

0 comments on commit f88a8c8

Please sign in to comment.