diff --git a/Cargo.toml b/Cargo.toml index e9d53e97a6c..6feabe56bce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -193,6 +193,7 @@ match_wildcard_for_single_variants = "warn" mem_forget = "warn" mismatched_target_os = "warn" mismatching_type_param_order = "warn" +missing_assert_message = "warn" missing_enforced_import_renames = "warn" missing_errors_doc = "warn" missing_safety_doc = "warn" @@ -256,7 +257,6 @@ zero_sized_map_values = "warn" # TODO(emilk): enable more of these lints: iter_over_hash_type = "allow" let_underscore_untyped = "allow" -missing_assert_message = "deny" should_panic_without_expect = "allow" too_many_lines = "allow" unwrap_used = "allow" # TODO(emilk): We really wanna warn on this one diff --git a/crates/eframe/src/stopwatch.rs b/crates/eframe/src/stopwatch.rs index 9b0136189fc..9f9db171f18 100644 --- a/crates/eframe/src/stopwatch.rs +++ b/crates/eframe/src/stopwatch.rs @@ -18,7 +18,7 @@ impl Stopwatch { } pub fn start(&mut self) { - assert!(self.start.is_none()); + assert!(self.start.is_none(), "Stopwatch already running"); self.start = Some(Instant::now()); } @@ -29,7 +29,7 @@ impl Stopwatch { } pub fn resume(&mut self) { - assert!(self.start.is_none()); + assert!(self.start.is_none(), "Stopwatch already running"); self.start = Some(Instant::now()); } diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index e8b0803b958..e93f7c86abb 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -83,7 +83,11 @@ impl Default for WrappedTextureManager { epaint::FontImage::new([0, 0]).into(), Default::default(), ); - assert_eq!(font_id, TextureId::default()); + assert_eq!( + font_id, + TextureId::default(), + "the font_id must be the same as the default TextureId" + ); Self(Arc::new(RwLock::new(tex_mngr))) } @@ -794,7 +798,10 @@ impl Context { let max_passes = self.write(|ctx| ctx.memory.options.max_passes.get()); let mut output = FullOutput::default(); - debug_assert_eq!(output.platform_output.num_completed_passes, 0); + debug_assert_eq!( + output.platform_output.num_completed_passes, 0, + "Should be 0 for the first pass" + ); loop { crate::profile_scope!( @@ -814,7 +821,10 @@ impl Context { self.begin_pass(new_input.take()); run_ui(self); output.append(self.end_pass()); - debug_assert!(0 < output.platform_output.num_completed_passes); + debug_assert!( + 0 < output.platform_output.num_completed_passes, + "Should be at least 1" + ); if !output.platform_output.requested_discard() { break; // no need for another pass @@ -3186,7 +3196,7 @@ impl Context { #[cfg(feature = "accesskit")] self.pass_state_mut(|fs| { if let Some(state) = fs.accesskit_state.as_mut() { - assert_eq!(state.parent_stack.pop(), Some(_id)); + assert_eq!(state.parent_stack.pop(), Some(_id), "Mismatched push/pop"); } }); diff --git a/crates/egui/src/hit_test.rs b/crates/egui/src/hit_test.rs index 142645f24e6..f5ae6ca21bb 100644 --- a/crates/egui/src/hit_test.rs +++ b/crates/egui/src/hit_test.rs @@ -96,10 +96,10 @@ pub fn hit_test( let hits = hit_test_on_close(&close, pos_in_layer); if let Some(drag) = hits.drag { - debug_assert!(drag.sense.drag); + debug_assert!(drag.sense.drag, "Drag widget should sense drag"); } if let Some(click) = hits.click { - debug_assert!(click.sense.click); + debug_assert!(click.sense.click, "Click widget should sense click"); } hits diff --git a/crates/egui/src/layout.rs b/crates/egui/src/layout.rs index 32fd0d03ac4..e1b3ef898cf 100644 --- a/crates/egui/src/layout.rs +++ b/crates/egui/src/layout.rs @@ -69,9 +69,9 @@ impl Region { } pub fn sanity_check(&self) { - debug_assert!(!self.min_rect.any_nan()); - debug_assert!(!self.max_rect.any_nan()); - debug_assert!(!self.cursor.any_nan()); + debug_assert!(!self.min_rect.any_nan(), "should not be NaN"); + debug_assert!(!self.max_rect.any_nan(), "should not be NaN"); + debug_assert!(!self.cursor.any_nan(), "should not be NaN"); } } @@ -392,8 +392,8 @@ impl Layout { /// ## Doing layout impl Layout { pub fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect { - debug_assert!(size.x >= 0.0 && size.y >= 0.0); - debug_assert!(!outer.is_negative()); + debug_assert!(size.x >= 0.0 && size.y >= 0.0, "size should be positive"); + debug_assert!(!outer.is_negative(), "outer should be positive"); self.align2().align_size_within_rect(size, outer) } @@ -419,7 +419,7 @@ impl Layout { } pub(crate) fn region_from_max_rect(&self, max_rect: Rect) -> Region { - debug_assert!(!max_rect.any_nan()); + debug_assert!(!max_rect.any_nan(), "should not be NaN"); let mut region = Region { min_rect: Rect::NOTHING, // temporary max_rect, @@ -452,8 +452,8 @@ impl Layout { /// Given the cursor in the region, how much space is available /// for the next widget? fn available_from_cursor_max_rect(&self, cursor: Rect, max_rect: Rect) -> Rect { - debug_assert!(!cursor.any_nan()); - debug_assert!(!max_rect.any_nan()); + debug_assert!(!cursor.any_nan(), "should not be NaN"); + debug_assert!(!max_rect.any_nan(), "should not be NaN"); // NOTE: in normal top-down layout the cursor has moved below the current max_rect, // but the available shouldn't be negative. @@ -507,7 +507,7 @@ impl Layout { avail.max.y = y; } - debug_assert!(!avail.any_nan()); + debug_assert!(!avail.any_nan(), "should not be NaN"); avail } @@ -518,7 +518,10 @@ impl Layout { /// Use `justify_and_align` to get the inner `widget_rect`. pub(crate) fn next_frame(&self, region: &Region, child_size: Vec2, spacing: Vec2) -> Rect { region.sanity_check(); - debug_assert!(child_size.x >= 0.0 && child_size.y >= 0.0); + debug_assert!( + child_size.x >= 0.0 && child_size.y >= 0.0, + "child_size should be positive" + ); if self.main_wrap { let available_size = self.available_rect_before_wrap(region).size(); @@ -598,7 +601,10 @@ impl Layout { fn next_frame_ignore_wrap(&self, region: &Region, child_size: Vec2) -> Rect { region.sanity_check(); - debug_assert!(child_size.x >= 0.0 && child_size.y >= 0.0); + debug_assert!( + child_size.x >= 0.0 && child_size.y >= 0.0, + "child_size should be positive" + ); let available_rect = self.available_rect_before_wrap(region); @@ -631,16 +637,19 @@ impl Layout { frame_rect = frame_rect.translate(Vec2::Y * (region.cursor.top() - frame_rect.top())); } - debug_assert!(!frame_rect.any_nan()); - debug_assert!(!frame_rect.is_negative()); + debug_assert!(!frame_rect.any_nan(), "frame should not be NaN"); + debug_assert!(!frame_rect.is_negative(), "frame should be positive"); frame_rect } /// Apply justify (fill width/height) and/or alignment after calling `next_space`. pub(crate) fn justify_and_align(&self, frame: Rect, mut child_size: Vec2) -> Rect { - debug_assert!(child_size.x >= 0.0 && child_size.y >= 0.0); - debug_assert!(!frame.is_negative()); + debug_assert!( + child_size.x >= 0.0 && child_size.y >= 0.0, + "child_size should be positive" + ); + debug_assert!(!frame.is_negative(), "frame should be positive"); if self.horizontal_justify() { child_size.x = child_size.x.at_least(frame.width()); // fill full width @@ -658,8 +667,8 @@ impl Layout { ) -> Rect { let frame = self.next_frame_ignore_wrap(region, size); let rect = self.align_size_within_rect(size, frame); - debug_assert!(!rect.any_nan()); - debug_assert!(!rect.is_negative()); + debug_assert!(!rect.any_nan(), "rect should not be NaN"); + debug_assert!(!rect.is_negative(), "rect should be positive"); rect } @@ -702,7 +711,7 @@ impl Layout { widget_rect: Rect, item_spacing: Vec2, ) { - debug_assert!(!cursor.any_nan()); + debug_assert!(!cursor.any_nan(), "cursor should not be NaN"); if self.main_wrap { if cursor.intersects(frame_rect.shrink(1.0)) { // make row/column larger if necessary diff --git a/crates/egui/src/placer.rs b/crates/egui/src/placer.rs index 3490eef1064..6cbc744ec7d 100644 --- a/crates/egui/src/placer.rs +++ b/crates/egui/src/placer.rs @@ -133,8 +133,8 @@ impl Placer { /// Apply justify or alignment after calling `next_space`. pub(crate) fn justify_and_align(&self, rect: Rect, child_size: Vec2) -> Rect { - debug_assert!(!rect.any_nan()); - debug_assert!(!child_size.any_nan()); + debug_assert!(!rect.any_nan(), "rect should not be NaN"); + debug_assert!(!child_size.any_nan(), "child_size should not be NaN"); if let Some(grid) = &self.grid { grid.justify_and_align(rect, child_size) @@ -164,8 +164,8 @@ impl Placer { widget_rect: Rect, item_spacing: Vec2, ) { - debug_assert!(!frame_rect.any_nan()); - debug_assert!(!widget_rect.any_nan()); + debug_assert!(!frame_rect.any_nan(), "frame_rect should not be NaN"); + debug_assert!(!widget_rect.any_nan(), "widget_rect should not be NaN"); self.region.sanity_check(); if let Some(grid) = &mut self.grid { diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 6940a587589..6f44774dcac 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -1145,7 +1145,10 @@ impl Response { /// /// You may not call [`Self::interact`] on the resulting `Response`. pub fn union(&self, other: Self) -> Self { - assert!(self.ctx == other.ctx); + assert!( + self.ctx == other.ctx, + "Responses must be from the same `Ui`" + ); debug_assert!( self.layer_id == other.layer_id, "It makes no sense to combine Responses from two different layers" diff --git a/crates/egui/src/text_selection/text_cursor_state.rs b/crates/egui/src/text_selection/text_cursor_state.rs index dc75c7dd864..61edfc31c81 100644 --- a/crates/egui/src/text_selection/text_cursor_state.rs +++ b/crates/egui/src/text_selection/text_cursor_state.rs @@ -329,7 +329,10 @@ pub fn byte_index_from_char_index(s: &str, char_index: usize) -> usize { } pub fn slice_char_range(s: &str, char_range: std::ops::Range) -> &str { - assert!(char_range.start <= char_range.end); + assert!( + char_range.start <= char_range.end, + "start must be less than or equal to end" + ); let start_byte = byte_index_from_char_index(s, char_range.start); let end_byte = byte_index_from_char_index(s, char_range.end); &s[start_byte..end_byte] diff --git a/crates/egui/src/text_selection/visuals.rs b/crates/egui/src/text_selection/visuals.rs index d86f9dc56c2..7a36dcf16c0 100644 --- a/crates/egui/src/text_selection/visuals.rs +++ b/crates/egui/src/text_selection/visuals.rs @@ -59,7 +59,11 @@ pub fn paint_text_selection( // Start by appending the selection rectangle to end of the mesh, as two triangles (= 6 indices): let num_indices_before = mesh.indices.len(); mesh.add_colored_rect(rect, color); - assert_eq!(num_indices_before + 6, mesh.indices.len()); + assert_eq!( + num_indices_before + 6, + mesh.indices.len(), + "We expect exactly 6 new indices" + ); // Copy out the new triangles: let selection_triangles = [ diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 9db1404d939..b1b588992cd 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -285,7 +285,7 @@ impl Ui { } } - debug_assert!(!max_rect.any_nan()); + debug_assert!(!max_rect.any_nan(), "max_rect should not be NaN"); let stable_id = self.id.with(id_salt); let unique_id = stable_id.with(self.next_auto_id_salt); let next_auto_id_salt = unique_id.value().wrapping_add(1); @@ -901,14 +901,14 @@ impl Ui { /// Set the minimum width of the ui. /// This can't shrink the ui, only make it larger. pub fn set_min_width(&mut self, width: f32) { - debug_assert!(0.0 <= width); + debug_assert!(0.0 <= width, "width must be larger than or equal to 0.0"); self.placer.set_min_width(width); } /// Set the minimum height of the ui. /// This can't shrink the ui, only make it larger. pub fn set_min_height(&mut self, height: f32) { - debug_assert!(0.0 <= height); + debug_assert!(0.0 <= height, "height must be larger than or equal to 0.0"); self.placer.set_min_height(height); } @@ -1275,7 +1275,7 @@ impl Ui { fn allocate_space_impl(&mut self, desired_size: Vec2) -> Rect { let item_spacing = self.spacing().item_spacing; let frame_rect = self.placer.next_space(desired_size, item_spacing); - debug_assert!(!frame_rect.any_nan()); + debug_assert!(!frame_rect.any_nan(), "frame_rect should not be NaN"); let widget_rect = self.placer.justify_and_align(frame_rect, desired_size); self.placer @@ -1297,7 +1297,7 @@ impl Ui { /// Allocate a rect without interacting with it. pub fn advance_cursor_after_rect(&mut self, rect: Rect) -> Id { - debug_assert!(!rect.any_nan()); + debug_assert!(!rect.any_nan(), "rect should not be NaN"); let item_spacing = self.spacing().item_spacing; self.placer.advance_after_rects(rect, rect, item_spacing); register_rect(self, rect); @@ -1367,7 +1367,10 @@ impl Ui { layout: Layout, add_contents: Box R + 'c>, ) -> InnerResponse { - debug_assert!(desired_size.x >= 0.0 && desired_size.y >= 0.0); + debug_assert!( + desired_size.x >= 0.0 && desired_size.y >= 0.0, + "desired_size should be positive" + ); let item_spacing = self.spacing().item_spacing; let frame_rect = self.placer.next_space(desired_size, item_spacing); let child_rect = self.placer.justify_and_align(frame_rect, desired_size); diff --git a/crates/egui/src/widgets/label.rs b/crates/egui/src/widgets/label.rs index b6ade45ae30..c90a53ff061 100644 --- a/crates/egui/src/widgets/label.rs +++ b/crates/egui/src/widgets/label.rs @@ -180,7 +180,10 @@ impl Label { let cursor = ui.cursor(); let first_row_indentation = available_width - ui.available_size_before_wrap().x; - debug_assert!(first_row_indentation.is_finite()); + debug_assert!( + first_row_indentation.is_finite(), + "first_row_indentation should be finite" + ); layout_job.wrap.max_width = available_width; layout_job.first_row_min_height = cursor.height(); diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 3c2bb973f88..12ed7f26384 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -1058,7 +1058,7 @@ fn value_from_normalized(normalized: f64, range: RangeInclusive, spec: &Sli let log = lerp(min_log..=max_log, normalized); 10.0_f64.powf(log) } else { - assert!(min < 0.0 && 0.0 < max); + assert!(min < 0.0 && 0.0 < max, "You should use a logarithmic range"); let zero_cutoff = logarithmic_zero_cutoff(min, max); if normalized < zero_cutoff { // negative @@ -1107,7 +1107,7 @@ fn normalized_from_value(value: f64, range: RangeInclusive, spec: &SliderSp let value_log = value.log10(); remap_clamp(value_log, min_log..=max_log, 0.0..=1.0) } else { - assert!(min < 0.0 && 0.0 < max); + assert!(min < 0.0 && 0.0 < max, "You should use a logarithmic range"); let zero_cutoff = logarithmic_zero_cutoff(min, max); if value < 0.0 { // negative @@ -1135,8 +1135,8 @@ fn normalized_from_value(value: f64, range: RangeInclusive, spec: &SliderSp } fn range_log10(min: f64, max: f64, spec: &SliderSpec) -> (f64, f64) { - assert!(spec.logarithmic); - assert!(min <= max); + assert!(spec.logarithmic, "You should use a logarithmic range"); + assert!(min <= max, "min must be less than or equal to max"); if min == 0.0 && max == INFINITY { (spec.smallest_positive.log10(), INF_RANGE_MAGNITUDE) @@ -1160,7 +1160,7 @@ fn range_log10(min: f64, max: f64, spec: &SliderSpec) -> (f64, f64) { /// where to put the zero cutoff for logarithmic sliders /// that crosses zero ? fn logarithmic_zero_cutoff(min: f64, max: f64) -> f64 { - assert!(min < 0.0 && 0.0 < max); + assert!(min < 0.0 && 0.0 < max, "min and max must straddle zero"); let min_magnitude = if min == -INFINITY { INF_RANGE_MAGNITUDE diff --git a/crates/egui/src/widgets/text_edit/text_buffer.rs b/crates/egui/src/widgets/text_edit/text_buffer.rs index ea3992c57e4..e3d7eb1123c 100644 --- a/crates/egui/src/widgets/text_edit/text_buffer.rs +++ b/crates/egui/src/widgets/text_edit/text_buffer.rs @@ -205,7 +205,10 @@ impl TextBuffer for String { } fn delete_char_range(&mut self, char_range: Range) { - assert!(char_range.start <= char_range.end); + assert!( + char_range.start <= char_range.end, + "end must be greater than or equal to start" + ); // Get both byte indices let byte_start = byte_index_from_char_index(self.as_str(), char_range.start); diff --git a/crates/egui_demo_lib/src/rendering_test.rs b/crates/egui_demo_lib/src/rendering_test.rs index 3ae4f111808..6994cbb0623 100644 --- a/crates/egui_demo_lib/src/rendering_test.rs +++ b/crates/egui_demo_lib/src/rendering_test.rs @@ -277,7 +277,7 @@ fn vertex_gradient(ui: &mut Ui, bg_fill: Color32, gradient: &Gradient) -> Respon } { let n = gradient.0.len(); - assert!(n >= 2); + assert!(n >= 2, "Need at least two colors for a gradient"); let mut mesh = Mesh::default(); for (i, &color) in gradient.0.iter().enumerate() { let t = i as f32 / (n as f32 - 1.0); @@ -562,8 +562,8 @@ fn blending_and_feathering_test(ui: &mut Ui) { } fn text_on_bg(ui: &mut egui::Ui, fg: Color32, bg: Color32) { - assert!(fg.is_opaque()); - assert!(bg.is_opaque()); + assert!(fg.is_opaque(), "Text color must be opaque"); + assert!(bg.is_opaque(), "Background color must be opaque"); ui.horizontal(|ui| { ui.label( diff --git a/crates/egui_extras/src/loaders/file_loader.rs b/crates/egui_extras/src/loaders/file_loader.rs index 5d1b45fb493..8b762887bc0 100644 --- a/crates/egui_extras/src/loaders/file_loader.rs +++ b/crates/egui_extras/src/loaders/file_loader.rs @@ -96,7 +96,7 @@ impl BytesLoader for FileLoader { Err(err) => Err(err.to_string()), }; let prev = cache.lock().insert(uri.clone(), Poll::Ready(result)); - assert!(matches!(prev, Some(Poll::Pending))); + assert!(matches!(prev, Some(Poll::Pending)), "unexpected state"); ctx.request_repaint(); log::trace!("finished loading {uri:?}"); } diff --git a/crates/egui_extras/src/sizing.rs b/crates/egui_extras/src/sizing.rs index 770306770df..e6d4c0047d8 100644 --- a/crates/egui_extras/src/sizing.rs +++ b/crates/egui_extras/src/sizing.rs @@ -32,7 +32,10 @@ impl Size { /// Relative size relative to all available space. Values must be in range `0.0..=1.0`. pub fn relative(fraction: f32) -> Self { - debug_assert!(0.0 <= fraction && fraction <= 1.0); + debug_assert!( + 0.0 <= fraction && fraction <= 1.0, + "Values must be in range 0.0..=1.0" + ); Self::Relative { fraction, range: Rangef::new(0.0, f32::INFINITY), @@ -121,7 +124,10 @@ impl Sizing { .map(|&size| match size { Size::Absolute { initial, .. } => initial, Size::Relative { fraction, range } => { - assert!(0.0 <= fraction && fraction <= 1.0); + assert!( + 0.0 <= fraction && fraction <= 1.0, + "Values must be in range 0.0..=1.0" + ); range.clamp(length * fraction) } Size::Remainder { .. } => { diff --git a/crates/egui_extras/src/syntax_highlighting.rs b/crates/egui_extras/src/syntax_highlighting.rs index 293fbde007f..9fdd384c050 100644 --- a/crates/egui_extras/src/syntax_highlighting.rs +++ b/crates/egui_extras/src/syntax_highlighting.rs @@ -493,8 +493,11 @@ impl Highlighter { fn as_byte_range(whole: &str, range: &str) -> std::ops::Range { let whole_start = whole.as_ptr() as usize; let range_start = range.as_ptr() as usize; - assert!(whole_start <= range_start); - assert!(range_start + range.len() <= whole_start + whole.len()); + assert!(whole_start <= range_start, "range must be within whole"); + assert!( + range_start + range.len() <= whole_start + whole.len(), + "range must be within whole" + ); let offset = range_start - whole_start; offset..(offset + range.len()) } diff --git a/crates/egui_glow/src/painter.rs b/crates/egui_glow/src/painter.rs index f8f6145c8a0..b40ff103570 100644 --- a/crates/egui_glow/src/painter.rs +++ b/crates/egui_glow/src/painter.rs @@ -469,7 +469,7 @@ impl Painter { #[inline(never)] // Easier profiling fn paint_mesh(&mut self, mesh: &Mesh) { - debug_assert!(mesh.is_valid()); + debug_assert!(mesh.is_valid(), "Invalid mesh"); if let Some(texture) = self.texture(mesh.texture_id) { unsafe { self.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo)); @@ -560,7 +560,11 @@ impl Painter { data: &[u8], ) { crate::profile_function!(); - assert_eq!(data.len(), w * h * 4); + assert_eq!( + data.len(), + w * h * 4, + "Mismatch between texture size and texel count" + ); assert!( w <= self.max_texture_side && h <= self.max_texture_side, "Got a texture image of size {}x{}, but the maximum supported texture side is only {}", diff --git a/crates/epaint/benches/benchmark.rs b/crates/epaint/benches/benchmark.rs index e723638b849..8549b387610 100644 --- a/crates/epaint/benches/benchmark.rs +++ b/crates/epaint/benches/benchmark.rs @@ -53,7 +53,7 @@ fn tessellate_circles(c: &mut Criterion) { clipped_shapes.push(ClippedShape { clip_rect, shape }); } } - assert_eq!(clipped_shapes.len(), 100_000); + assert_eq!(clipped_shapes.len(), 100_000, "100k circles"); let pixels_per_point = 2.0; let options = TessellationOptions::default();