Skip to content

Commit e5b674e

Browse files
authored
Merge pull request #1581 from PJungkamp/signal/accumulator
Signal/accumulator
2 parents b8c3023 + 8ffa149 commit e5b674e

File tree

2 files changed

+54
-9
lines changed

2 files changed

+54
-9
lines changed

glib/src/subclass/object.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,19 @@ mod test {
422422
.build(),
423423
super::Signal::builder("create-string")
424424
.return_type::<String>()
425+
.accumulator(|_hint, acc, val| {
426+
// join all strings from signal handlers by newline
427+
let mut acc = acc
428+
.get_owned::<Option<String>>()
429+
.unwrap()
430+
.map(|mut acc| {
431+
acc.push('\n');
432+
acc
433+
})
434+
.unwrap_or_default();
435+
acc.push_str(val.get::<&str>().unwrap());
436+
std::ops::ControlFlow::Continue(acc.to_value())
437+
})
425438
.build(),
426439
super::Signal::builder("create-child-object")
427440
.return_type::<super::ChildObject>()
@@ -891,13 +904,17 @@ mod test {
891904
let obj = Object::with_type(SimpleObject::static_type());
892905

893906
obj.connect("create-string", false, move |_args| {
894-
Some("return value".to_value())
907+
Some("return value 1".to_value())
908+
});
909+
910+
obj.connect("create-string", false, move |_args| {
911+
Some("return value 2".to_value())
895912
});
896913

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

899916
let value = obj.emit::<String>(signal_id, &[]);
900-
assert_eq!(value, "return value");
917+
assert_eq!(value, "return value 1\nreturn value 2");
901918
}
902919

903920
#[test]

glib/src/subclass/signal.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Take a look at the license at the top of the repository in the LICENSE file.
22

3-
use std::{fmt, num::NonZeroU32, ptr, sync::Mutex};
3+
use std::{fmt, num::NonZeroU32, ops::ControlFlow, ptr, sync::Mutex};
44

55
use crate::{
66
ffi, gobject_ffi, prelude::*, translate::*, utils::is_canonical_pspec_name, Closure,
@@ -18,7 +18,12 @@ pub struct SignalBuilder {
1818
return_type: SignalType,
1919
class_handler: Option<Box<dyn Fn(&[Value]) -> Option<Value> + Send + Sync + 'static>>,
2020
accumulator: Option<
21-
Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
21+
Box<
22+
dyn Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
23+
+ Send
24+
+ Sync
25+
+ 'static,
26+
>,
2227
>,
2328
}
2429

@@ -352,7 +357,12 @@ enum SignalRegistration {
352357
Unregistered {
353358
class_handler: Option<Box<dyn Fn(&[Value]) -> Option<Value> + Send + Sync + 'static>>,
354359
accumulator: Option<
355-
Box<dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static>,
360+
Box<
361+
dyn Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
362+
+ Send
363+
+ Sync
364+
+ 'static,
365+
>,
356366
>,
357367
},
358368
Registered {
@@ -480,7 +490,10 @@ impl SignalBuilder {
480490
/// This is called if multiple signal handlers are connected to the signal for accumulating the
481491
/// return values into a single value.
482492
pub fn accumulator<
483-
F: Fn(&SignalInvocationHint, &mut Value, &Value) -> bool + Send + Sync + 'static,
493+
F: Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
494+
+ Send
495+
+ Sync
496+
+ 'static,
484497
>(
485498
mut self,
486499
func: F,
@@ -633,7 +646,7 @@ impl Signal {
633646
let accumulator = &*(data as *const (
634647
SignalType,
635648
Box<
636-
dyn Fn(&SignalInvocationHint, &mut Value, &Value) -> bool
649+
dyn Fn(&SignalInvocationHint, Value, &Value) -> ControlFlow<Value, Value>
637650
+ Send
638651
+ Sync
639652
+ 'static,
@@ -651,8 +664,23 @@ impl Signal {
651664
handler_return.type_()
652665
);
653666

654-
let res = (accumulator.1)(&SignalInvocationHint(*ihint), return_accu, handler_return)
655-
.into_glib();
667+
let control_flow = (accumulator.1)(
668+
&SignalInvocationHint(*ihint),
669+
std::mem::replace(return_accu, Value::uninitialized()),
670+
handler_return,
671+
);
672+
673+
let res = match control_flow {
674+
ControlFlow::Continue(val) => {
675+
*return_accu = val;
676+
true.into_glib()
677+
}
678+
679+
ControlFlow::Break(val) => {
680+
*return_accu = val;
681+
false.into_glib()
682+
}
683+
};
656684

657685
assert!(
658686
return_accu.type_().is_a(return_type.into()),

0 commit comments

Comments
 (0)