Skip to content

Commit be83783

Browse files
committed
Avoid crashing if an error occurs in the layout widget update handlers
1 parent 74e35f0 commit be83783

File tree

2 files changed

+83
-26
lines changed

2 files changed

+83
-26
lines changed

editor/src/messages/layout/layout_message_handler.rs

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,10 @@ impl LayoutMessageHandler {
123123
let callback_message = match action {
124124
WidgetValueAction::Commit => (breadcrumb_trail_buttons.on_commit.callback)(&()),
125125
WidgetValueAction::Update => {
126-
let update_value = value.as_u64().expect("BreadcrumbTrailButtons update was not of type: u64");
126+
let Some(update_value) = value.as_u64() else {
127+
error!("BreadcrumbTrailButtons update was not of type: u64");
128+
return;
129+
};
127130
(breadcrumb_trail_buttons.on_update.callback)(&update_value)
128131
}
129132
};
@@ -133,7 +136,10 @@ impl LayoutMessageHandler {
133136
let callback_message = match action {
134137
WidgetValueAction::Commit => (checkbox_input.on_commit.callback)(&()),
135138
WidgetValueAction::Update => {
136-
let update_value = value.as_bool().expect("CheckboxInput update was not of type: bool");
139+
let Some(update_value) = value.as_bool() else {
140+
error!("CheckboxInput update was not of type: bool");
141+
return;
142+
};
137143
checkbox_input.checked = update_value;
138144
(checkbox_input.on_update.callback)(checkbox_input)
139145
}
@@ -208,7 +214,10 @@ impl LayoutMessageHandler {
208214
let callback_message = match action {
209215
WidgetValueAction::Commit => (curve_input.on_commit.callback)(&()),
210216
WidgetValueAction::Update => {
211-
let curve = serde_json::from_value(value).expect("CurveInput event data could not be deserialized");
217+
let Some(curve) = serde_json::from_value(value).ok() else {
218+
error!("CurveInput event data could not be deserialized");
219+
return;
220+
};
212221
curve_input.value = curve;
213222
(curve_input.on_update.callback)(curve_input)
214223
}
@@ -219,13 +228,27 @@ impl LayoutMessageHandler {
219228
Widget::DropdownInput(dropdown_input) => {
220229
let callback_message = match action {
221230
WidgetValueAction::Commit => {
222-
let update_value = value.as_u64().unwrap_or_else(|| panic!("DropdownInput commit was not of type `u64`, found {value:?}"));
223-
(dropdown_input.entries.iter().flatten().nth(update_value as usize).unwrap().on_commit.callback)(&())
231+
let Some(update_value) = value.as_u64() else {
232+
error!("DropdownInput commit was not of type `u64`, found {value:?}");
233+
return;
234+
};
235+
let Some(entry) = dropdown_input.entries.iter().flatten().nth(update_value as usize) else {
236+
error!("DropdownInput commit was not able to find entry for index {update_value}");
237+
return;
238+
};
239+
(entry.on_commit.callback)(&())
224240
}
225241
WidgetValueAction::Update => {
226-
let update_value = value.as_u64().unwrap_or_else(|| panic!("DropdownInput update was not of type `u64`, found {value:?}"));
242+
let Some(update_value) = value.as_u64() else {
243+
error!("DropdownInput update was not of type `u64`, found {value:?}");
244+
return;
245+
};
227246
dropdown_input.selected_index = Some(update_value as u32);
228-
(dropdown_input.entries.iter().flatten().nth(update_value as usize).unwrap().on_update.callback)(&())
247+
let Some(entry) = dropdown_input.entries.iter().flatten().nth(update_value as usize) else {
248+
error!("DropdownInput update was not able to find entry for index {update_value}");
249+
return;
250+
};
251+
(entry.on_update.callback)(&())
229252
}
230253
};
231254

@@ -235,12 +258,27 @@ impl LayoutMessageHandler {
235258
let callback_message = match action {
236259
WidgetValueAction::Commit => (font_input.on_commit.callback)(&()),
237260
WidgetValueAction::Update => {
238-
let update_value = value.as_object().expect("FontInput update was not of type: object");
239-
let font_family_value = update_value.get("fontFamily").expect("FontInput update does not have a fontFamily");
240-
let font_style_value = update_value.get("fontStyle").expect("FontInput update does not have a fontStyle");
261+
let Some(update_value) = value.as_object() else {
262+
error!("FontInput update was not of type: object");
263+
return;
264+
};
265+
let Some(font_family_value) = update_value.get("fontFamily") else {
266+
error!("FontInput update does not have a fontFamily");
267+
return;
268+
};
269+
let Some(font_style_value) = update_value.get("fontStyle") else {
270+
error!("FontInput update does not have a fontStyle");
271+
return;
272+
};
241273

242-
let font_family = font_family_value.as_str().expect("FontInput update fontFamily was not of type: string");
243-
let font_style = font_style_value.as_str().expect("FontInput update fontStyle was not of type: string");
274+
let Some(font_family) = font_family_value.as_str() else {
275+
error!("FontInput update fontFamily was not of type: string");
276+
return;
277+
};
278+
let Some(font_style) = font_style_value.as_str() else {
279+
error!("FontInput update fontStyle was not of type: string");
280+
return;
281+
};
244282

245283
font_input.font_family = font_family.into();
246284
font_input.font_style = font_style.into();
@@ -285,7 +323,10 @@ impl LayoutMessageHandler {
285323
responses.add(callback_message);
286324
}
287325
WidgetValueAction::Update => {
288-
let value = value.as_str().expect("NodeCatalog update was not of type String").to_string();
326+
let Some(value) = value.as_str().map(|s| s.to_string()) else {
327+
error!("NodeCatalog update was not of type String");
328+
return;
329+
};
289330
let callback_message = (node_type_input.on_update.callback)(&value);
290331
responses.add(callback_message);
291332
}
@@ -296,8 +337,11 @@ impl LayoutMessageHandler {
296337
responses.add(callback_message);
297338
}
298339
WidgetValueAction::Update => match value {
299-
Value::Number(num) => {
300-
let update_value = num.as_f64().unwrap();
340+
Value::Number(ref num) => {
341+
let Some(update_value) = num.as_f64() else {
342+
error!("NumberInput update was not of type: f64, found {value:?}");
343+
return;
344+
};
301345
number_input.value = Some(update_value);
302346
let callback_message = (number_input.on_update.callback)(number_input);
303347
responses.add(callback_message);
@@ -323,7 +367,10 @@ impl LayoutMessageHandler {
323367
let callback_message = match action {
324368
WidgetValueAction::Commit => (reference_point_input.on_commit.callback)(&()),
325369
WidgetValueAction::Update => {
326-
let update_value = value.as_str().expect("ReferencePointInput update was not of type: u64");
370+
let Some(update_value) = value.as_str() else {
371+
error!("ReferencePointInput update was not of type: u64");
372+
return;
373+
};
327374
reference_point_input.value = update_value.into();
328375
(reference_point_input.on_update.callback)(reference_point_input)
329376
}
@@ -333,7 +380,10 @@ impl LayoutMessageHandler {
333380
}
334381
Widget::PopoverButton(_) => {}
335382
Widget::RadioInput(radio_input) => {
336-
let update_value = value.as_u64().expect("RadioInput update was not of type: u64");
383+
let Some(update_value) = value.as_u64() else {
384+
error!("RadioInput update was not of type: u64");
385+
return;
386+
};
337387
radio_input.selected_index = Some(update_value as u32);
338388
let callback_message = match action {
339389
WidgetValueAction::Commit => (radio_input.entries[update_value as usize].on_commit.callback)(&()),
@@ -347,7 +397,10 @@ impl LayoutMessageHandler {
347397
let callback_message = match action {
348398
WidgetValueAction::Commit => (text_area_input.on_commit.callback)(&()),
349399
WidgetValueAction::Update => {
350-
let update_value = value.as_str().expect("TextAreaInput update was not of type: string");
400+
let Some(update_value) = value.as_str() else {
401+
error!("TextAreaInput update was not of type: string");
402+
return;
403+
};
351404
text_area_input.value = update_value.into();
352405
(text_area_input.on_update.callback)(text_area_input)
353406
}
@@ -367,7 +420,10 @@ impl LayoutMessageHandler {
367420
let callback_message = match action {
368421
WidgetValueAction::Commit => (text_input.on_commit.callback)(&()),
369422
WidgetValueAction::Update => {
370-
let update_value = value.as_str().expect("TextInput update was not of type: string");
423+
let Some(update_value) = value.as_str() else {
424+
error!("TextInput update was not of type: string");
425+
return;
426+
};
371427
text_input.value = update_value.into();
372428
(text_input.on_update.callback)(text_input)
373429
}
@@ -411,10 +467,11 @@ impl LayoutMessageHandler {
411467
self.layouts[layout_target as usize] = new_layout;
412468

413469
// Update the UI
414-
responses.add(FrontendMessage::UpdateMenuBarLayout {
415-
layout_target,
416-
layout: self.layouts[layout_target as usize].clone().unwrap_menu_layout(action_input_mapping).layout,
417-
});
470+
let Some(layout) = self.layouts[layout_target as usize].clone().as_menu_layout(action_input_mapping).map(|x| x.layout) else {
471+
error!("Called unwrap_menu_layout on a widget layout");
472+
return;
473+
};
474+
responses.add(FrontendMessage::UpdateMenuBarLayout { layout_target, layout });
418475
}
419476
}
420477
}

editor/src/messages/layout/utility_types/layout_widget.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,14 @@ pub enum Layout {
109109
}
110110

111111
impl Layout {
112-
pub fn unwrap_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) -> MenuLayout {
112+
pub fn as_menu_layout(self, action_input_mapping: &impl Fn(&MessageDiscriminant) -> Option<KeysGroup>) -> Option<MenuLayout> {
113113
if let Self::MenuLayout(mut menu) = self {
114114
menu.layout
115115
.iter_mut()
116116
.for_each(|menu_column| menu_column.children.fill_in_shortcut_actions_with_keys(action_input_mapping));
117-
menu
117+
Some(menu)
118118
} else {
119-
panic!("Called unwrap_menu_layout on a widget layout");
119+
None
120120
}
121121
}
122122

0 commit comments

Comments
 (0)