1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-26 14:49:06 -04:00

Forbid uses of unwrap() in the code (#7795)

This commit is contained in:
Emil Ernerfeldt
2025-12-19 20:34:18 +01:00
committed by GitHub
parent 646fea2133
commit 7fe58bbfd4
44 changed files with 120 additions and 64 deletions

View File

@@ -340,6 +340,7 @@ unused_peekable = "warn"
unused_rounding = "warn"
unused_self = "warn"
unused_trait_names = "warn"
unwrap_used = "warn"
use_self = "warn"
useless_let_if_seq = "warn"
useless_transmute = "warn"
@@ -352,7 +353,6 @@ zero_sized_map_values = "warn"
comparison_chain = "allow"
should_panic_without_expect = "allow"
too_many_lines = "allow"
unwrap_used = "allow" # TODO(emilk): We really wanna warn on this one
# These are meh:
assigning_clones = "allow" # No please

View File

@@ -791,6 +791,7 @@ impl Frame {
/// This function will take the ownership of your [`glow::Texture`], so please do not delete your [`glow::Texture`] after registering.
#[cfg(all(feature = "glow", not(target_arch = "wasm32")))]
pub fn register_native_glow_texture(&mut self, native: glow::Texture) -> egui::TextureId {
#[expect(clippy::unwrap_used)]
self.glow_register_native_texture.as_mut().unwrap()(native)
}

View File

@@ -376,6 +376,7 @@ impl EpiIntegration {
fn load_default_egui_icon() -> egui::IconData {
profiling::function_scope!();
#[expect(clippy::unwrap_used)]
crate::icon_data::from_png_bytes(&include_bytes!("../../data/icon.png")[..]).unwrap()
}

View File

@@ -5,7 +5,8 @@
//! There is a bunch of improvements we could do,
//! like removing a bunch of `unwraps`.
#![allow(clippy::undocumented_unsafe_blocks)]
#![expect(clippy::undocumented_unsafe_blocks)]
#![expect(clippy::unwrap_used)]
use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc, time::Instant};

View File

@@ -27,7 +27,10 @@ pub fn create_egui_context(storage: Option<&dyn crate::Storage>) -> egui::Contex
egui_ctx.options_mut(|o| {
// eframe supports multi-pass (Context::request_discard).
o.max_passes = 2.try_into().unwrap();
#[expect(clippy::unwrap_used)]
{
o.max_passes = 2.try_into().unwrap();
}
});
let memory = crate::native::epi_integration::load_egui_memory(storage).unwrap_or_default();

View File

@@ -23,7 +23,7 @@ impl Stopwatch {
}
pub fn pause(&mut self) {
let start = self.start.take().unwrap();
let start = self.start.take().expect("Stopwatch is not running");
let duration = start.elapsed();
self.total_time_ns += duration.as_nanos();
}

View File

@@ -1,6 +1,7 @@
//! [`egui`] bindings for web apps (compiling to WASM).
#![allow(clippy::missing_errors_doc)] // So many `-> Result<_, JsValue>`
#![expect(clippy::missing_errors_doc)] // So many `-> Result<_, JsValue>`
#![expect(clippy::unwrap_used)] // TODO(emilk): remove unwraps
mod app_runner;
mod backend;

View File

@@ -1,4 +1,4 @@
#![allow(unsafe_code)]
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
use std::{borrow::Cow, num::NonZeroU64, ops::Range};

View File

@@ -1,5 +1,6 @@
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::undocumented_unsafe_blocks)]
#![expect(clippy::missing_errors_doc)]
#![expect(clippy::undocumented_unsafe_blocks)]
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
use crate::{RenderState, SurfaceErrorAction, WgpuConfiguration, renderer};
use crate::{

View File

@@ -28,6 +28,7 @@ pub struct CacheStorage {
impl CacheStorage {
pub fn cache<Cache: CacheTrait + Default>(&mut self) -> &mut Cache {
#[expect(clippy::unwrap_used)]
self.caches
.entry(std::any::TypeId::of::<Cache>())
.or_insert_with(|| Box::<Cache>::default())

View File

@@ -722,6 +722,7 @@ fn automatic_area_position(ctx: &Context, constrain_rect: Rect, layer_id: LayerI
let mut column_bbs = vec![existing[0]];
for &rect in &existing {
#[expect(clippy::unwrap_used)]
let current_column_bb = column_bbs.last_mut().unwrap();
if rect.left() < current_column_bb.right() {
// same column
@@ -752,6 +753,7 @@ fn automatic_area_position(ctx: &Context, constrain_rect: Rect, layer_id: LayerI
}
// Maybe we can fit a new column?
#[expect(clippy::unwrap_used)]
let rightmost = column_bbs.last().unwrap().right();
if rightmost + 200.0 < constrain_rect.right() {
return pos2(rightmost + spacing, top);

View File

@@ -444,11 +444,8 @@ impl SubMenu {
let mut menu_config = self.config.unwrap_or_else(|| parent_config.clone());
menu_config.bar = false;
let menu_root_response = ui
.ctx()
.read_response(menu_id)
// Since we are a child of that ui, this should always exist
.unwrap();
#[expect(clippy::unwrap_used)] // Since we are a child of that ui, this should always exist
let menu_root_response = ui.ctx().read_response(menu_id).unwrap();
let hover_pos = ui.ctx().pointer_hover_pos();

View File

@@ -584,8 +584,8 @@ impl ContextImpl {
}
}
fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::Node {
let state = self.viewport().this_pass.accesskit_state.as_mut().unwrap();
fn accesskit_node_builder(&mut self, id: Id) -> Option<&mut accesskit::Node> {
let state = self.viewport().this_pass.accesskit_state.as_mut()?;
let builders = &mut state.nodes;
if let std::collections::hash_map::Entry::Vacant(entry) = builders.entry(id) {
@@ -611,11 +611,11 @@ impl ContextImpl {
let parent_id = find_accesskit_parent(&state.parent_map, builders, id)
.unwrap_or_else(crate::accesskit_root_id);
let parent_builder = builders.get_mut(&parent_id).unwrap();
let parent_builder = builders.get_mut(&parent_id)?;
parent_builder.push_child(id.accesskit_id());
}
builders.get_mut(&id).unwrap()
builders.get_mut(&id)
}
fn pixels_per_point(&mut self) -> f32 {
@@ -3639,14 +3639,7 @@ impl Context {
id: Id,
writer: impl FnOnce(&mut accesskit::Node) -> R,
) -> Option<R> {
self.write(|ctx| {
ctx.viewport()
.this_pass
.accesskit_state
.is_some()
.then(|| ctx.accesskit_node_builder(id))
.map(writer)
})
self.write(|ctx| ctx.accesskit_node_builder(id).map(writer))
}
pub(crate) fn register_accesskit_parent(&self, id: Id, parent_id: Id) {

View File

@@ -361,7 +361,10 @@ fn hit_test_on_close(close: &[WidgetRect], pos: Pos2) -> WidgetHits {
(Some(hit_click), Some(hit_drag)) => {
// We have a perfect hit on both click and drag. Which is the topmost?
#[expect(clippy::unwrap_used)]
let click_idx = close.iter().position(|w| *w == hit_click).unwrap();
#[expect(clippy::unwrap_used)]
let drag_idx = close.iter().position(|w| *w == hit_drag).unwrap();
let click_is_on_top_of_drag = drag_idx < click_idx;

View File

@@ -1551,11 +1551,9 @@ impl InputState {
options: _,
} = self;
ui.style_mut()
.text_styles
.get_mut(&crate::TextStyle::Body)
.unwrap()
.family = crate::FontFamily::Monospace;
if let Some(style) = ui.style_mut().text_styles.get_mut(&crate::TextStyle::Body) {
style.family = crate::FontFamily::Monospace;
}
ui.collapsing("Raw Input", |ui| raw.ui(ui));

View File

@@ -288,6 +288,7 @@ impl TouchState {
// touch individually, and then calculate the average of all individual changes in
// direction. But this approach cannot be implemented locally in this method, making
// everything a bit more complicated.
#[expect(clippy::unwrap_used)] // guarded against already
let first_touch = self.active_touches.values().next().unwrap();
state.heading = (state.avg_pos - first_touch.pos).angle();
@@ -323,13 +324,14 @@ enum PinchType {
impl PinchType {
fn classify(touches: &BTreeMap<TouchId, ActiveTouch>) -> Self {
#![expect(clippy::unwrap_used)]
// For non-proportional 2d zooming:
// If the user is pinching with two fingers that have roughly the same Y coord,
// then the Y zoom is unstable and should be 1.
// Similarly, if the fingers are directly above/below each other,
// we should only zoom on the Y axis.
// If the fingers are roughly on a diagonal, we revert to the proportional zooming.
if touches.len() == 2 {
let mut touches = touches.values();
let t0 = touches.next().unwrap().pos;

View File

@@ -306,6 +306,8 @@ impl Default for Options {
zoom_with_keyboard: true,
tessellation_options: Default::default(),
repaint_on_widget_change: false,
#[expect(clippy::unwrap_used)]
max_passes: NonZeroUsize::new(2).unwrap(),
screen_reader: false,
warn_on_id_clash: cfg!(debug_assertions),

View File

@@ -142,7 +142,9 @@ impl Element {
Self::Value {
value: Box::new(t),
clone_fn: |x| {
let x = x.downcast_ref::<T>().unwrap(); // This unwrap will never panic, because we always construct this type using this `new` function and because we return &mut reference only with this type `T`, so type cannot change.
// This unwrap will never panic, because we always construct this type using this `new` function and because we return &mut reference only with this type `T`, so type cannot change.
#[expect(clippy::unwrap_used)]
let x = x.downcast_ref::<T>().unwrap();
Box::new(x.clone())
},
#[cfg(feature = "persistence")]
@@ -156,12 +158,16 @@ impl Element {
Self::Value {
value: Box::new(t),
clone_fn: |x| {
let x = x.downcast_ref::<T>().unwrap(); // This unwrap will never panic, because we always construct this type using this `new` function and because we return &mut reference only with this type `T`, so type cannot change.
// This unwrap will never panic, because we always construct this type using this `new` function and because we return &mut reference only with this type `T`, so type cannot change.
#[expect(clippy::unwrap_used)]
let x = x.downcast_ref::<T>().unwrap();
Box::new(x.clone())
},
#[cfg(feature = "persistence")]
serialize_fn: Some(|x| {
let x = x.downcast_ref::<T>().unwrap(); // This will never panic too, for same reason.
// This will never panic too, for same reason.
#[expect(clippy::unwrap_used)]
let x = x.downcast_ref::<T>().unwrap();
ron::to_string(x).ok()
}),
}
@@ -209,7 +215,9 @@ impl Element {
}
match self {
Self::Value { value, .. } => value.downcast_mut().unwrap(), // This unwrap will never panic because we already converted object to required type
// This unwrap will never panic because we already converted object to required type
#[expect(clippy::unwrap_used)]
Self::Value { value, .. } => value.downcast_mut().unwrap(),
Self::Serialized(_) => unreachable!(),
}
}
@@ -238,7 +246,9 @@ impl Element {
}
match self {
Self::Value { value, .. } => value.downcast_mut().unwrap(), // This unwrap will never panic because we already converted object to required type
// This unwrap will never panic because we already converted object to required type
#[expect(clippy::unwrap_used)]
Self::Value { value, .. } => value.downcast_mut().unwrap(),
Self::Serialized(_) => unreachable!(),
}
}
@@ -436,10 +446,14 @@ impl IdTypeMap {
let hash = hash(TypeId::of::<T>(), id);
use std::collections::hash_map::Entry;
match self.map.entry(hash) {
Entry::Vacant(vacant) => vacant
.insert(Element::new_temp(insert_with()))
.get_mut_temp()
.unwrap(), // this unwrap will never panic, because we insert correct type right now
Entry::Vacant(vacant) => {
// this unwrap will never panic, because we insert correct type right now
#[expect(clippy::unwrap_used)]
vacant
.insert(Element::new_temp(insert_with()))
.get_mut_temp()
.unwrap()
}
Entry::Occupied(occupied) => {
occupied.into_mut().get_temp_mut_or_insert_with(insert_with)
}
@@ -454,10 +468,14 @@ impl IdTypeMap {
let hash = hash(TypeId::of::<T>(), id);
use std::collections::hash_map::Entry;
match self.map.entry(hash) {
Entry::Vacant(vacant) => vacant
.insert(Element::new_persisted(insert_with()))
.get_mut_persisted()
.unwrap(), // this unwrap will never panic, because we insert correct type right now
Entry::Vacant(vacant) => {
// this unwrap will never panic, because we insert correct type right now
#[expect(clippy::unwrap_used)]
vacant
.insert(Element::new_persisted(insert_with()))
.get_mut_persisted()
.unwrap()
}
Entry::Occupied(occupied) => occupied
.into_mut()
.get_persisted_mut_or_insert_with(insert_with),

View File

@@ -135,6 +135,7 @@ where
self.flux = None;
if self.undos.back() == Some(current_state) {
#[expect(clippy::unwrap_used)] // we just checked that undos is not empty
self.redos.push(self.undos.pop_back().unwrap());
} else {
self.redos.push(current_state.clone());

View File

@@ -827,8 +827,7 @@ impl TextEdit<'_> {
hint_text_str.as_str(),
)
});
} else if selection_changed {
let cursor_range = cursor_range.unwrap();
} else if selection_changed && let Some(cursor_range) = cursor_range {
let char_range = cursor_range.primary.index..=cursor_range.secondary.index;
let info = WidgetInfo::text_selection_changed(
ui.is_enabled(),

View File

@@ -1,3 +1,5 @@
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
use std::num::NonZeroU64;
use eframe::{

View File

@@ -459,11 +459,13 @@ fn call_after_delay(delay: std::time::Duration, f: impl FnOnce() + Send + 'stati
std::thread::sleep(delay);
f();
})
.unwrap();
.expect("Failed to spawn a thread");
}
#[cfg(target_arch = "wasm32")]
fn call_after_delay(delay: std::time::Duration, f: impl FnOnce() + Send + 'static) {
#![expect(clippy::unwrap_used)]
use wasm_bindgen::prelude::*;
let window = web_sys::window().unwrap();
let closure = Closure::once(f);

View File

@@ -1,5 +1,4 @@
//! Demo app for egui
#![allow(clippy::missing_errors_doc)]
mod apps;
mod backend_panel;

View File

@@ -31,6 +31,9 @@ impl WebHandle {
}
/// Call this once from JavaScript to start your app.
///
/// # Errors
/// Returns an error if the app could not start.
#[wasm_bindgen]
pub async fn start(
&self,

View File

@@ -8,8 +8,7 @@
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
//!
#![allow(clippy::float_cmp)]
#![allow(clippy::manual_range_contains)]
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
mod demo;
pub mod easy_mark;

View File

@@ -1,3 +1,5 @@
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
mod button;
mod popup;

View File

@@ -1,9 +1,9 @@
//! Example how to use pure `egui_glow`.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![allow(clippy::undocumented_unsafe_blocks)]
#![allow(unsafe_code)]
#![expect(rustdoc::missing_crate_level_docs, clippy::unwrap_used)] // it's an example
#![expect(clippy::undocumented_unsafe_blocks)]
#![expect(unsafe_code)]
use std::num::NonZeroU32;
use std::sync::Arc;

View File

@@ -1,4 +1,5 @@
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::unwrap_used)]
#![allow(unsafe_code)]
use std::{collections::HashMap, sync::Arc};

View File

@@ -1,5 +1,6 @@
#![allow(unsafe_code)]
#![allow(clippy::undocumented_unsafe_blocks)]
#![expect(clippy::undocumented_unsafe_blocks)]
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
#![expect(unsafe_code)]
use std::convert::TryInto as _;

View File

@@ -1,4 +1,5 @@
#![allow(unsafe_code)]
#![expect(unsafe_code)]
#![expect(clippy::unwrap_used)]
use glow::HasContext as _;

View File

@@ -28,6 +28,7 @@ impl EguiGlow {
native_pixels_per_point: Option<f32>,
dithering: bool,
) -> Self {
#[expect(clippy::unwrap_used)] // TODO(emilk): return error instead of unwrap
let painter = crate::Painter::new(gl, "", shader_version, dithering)
.map_err(|err| {
log::error!("error occurred in initializing painter:\n{err}");

View File

@@ -2,6 +2,7 @@
//!
//! ## Feature flags
#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
mod builder;
#[cfg(feature = "snapshot")]

View File

@@ -233,7 +233,9 @@ pub fn format_with_decimals_in_range(value: f64, decimal_range: RangeInclusive<u
for decimals in min_decimals..max_decimals {
let text = format!("{value:.decimals$}");
let epsilon = 16.0 * f32::EPSILON; // margin large enough to handle most peoples round-tripping needs
if almost_equal(text.parse::<f32>().unwrap(), value as f32, epsilon) {
if let Ok(parsed_value) = text.parse::<f32>()
&& almost_equal(parsed_value, value as f32, epsilon)
{
// Enough precision to show the value accurately - good!
return text;
}

View File

@@ -281,7 +281,12 @@ impl Mesh {
let mesh = Mesh16 {
indices: self.indices[span_start..index_cursor]
.iter()
.map(|vi| u16::try_from(vi - min_vindex).unwrap())
.map(|vi| {
#[expect(clippy::unwrap_used)]
{
u16::try_from(vi - min_vindex).unwrap()
}
})
.collect(),
vertices: self.vertices[(min_vindex as usize)..=(max_vindex as usize)].to_vec(),
texture_id: self.texture_id,

View File

@@ -1403,6 +1403,7 @@ impl Tessellator {
});
}
#[expect(clippy::unwrap_used)] // it's never empty
let out = out_primitives.last_mut().unwrap();
if let Primitive::Mesh(out_mesh) = &mut out.primitive {

View File

@@ -1,3 +1,5 @@
#![expect(clippy::unwrap_used)] // TODO(emilk): remove unwraps
use std::sync::Arc;
use emath::{Align, GuiRounding as _, NumExt as _, Pos2, Rect, Vec2, pos2, vec2};

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs, clippy::unwrap_used)] // it's an example
use eframe::{UserEvent, egui};
use std::{cell::Cell, rc::Rc};

View File

@@ -1,3 +1,5 @@
#![expect(clippy::unwrap_used)] // It's an example
use std::{cell::Cell, io, os::fd::AsRawFd as _, rc::Rc, time::Duration};
use tokio::task::LocalSet;

View File

@@ -1,7 +1,7 @@
//! This example shows that you can use egui in parallel from multiple threads.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(clippy::unwrap_used)] // it's an example
use std::sync::mpsc;
use std::thread::JoinHandle;

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(rustdoc::missing_crate_level_docs, clippy::unwrap_used)] // it's an example
use std::sync::Arc;

View File

@@ -1,3 +1,5 @@
#![expect(clippy::unwrap_used)] // it's a test
use egui::accesskit::Role;
use egui::load::SizedTexture;
use egui::{

View File

@@ -1,6 +1,10 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![allow(clippy::undocumented_unsafe_blocks)]
#![expect(
// it's a test:
clippy::undocumented_unsafe_blocks,
clippy::unwrap_used,
rustdoc::missing_crate_level_docs
)]
// Test that we can paint to the screen using glow directly.

View File

@@ -1,5 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example
#![expect(clippy::unwrap_used, rustdoc::missing_crate_level_docs)] // it's a test
use std::sync::Arc;

View File

@@ -1,3 +1,5 @@
#![expect(clippy::unwrap_used)]
use std::{
env,
io::{self, Write as _},