Skip to content

Commit 246ff16

Browse files
authored
Merge pull request #490 from kas-gui/push-tlnpmvnkvtrl
Replace fns for_child* with get_child* to reduce stack depth
2 parents 27b25f0 + 94a42dc commit 246ff16

File tree

18 files changed

+119
-166
lines changed

18 files changed

+119
-166
lines changed

crates/kas-core/src/core/collection.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,7 @@ pub trait Collection {
3838
fn get_mut_tile(&mut self, index: usize) -> Option<&mut dyn Tile>;
3939

4040
/// Operate on a widget as a [`Node`]
41-
fn for_node(
42-
&mut self,
43-
data: &Self::Data,
44-
index: usize,
45-
closure: Box<dyn FnOnce(Node<'_>) + '_>,
46-
);
41+
fn child_node<'n>(&'n mut self, data: &'n Self::Data, index: usize) -> Option<Node<'n>>;
4742

4843
/// Iterate over elements as [`Tile`] items within `range`
4944
///
@@ -255,15 +250,12 @@ macro_rules! impl_slice {
255250
}
256251

257252
#[inline]
258-
fn for_node(
259-
&mut self,
260-
data: &W::Data,
253+
fn child_node<'n>(
254+
&'n mut self,
255+
data: &'n Self::Data,
261256
index: usize,
262-
closure: Box<dyn FnOnce(Node<'_>) + '_>,
263-
) {
264-
if let Some($pat) = self.get_mut(index) {
265-
closure($w.as_node(data));
266-
}
257+
) -> Option<Node<'n>> {
258+
self.get_mut(index).map(|$pat| $w.as_node(data))
267259
}
268260

269261
#[inline]

crates/kas-core/src/core/impls.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ pub fn _send<W: Events>(
4242
if let Some(index) = widget.find_child_index(&id) {
4343
let translation = widget.translation();
4444
let mut _found = false;
45-
widget.as_node(data).for_child(index, |mut node| {
45+
if let Some(mut node) = widget.as_node(data).get_child(index) {
4646
is_used = node._send(cx, id.clone(), event.clone() + translation);
4747
_found = true;
48-
});
48+
}
4949

5050
#[cfg(debug_assertions)]
5151
if !_found {
@@ -81,10 +81,10 @@ pub fn _send<W: Events>(
8181
pub fn _replay<W: Events>(widget: &mut W, cx: &mut EventCx, data: &<W as Widget>::Data, id: Id) {
8282
if let Some(index) = widget.find_child_index(&id) {
8383
let mut _found = false;
84-
widget.as_node(data).for_child(index, |mut node| {
84+
if let Some(mut node) = widget.as_node(data).get_child(index) {
8585
node._replay(cx, id.clone());
8686
_found = true;
87-
});
87+
}
8888

8989
#[cfg(debug_assertions)]
9090
if !_found {
@@ -147,7 +147,9 @@ fn nav_next(
147147
if let Some(index) = child {
148148
let mut opt_id = None;
149149
let out = &mut opt_id;
150-
widget.for_child(index, |mut node| *out = node._nav_next(cx, focus, advance));
150+
if let Some(mut node) = widget.get_child(index) {
151+
*out = node._nav_next(cx, focus, advance);
152+
}
151153
if let Some(id) = opt_id {
152154
return Some(id);
153155
}
@@ -174,7 +176,9 @@ fn nav_next(
174176
while let Some(index) = widget.nav_next(rev, child) {
175177
let mut opt_id = None;
176178
let out = &mut opt_id;
177-
widget.for_child(index, |mut node| *out = node._nav_next(cx, focus, advance));
179+
if let Some(mut node) = widget.get_child(index) {
180+
*out = node._nav_next(cx, focus, advance);
181+
}
178182
if let Some(id) = opt_id {
179183
return Some(id);
180184
}

crates/kas-core/src/core/node.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ trait NodeT {
2222

2323
fn num_children(&self) -> usize;
2424
fn find_child_index(&self, id: &Id) -> Option<usize>;
25-
fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>);
25+
fn child_node(&mut self, index: usize) -> Option<Node<'_>>;
2626

2727
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules;
2828
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints);
@@ -64,8 +64,8 @@ impl<'a, T> NodeT for (&'a mut dyn Widget<Data = T>, &'a T) {
6464
self.0.find_child_index(id)
6565
}
6666

67-
fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>) {
68-
self.0.for_child_node(self.1, index, f);
67+
fn child_node(&mut self, index: usize) -> Option<Node<'_>> {
68+
self.0.child_node(self.1, index)
6969
}
7070

7171
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
@@ -218,13 +218,12 @@ impl<'a> Node<'a> {
218218
///
219219
/// Calls the closure exactly when `index < self.num_children()`.
220220
#[inline(always)]
221-
pub fn for_child(&mut self, index: usize, f: impl FnOnce(Node<'_>)) {
222-
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(f);
221+
pub fn get_child(&mut self, index: usize) -> Option<Node<'_>> {
223222
cfg_if::cfg_if! {
224223
if #[cfg(feature = "unsafe_node")] {
225-
self.0.for_child_node(self.1, index, f);
224+
self.0.child_node(self.1, index)
226225
} else {
227-
self.0.for_child_node(index, f);
226+
self.0.child_node(index)
228227
}
229228
}
230229
}
@@ -234,12 +233,17 @@ impl<'a> Node<'a> {
234233
pub fn for_children(&mut self, mut f: impl FnMut(Node<'_>)) {
235234
for index in 0..self.0.num_children() {
236235
let f: Box<dyn for<'b> FnOnce(Node<'b>)> = Box::new(&mut f);
237-
cfg_if::cfg_if! {
238-
if #[cfg(feature = "unsafe_node")] {
239-
self.0.for_child_node(self.1, index, f);
240-
} else {
241-
self.0.for_child_node(index, f);
236+
let opt_node = {
237+
cfg_if::cfg_if! {
238+
if #[cfg(feature = "unsafe_node")] {
239+
self.0.child_node(self.1, index)
240+
} else {
241+
self.0.child_node(index)
242+
}
242243
}
244+
};
245+
if let Some(node) = opt_node {
246+
f(node);
243247
}
244248
}
245249
}
@@ -259,10 +263,12 @@ impl<'a> Node<'a> {
259263
#[inline(always)]
260264
pub fn find_node<F: FnOnce(Node<'_>) -> T, T>(&mut self, id: &Id, cb: F) -> Option<T> {
261265
if let Some(index) = self.find_child_index(id) {
262-
let mut result = None;
263-
let out = &mut result;
264-
self.for_child(index, |mut node| *out = node.find_node(id, cb));
265-
result
266+
if let Some(mut node) = self.get_child(index) {
267+
node.find_node(id, cb)
268+
} else {
269+
debug_assert!(false);
270+
None
271+
}
266272
} else if self.eq_id(id) {
267273
Some(cb(self.re()))
268274
} else {

crates/kas-core/src/core/tile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub trait Tile: Layout {
9191
///
9292
/// This method is usually implemented automatically by the `#[widget]`
9393
/// macro. It should be implemented directly if and only if
94-
/// [`Tile::get_child`] and [`Widget::for_child_node`] are
94+
/// [`Tile::get_child`] and [`Widget::child_node`] are
9595
/// implemented directly.
9696
fn num_children(&self) -> usize {
9797
unimplemented!() // make rustdoc show that this is a provided method

crates/kas-core/src/core/widget.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,9 @@ pub trait Events: Widget + Sized {
102102
for index in 0..self.num_children() {
103103
let id = self.make_child_id(index);
104104
if id.is_valid() {
105-
self.as_node(data)
106-
.for_child(index, |node| cx.configure(node, id));
105+
if let Some(node) = self.as_node(data).get_child(index) {
106+
cx.configure(node, id);
107+
}
107108
}
108109
}
109110
}
@@ -134,7 +135,9 @@ pub trait Events: Widget + Sized {
134135
/// Use [`ConfigCx::update`].
135136
fn update_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
136137
for index in 0..self.num_children() {
137-
self.as_node(data).for_child(index, |node| cx.update(node));
138+
if let Some(node) = self.as_node(data).get_child(index) {
139+
cx.update(node);
140+
}
138141
}
139142
}
140143

@@ -315,7 +318,7 @@ pub enum NavAdvance {
315318
/// - **Core** methods of [`Tile`] are *always* implemented via the [`#widget`]
316319
/// macro, whether or not an `impl Tile { ... }` item is present.
317320
/// - **Introspection** methods [`Tile::num_children`], [`Tile::get_child`]
318-
/// and [`Widget::for_child_node`] are implemented by the [`#widget`] macro
321+
/// and [`Widget::child_node`] are implemented by the [`#widget`] macro
319322
/// in most cases: child widgets embedded within a layout descriptor or
320323
/// included as fields marked with `#[widget]` are enumerated.
321324
/// - **Introspection** methods [`Tile::find_child_index`] and
@@ -362,13 +365,8 @@ pub trait Widget: Tile {
362365
///
363366
/// It is recommended to use the methods on [`Node`]
364367
/// instead of calling this method.
365-
fn for_child_node(
366-
&mut self,
367-
data: &Self::Data,
368-
index: usize,
369-
closure: Box<dyn FnOnce(Node<'_>) + '_>,
370-
) {
371-
let _ = (data, index, closure);
368+
fn child_node<'n>(&'n mut self, data: &'n Self::Data, index: usize) -> Option<Node<'n>> {
369+
let _ = (data, index);
372370
unimplemented!() // make rustdoc show that this is a provided method
373371
}
374372

crates/kas-macros/src/collection.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ impl Collection {
356356
#index => Some(&mut self.#path),
357357
});
358358
for_node_rules.append_all(quote! {
359-
#index => closure(self.#path.as_node(data)),
359+
#index => Some(self.#path.as_node(data)),
360360
});
361361
}
362362

@@ -398,16 +398,16 @@ impl Collection {
398398
_ => None,
399399
}
400400
}
401-
fn for_node(
402-
&mut self,
403-
data: &Self::Data,
401+
#[inline]
402+
fn child_node<'__n>(
403+
&'__n mut self,
404+
data: &'__n Self::Data,
404405
index: usize,
405-
closure: Box<dyn FnOnce(::kas::Node<'_>) + '_>,
406-
) {
406+
) -> Option<::kas::Node<'__n>> {
407407
use ::kas::Widget;
408408
match index {
409409
#for_node_rules
410-
_ => (),
410+
_ => None,
411411
}
412412
}
413413
};

crates/kas-macros/src/widget.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
3737

3838
let mut num_children = None;
3939
let mut get_child = None;
40-
let mut for_child_node = None;
40+
let mut child_node = None;
4141
let mut find_child_index = None;
4242
let mut make_child_id = None;
4343
for (index, impl_) in scope.impls.iter().enumerate() {
@@ -50,8 +50,8 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
5050

5151
for item in &impl_.items {
5252
if let ImplItem::Fn(ref item) = item {
53-
if item.sig.ident == "for_child_node" {
54-
for_child_node = Some(item.sig.ident.clone());
53+
if item.sig.ident == "child_node" {
54+
child_node = Some(item.sig.ident.clone());
5555
}
5656
} else if let ImplItem::Type(ref item) = item {
5757
if item.ident == "Data" {
@@ -293,11 +293,11 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
293293
if get_child.is_none() {
294294
emit_warning!(span, "fn num_children without fn get_child");
295295
}
296-
if for_child_node.is_none() {
297-
emit_warning!(span, "fn num_children without fn for_child_node");
296+
if child_node.is_none() {
297+
emit_warning!(span, "fn num_children without fn child_node");
298298
}
299299
}
300-
if let Some(span) = get_child.as_ref().or(for_child_node.as_ref()) {
300+
if let Some(span) = get_child.as_ref().or(child_node.as_ref()) {
301301
if num_children.is_none() {
302302
emit_warning!(span, "associated impl of `fn Tile::num_children` required");
303303
}
@@ -321,7 +321,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
321321
#core_path.status.require_rect(&#core_path._id);
322322
};
323323

324-
let do_impl_widget_children = get_child.is_none() && for_child_node.is_none();
324+
let do_impl_widget_children = get_child.is_none() && child_node.is_none();
325325
let fns_get_child = if do_impl_widget_children {
326326
let mut get_rules = quote! {};
327327
for (index, child) in children.iter().enumerate() {
@@ -349,7 +349,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
349349
let item_idents = collect_idents(widget_impl);
350350
let has_item = |name| item_idents.iter().any(|(_, ident)| ident == name);
351351

352-
// If the user impls Widget, they must supply type Data and fn for_child_node
352+
// If the user impls Widget, they must supply type Data and fn child_node
353353

354354
// Always impl fn as_node
355355
widget_impl.items.push(Verbatim(widget_as_node()));
@@ -841,26 +841,25 @@ pub fn impl_widget(
841841
};
842842

843843
get_mut_rules.append_all(if let Some(ref data) = child.data_binding {
844-
quote! { #i => closure(#path.as_node(#data)), }
844+
quote! { #i => Some(#path.as_node(#data)), }
845845
} else {
846846
if let Some(ref span) = child.attr_span {
847-
quote_spanned! {*span=> #i => closure(#path.as_node(data)), }
847+
quote_spanned! {*span=> #i => Some(#path.as_node(data)), }
848848
} else {
849-
quote! { #i => closure(#path.as_node(data)), }
849+
quote! { #i => Some(#path.as_node(data)), }
850850
}
851851
});
852852
}
853853

854854
quote! {
855-
fn for_child_node(
856-
&mut self,
857-
data: &Self::Data,
855+
fn child_node<'__n>(
856+
&'__n mut self,
857+
data: &'__n Self::Data,
858858
index: usize,
859-
closure: Box<dyn FnOnce(::kas::Node<'_>) + '_>,
860-
) {
859+
) -> Option<::kas::Node<'__n>> {
861860
match index {
862861
#get_mut_rules
863-
_ => (),
862+
_ => None,
864863
}
865864
}
866865
}
@@ -885,7 +884,7 @@ pub fn impl_widget(
885884
pub fn widget_as_node() -> Toks {
886885
quote! {
887886
#[inline]
888-
fn as_node<'a>(&'a mut self, data: &'a Self::Data) -> ::kas::Node<'a> {
887+
fn as_node<'__a>(&'__a mut self, data: &'__a Self::Data) -> ::kas::Node<'__a> {
889888
::kas::Node::new(self, data)
890889
}
891890
}

crates/kas-macros/src/widget_derive.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,15 @@ pub fn widget(_attr_span: Span, args: WidgetArgs, scope: &mut Scope) -> Result<(
274274

275275
// Widget methods are derived. Cost: cannot override any Events methods or translation().
276276
let fn_as_node = widget_as_node();
277-
let fn_for_child_node = quote! {
277+
let fn_child_node = quote! {
278278
#[inline]
279-
fn for_child_node(
280-
&mut self,
281-
data: &Self::Data,
279+
fn child_node<'__n>(
280+
&'__n mut self,
281+
data: &'__n Self::Data,
282282
index: usize,
283-
closure: Box<dyn FnOnce(::kas::Node<'_>) + '_>,
284-
) {
283+
) -> Option<::kas::Node<'__n>> {
285284
#map_data
286-
self.#inner.for_child_node(data, index, closure)
285+
self.#inner.child_node(data, index)
287286
}
288287
};
289288
let fn_configure = quote! {
@@ -358,8 +357,8 @@ pub fn widget(_attr_span: Span, args: WidgetArgs, scope: &mut Scope) -> Result<(
358357
widget_impl.items.push(Verbatim(fn_as_node));
359358
}
360359

361-
if !has_item("for_child_node") {
362-
widget_impl.items.push(Verbatim(fn_for_child_node));
360+
if !has_item("child_node") {
361+
widget_impl.items.push(Verbatim(fn_child_node));
363362
}
364363

365364
if !has_item("_configure") {
@@ -386,7 +385,7 @@ pub fn widget(_attr_span: Span, args: WidgetArgs, scope: &mut Scope) -> Result<(
386385
impl #impl_generics ::kas::Widget for #impl_target {
387386
type Data = #data_ty;
388387
#fn_as_node
389-
#fn_for_child_node
388+
#fn_child_node
390389
#fn_configure
391390
#fn_update
392391
#fn_send

0 commit comments

Comments
 (0)