Skip to content

Commit

Permalink
Merge pull request #1581 from PJungkamp/signal/accumulator
Browse files Browse the repository at this point in the history
Signal/accumulator
  • Loading branch information
sdroege authored Nov 27, 2024
2 parents b8c3023 + 8ffa149 commit e5b674e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 9 deletions.
21 changes: 19 additions & 2 deletions glib/src/subclass/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,19 @@ mod test {
.build(),
super::Signal::builder("create-string")
.return_type::<String>()
.accumulator(|_hint, acc, val| {
// join all strings from signal handlers by newline
let mut acc = acc
.get_owned::<Option<String>>()
.unwrap()
.map(|mut acc| {
acc.push('\n');
acc
})
.unwrap_or_default();
acc.push_str(val.get::<&str>().unwrap());
std::ops::ControlFlow::Continue(acc.to_value())
})
.build(),
super::Signal::builder("create-child-object")
.return_type::<super::ChildObject>()
Expand Down Expand Up @@ -891,13 +904,17 @@ mod test {
let obj = Object::with_type(SimpleObject::static_type());

obj.connect("create-string", false, move |_args| {
Some("return value".to_value())
Some("return value 1".to_value())
});

obj.connect("create-string", false, move |_args| {
Some("return value 2".to_value())
});

let signal_id = imp::SimpleObject::signals()[2].signal_id();

let value = obj.emit::<String>(signal_id, &[]);
assert_eq!(value, "return value");
assert_eq!(value, "return value 1\nreturn value 2");
}

#[test]
Expand Down
42 changes: 35 additions & 7 deletions glib/src/subclass/signal.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Take a look at the license at the top of the repository in the LICENSE file.

use std::{fmt, num::NonZeroU32, ptr, sync::Mutex};
use std::{fmt, num::NonZeroU32, ops::ControlFlow, ptr, sync::Mutex};

use crate::{
ffi, gobject_ffi, prelude::*, translate::*, utils::is_canonical_pspec_name, Closure,
Expand All @@ -18,7 +18,12 @@ pub struct SignalBuilder {
return_type: SignalType,
class_handler: Option<Box<dyn Fn(&[Value]) -> Option<Value> + Send + Sync + 'static>>,
accumulator: Option<
Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
Box<
dyn Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
+ Send
+ Sync
+ 'static,
>,
>,
}

Expand Down Expand Up @@ -352,7 +357,12 @@ enum SignalRegistration {
Unregistered {
class_handler: Option<Box<dyn Fn(&[Value]) -> Option<Value> + Send + Sync + 'static>>,
accumulator: Option<
Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
Box<
dyn Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
+ Send
+ Sync
+ 'static,
>,
>,
},
Registered {
Expand Down Expand Up @@ -480,7 +490,10 @@ impl SignalBuilder {
/// This is called if multiple signal handlers are connected to the signal for accumulating the
/// return values into a single value.
pub fn accumulator<
F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
F: Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
+ Send
+ Sync
+ 'static,
>(
mut self,
func: F,
Expand Down Expand Up @@ -633,7 +646,7 @@ impl Signal {
let accumulator = &*(data as *const (
SignalType,
Box<
dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool
dyn Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
+ Send
+ Sync
+ 'static,
Expand All @@ -651,8 +664,23 @@ impl Signal {
handler_return.type_()
);

let res = (accumulator.1)(&SignalInvocationHint(*ihint), return_accu, handler_return)
.into_glib();
let control_flow = (accumulator.1)(
&SignalInvocationHint(*ihint),
std::mem::replace(return_accu, Value::uninitialized()),
handler_return,
);

let res = match control_flow {
ControlFlow::Continue(val) => {
*return_accu = val;
true.into_glib()
}

ControlFlow::Break(val) => {
*return_accu = val;
false.into_glib()
}
};

assert!(
return_accu.type_().is_a(return_type.into()),
Expand Down

0 comments on commit e5b674e

Please sign in to comment.