Issues ranked by severity. Check the box when implemented.
-
1.
toggle_group.rslines 51, 71 — division by zero on empty items Bothinput_toggle_groupanddraw_toggle_groupcomputebounds.size.w / state.items.len()with no guard for an empty list. Same bug that was just fixed inlist_view.rs: addif state.items.is_empty() { return; }before the division in both functions. -
2.
list_view.rsline 97 — latent panic in Enter-key path The!is_empty()guard was added, butitems[state.selected]is still an unchecked index. If the list is shortened externally afterselectedwas set, this panics. Fix: usestate.items.get(state.selected)and handleNone.
-
3.
layouts.rsline 144 — hbox reads.hinstead of.wfor horizontal flex space// current (wrong): let avail_horizontal_space = (available_space - padding).h - kids_sum; // correct: let avail_horizontal_space = available_space.w - kids_sum;
Also double-subtracts
padding(already removed fromavailable_spaceon line 126). The existing test uses a square 200×200 scene sow == hand the bug is invisible. On any non-square display (e.g. 320×240) flex children get the wrong width. -
4.
scene.rslines 290–297 —move_view_to_parentdoesn't update theparentsmap The function pusheschildinto the new parent'schildrenlist but never callsself.parents.insert(child.clone(), parent.clone()). After a move,get_parent_for_view(child)still returns the old parent. The test only assertsget_children_idslength, not the parent side. -
5.
scene.rslines 299–306 —remove_parent_and_childrenleaks grandchildrenself.remove_view(&kid)only removes fromself.keys; it does not touchself.childrenorself.parents. Any grandchildren of a removed child remain as orphaned entries in all three maps. Fix: replace the two inner calls with a recursiveself.remove_parent_and_children(&kid). -
6.
geom.rslines 138–139, 214–221 — silentu32 → i32cast inscaled()let s = scale as i32wraps silently ifscale > i32::MAX. Fix: usescale.min(i32::MAX as u32) as i32or change the parameter type toi32.
-
7.
scene.rslines 63–67, 370–373 —is_some()+unwrap()pairs// current: if self.focused.is_some() { let fo = self.focused.as_ref().unwrap().clone(); } // fix: if let Some(fo) = self.focused.clone() { ... }
Triggers
clippy::unnecessary_unwrap. Appears inset_focusedandevent_at_focused. -
8.
scene.rsline 341 —&Vec<Callback>parameter should be&[Callback]The function only iterates;&[T]is the idiomatic slice reference. Triggersclippy::ptr_arg. -
9.
scene.rslines 139–147 —.map(...).flatten()should be.filter_map(...).map(f).flatten()wherefreturnsOptionis exactly what.filter_map(f)does. Triggersclippy::map_flatten. -
10.
grid.rslines 191–195 —Intoimpl instead ofFrom, placed in wrong module// current (in grid.rs): impl Into<ViewId> for &'static str { ... } // fix (move to view.rs): impl From<&'static str> for ViewId { ... }
The blanket impl provides
Intoautomatically fromFrom. Keeping it ingrid.rsmeans it only applies whengridis in scope. -
11.
grid.rslines 154–158 — empty dead-codeif Shrink {}branches Two emptyif view.h_flex == Shrink {}/if view.v_flex == Shrink {}blocks do nothing and should be removed. -
12.
layouts.rslines 18–20, 115–116, 207, 215 —.clone()onCopytypesInsets,Flex,Size, andBoundsall deriveCopy. Calling.clone()on them is redundant and misleads readers. Remove the.clone()calls on these types throughoutlayouts.rs. -
13.
layouts.rslines 41–46 —returninside afoldclosurereturninside a closure returns from the closure, not the outer function — it works but is unusual and misleading. Replace with a direct expression.
-
14.
label.rs,text_input.rs— take&'static strinstead of&ViewIdEvery other widget constructor (make_button,make_panel,make_toggle_group, etc.) acceptsname: &ViewId. These two can't accept runtime-generated names. Fix: change signatures toname: &ViewId. -
15.
list_view.rsline 44,toggle_group.rsline 35 — constructors returnBox<dyn Any>ListState::new_withandSelectOneOfState::new_witherase their own type at construction. They should returnSelf; boxing can be done at the call site whereOption<Box<dyn Any>>is needed. -
16.
panel.rs,toggle_button.rs—PanelState::new()should implementDefaultBoth have a no-argumentnew()that creates canonical zero-state. These should use#[derive(Default)]or an explicitimpl Defaultso they work with spread syntax and generic bounds.
-
17.
scene.rslines 129–135 —get_children_idsclones the fullVecon every call Called repeatedly per frame in layout, draw, and pick paths. Each clone heap-allocates allViewIdstrings. Fix: return&[ViewId](requires lifetime annotation) or at minimum use aCow. -
18.
scene.rslines 416–424 —draw_sceneignoresdirty_rectfor cullingdirty_rectis carefully maintained butdraw_scenealways clears and redraws the entire view tree on every dirty frame. For embedded displays where partial redraws matter,draw_viewshould skip subtrees whose global bounds don't intersectdirty_rect.
-
19.
geom.rsline 11 — magic-99sentinel inSize::empty()Size { w: -99, h: -99 }is indistinguishable from an arithmetic underflow bug.is_empty()treats anyw < 1 || h < 1as empty, soSize { w: 0, h: 0 }works and is less surprising. -
20.
text_input.rs— byte cursor assumes ASCII, no enforcementcursor_forward/cursor_backmove by 1 byte.String::insert/removepanic on multi-byte character boundaries.TypedAscii(u8)keeps this safe today, but there is no compile-time or runtime guard. At minimum, add a comment documenting the ASCII-only assumption. Full fix: usechar_indices()for cursor navigation.
No unsafe code was found anywhere in the codebase.