From e673daed3836b97194dff23ae181c720bdcd34d7 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 18 Mar 2026 11:20:13 +0100 Subject: [PATCH 1/3] Update MSRV to 1.92 --- Cargo.toml | 2 +- clippy.toml | 2 +- rust-toolchain.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index db96b166..c9ce9139 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = ["puffin", "puffin_egui", "puffin_http", "puffin_viewer"] [workspace.package] edition = "2024" license = "MIT OR Apache-2.0" -rust-version = "1.87" +rust-version = "1.92.0" [workspace.dependencies] anyhow = "1.0.99" diff --git a/clippy.toml b/clippy.toml index 2dfd3167..e82c33a2 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.87.0" +msrv = "1.92.0" avoid-breaking-exported-api = false allow-expect-in-tests = true diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 598cea75..ce5b5098 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -5,6 +5,6 @@ # to the user in the error, instead of "error: invalid channel name '[toolchain]'". [toolchain] -channel = "1.87" # Avoid specifying a patch version here; see https://github.com/emilk/eframe_template/issues/145 +channel = "1.92.0" components = ["rustfmt", "clippy"] targets = ["wasm32-unknown-unknown"] From 22b65d28a1de6ffc2fe6597d5fdb553221c731ac Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 18 Mar 2026 11:20:21 +0100 Subject: [PATCH 2/3] Enable more lints --- Cargo.toml | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c9ce9139..513a7807 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,25 +80,33 @@ as_ptr_cast_mut = "warn" await_holding_lock = "warn" bool_to_int_with_if = "warn" branches_sharing_code = "warn" -cast_lossless = "warn" +cast_possible_truncation = "warn" # This might be too much +cast_possible_wrap = "warn" char_lit_as_u8 = "warn" checked_conversions = "warn" clear_with_drain = "warn" +clone_on_ref_ptr = "warn" cloned_instead_of_copied = "warn" +coerce_container_to_any = "warn" +comparison_chain = "warn" dbg_macro = "warn" debug_assert_with_mut_call = "warn" default_union_representation = "warn" derive_partial_eq_without_eq = "warn" -disallowed_macros = "warn" -disallowed_methods = "warn" -disallowed_names = "warn" -disallowed_script_idents = "warn" -disallowed_types = "warn" +disallowed_macros = "warn" # See clippy.toml +disallowed_methods = "warn" # See clippy.toml +disallowed_names = "warn" # See clippy.toml +disallowed_script_idents = "warn" # See clippy.toml +disallowed_types = "warn" # See clippy.toml +doc_broken_link = "warn" +doc_comment_double_space_linebreaks = "warn" +doc_include_without_cfg = "warn" doc_link_with_quotes = "warn" doc_markdown = "warn" +elidable_lifetime_names = "warn" empty_enum = "warn" -empty_line_after_outer_attr = "warn" empty_enum_variants_with_brackets = "warn" +empty_line_after_outer_attr = "warn" enum_glob_use = "warn" equatable_if_let = "warn" exit = "warn" @@ -115,15 +123,17 @@ fn_to_numeric_cast_any = "warn" from_iter_instead_of_collect = "warn" get_unwrap = "warn" if_let_mutex = "warn" +ignore_without_reason = "warn" implicit_clone = "warn" implied_bounds_in_impls = "warn" imprecise_flops = "warn" -indexing_slicing = "warn" +inconsistent_struct_constructor = "warn" index_refutable_slice = "warn" inefficient_to_string = "warn" infinite_loop = "warn" into_iter_without_iter = "warn" invalid_upcast_comparisons = "warn" +ip_constant = "warn" iter_filter_is_ok = "warn" iter_filter_is_some = "warn" iter_not_returning_iterator = "warn" @@ -132,6 +142,7 @@ iter_on_single_items = "warn" iter_over_hash_type = "warn" iter_without_into_iter = "warn" large_digit_groups = "warn" +large_futures = "warn" large_include_file = "warn" large_stack_arrays = "warn" large_stack_frames = "warn" @@ -149,11 +160,11 @@ manual_instant_elapsed = "warn" manual_is_power_of_two = "warn" manual_is_variant_and = "warn" manual_let_else = "warn" +manual_midpoint = "warn" manual_ok_or = "warn" manual_string_new = "warn" map_err_ignore = "warn" map_flatten = "warn" -map_unwrap_or = "warn" match_bool = "warn" match_same_arms = "warn" match_wild_err_arm = "warn" @@ -164,7 +175,6 @@ missing_assert_message = "warn" missing_enforced_import_renames = "warn" missing_errors_doc = "warn" missing_safety_doc = "warn" -mod_module_files = "warn" mixed_attributes_style = "warn" mut_mut = "warn" mutex_integer = "warn" @@ -174,12 +184,16 @@ needless_for_each = "warn" needless_pass_by_ref_mut = "warn" needless_pass_by_value = "warn" negative_feature_names = "warn" +non_std_lazy_statics = "warn" non_zero_suggestions = "warn" nonstandard_macro_braces = "warn" +only_used_in_recursion = "warn" option_as_ref_cloned = "warn" option_option = "warn" +or_fun_call = "warn" path_buf_push_overwrite = "warn" pathbuf_init_then_push = "warn" +precedence_bits = "warn" print_stderr = "warn" print_stdout = "warn" ptr_as_ptr = "warn" @@ -193,20 +207,21 @@ ref_as_ptr = "warn" ref_option_ref = "warn" ref_patterns = "warn" rest_pat_in_fully_bound_structs = "warn" +return_and_then = "warn" same_functions_in_if_condition = "warn" +self_only_used_in_recursion = "warn" semicolon_if_nothing_returned = "warn" set_contains_or_insert = "warn" should_panic_without_expect = "warn" -significant_drop_tightening = "warn" single_char_pattern = "warn" single_match_else = "warn" +single_option_map = "warn" str_split_at_newline = "warn" str_to_string = "warn" string_add = "warn" string_add_assign = "warn" string_lit_as_bytes = "warn" string_lit_chars_any = "warn" -string_to_string = "warn" suspicious_command_arg_space = "warn" suspicious_xor_used_as_pow = "warn" todo = "warn" @@ -216,19 +231,22 @@ trailing_empty_array = "warn" trait_duplication_in_bounds = "warn" transmute_ptr_to_ptr = "warn" tuple_array_conversions = "warn" -unchecked_duration_subtraction = "warn" +unchecked_time_subtraction = "warn" undocumented_unsafe_blocks = "warn" unimplemented = "warn" uninhabited_references = "warn" uninlined_format_args = "warn" unnecessary_box_returns = "warn" unnecessary_safety_comment = "warn" +unnecessary_debug_formatting = "warn" unnecessary_literal_bound = "warn" unnecessary_safety_doc = "warn" unnecessary_self_imports = "warn" +unnecessary_semicolon = "warn" unnecessary_struct_initialization = "warn" unnecessary_wraps = "warn" unnested_or_patterns = "warn" +unused_async = "warn" unused_peekable = "warn" unused_rounding = "warn" unused_self = "warn" From d8480d1b9ce2d3d4cae37777f3b7b48a69b3ac71 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 18 Mar 2026 11:21:10 +0100 Subject: [PATCH 3/3] Some clippy fixes --- puffin/src/profile_view.rs | 20 ++++++------- puffin/src/utils.rs | 35 +++++++++++----------- puffin_egui/src/flamegraph.rs | 16 +++++----- puffin_egui/src/lib.rs | 55 +++++++++++++++-------------------- puffin_http/src/client.rs | 6 ++-- puffin_http/src/server.rs | 6 ++-- 6 files changed, 65 insertions(+), 73 deletions(-) diff --git a/puffin/src/profile_view.rs b/puffin/src/profile_view.rs index 21999b48..8c54d4fa 100644 --- a/puffin/src/profile_view.rs +++ b/puffin/src/profile_view.rs @@ -67,16 +67,16 @@ impl FrameView { self.scope_collection.insert(new_scope.clone()); } - if let Some(last) = self.recent.iter().last() { - if new_frame.frame_index() <= last.0.frame_index() { - // A frame from the past!? - // Likely we are `puffin_viewer`, and the server restarted. - // The safe choice is to clear everything: - self.stats.clear(); - self.recent.clear(); - self.slowest_by_index.clear(); - self.slowest_by_duration.clear(); - } + if let Some(last) = self.recent.iter().last() + && new_frame.frame_index() <= last.0.frame_index() + { + // A frame from the past!? + // Likely we are `puffin_viewer`, and the server restarted. + // The safe choice is to clear everything: + self.stats.clear(); + self.recent.clear(); + self.slowest_by_index.clear(); + self.slowest_by_duration.clear(); } if let Some(last) = self.recent.iter().last() { diff --git a/puffin/src/utils.rs b/puffin/src/utils.rs index 1c4c7a16..67974073 100644 --- a/puffin/src/utils.rs +++ b/puffin/src/utils.rs @@ -38,24 +38,23 @@ pub fn shorten_rust_function_name(name: &str) -> String { } // look for: ::function_name - if let Some(end_caret) = name.rfind('>') { - if let Some(trait_as) = name.rfind(" as ") { - if trait_as < end_caret { - let concrete_name = if let Some(start_caret) = name[..trait_as].rfind('<') { - &name[start_caret + 1..trait_as] - } else { - name - }; - - let trait_name = &name[trait_as + 4..end_caret]; - - let concrete_name = last_part(concrete_name); - let trait_name = last_part(trait_name); - - let dubcolon_function_name = &name[end_caret + 1..]; - return format!("<{concrete_name} as {trait_name}>{dubcolon_function_name}"); - } - } + if let Some(end_caret) = name.rfind('>') + && let Some(trait_as) = name.rfind(" as ") + && trait_as < end_caret + { + let concrete_name = if let Some(start_caret) = name[..trait_as].rfind('<') { + &name[start_caret + 1..trait_as] + } else { + name + }; + + let trait_name = &name[trait_as + 4..end_caret]; + + let concrete_name = last_part(concrete_name); + let trait_name = last_part(trait_name); + + let dubcolon_function_name = &name[end_caret + 1..]; + return format!("<{concrete_name} as {trait_name}>{dubcolon_function_name}"); } if let Some(colon) = name.rfind("::") { diff --git a/puffin_egui/src/flamegraph.rs b/puffin_egui/src/flamegraph.rs index 72e27ae3..71d71935 100644 --- a/puffin_egui/src/flamegraph.rs +++ b/puffin_egui/src/flamegraph.rs @@ -649,12 +649,12 @@ fn paint_record( }; if info.response.double_clicked() { - if let Some(mouse_pos) = info.response.interact_pointer_pos() { - if rect.contains(mouse_pos) { - options - .scope_name_filter - .set_filter(scope_details.name().to_string()); - } + if let Some(mouse_pos) = info.response.interact_pointer_pos() + && rect.contains(mouse_pos) + { + options + .scope_name_filter + .set_filter(scope_details.name().to_string()); } } else if is_hovered && info.response.clicked() { options.zoom_to_relative_ns_range = Some(( @@ -819,7 +819,7 @@ fn paint_merge_scope( format!("{}x ", merge.num_pieces) } } else { - let is_integral = merge.num_pieces % info.num_frames == 0; + let is_integral = merge.num_pieces.is_multiple_of(info.num_frames); if is_integral { format!("{}x ", merge.num_pieces / info.num_frames) } else { @@ -939,7 +939,7 @@ fn merge_scope_tooltip( if merge.num_pieces == num_frames { ui.monospace("1 call / frame"); - } else if merge.num_pieces % num_frames == 0 { + } else if merge.num_pieces.is_multiple_of(num_frames) { ui.monospace(format!("{} calls / frame", merge.num_pieces / num_frames)); } else { ui.monospace(format!( diff --git a/puffin_egui/src/lib.rs b/puffin_egui/src/lib.rs index 49805dcd..dc8fdc3d 100644 --- a/puffin_egui/src/lib.rs +++ b/puffin_egui/src/lib.rs @@ -279,17 +279,13 @@ pub struct Paused { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Default)] pub enum View { + #[default] Flamegraph, Stats, } -impl Default for View { - fn default() -> Self { - Self::Flamegraph - } -} - /// Contains settings for the profiler. #[derive(Clone)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -518,16 +514,16 @@ impl ProfilerUi { || space_pressed { let latest = frame_view.latest_frame(); - if let Some(latest) = latest { - if let Ok(latest) = latest.unpacked() { - self.pause_and_select( - frame_view, - SelectedFrames::from_vec1( - frame_view.scope_collection(), - vec1::vec1![latest], - ), - ); - } + if let Some(latest) = latest + && let Ok(latest) = latest.unpacked() + { + self.pause_and_select( + frame_view, + SelectedFrames::from_vec1( + frame_view.scope_collection(), + vec1::vec1![latest], + ), + ); } } }); @@ -649,10 +645,10 @@ impl ProfilerUi { ui.style_mut().wrap_mode = Some(TextWrapMode::Extend); ui.add_space(16.0); // make it a bit more centered ui.label("Slowest:"); - if let Some(frame_view) = frame_view.as_mut() { - if ui.button("Clear").clicked() { - frame_view.clear_slowest(); - } + if let Some(frame_view) = frame_view.as_mut() + && ui.button("Clear").clicked() + { + frame_view.clear_slowest(); } }); @@ -761,18 +757,15 @@ impl ProfilerUi { }); } - if response.dragged() { - if let (Some(start), Some(curr)) = + if response.dragged() + && let (Some(start), Some(curr)) = ui.input(|i| (i.pointer.press_origin(), i.pointer.interact_pos())) - { - let min_x = start.x.min(curr.x); - let max_x = start.x.max(curr.x); - let intersects = min_x <= frame_rect.right() && frame_rect.left() <= max_x; - if intersects { - if let Ok(frame) = frame.unpacked() { - new_selection.push(frame); - } - } + { + let min_x = start.x.min(curr.x); + let max_x = start.x.max(curr.x); + let intersects = min_x <= frame_rect.right() && frame_rect.left() <= max_x; + if intersects && let Ok(frame) = frame.unpacked() { + new_selection.push(frame); } } diff --git a/puffin_http/src/client.rs b/puffin_http/src/client.rs index a8f37fc8..8151840d 100644 --- a/puffin_http/src/client.rs +++ b/puffin_http/src/client.rs @@ -39,9 +39,9 @@ impl Client { let client = Self { addr: addr.clone(), - connected: connected.clone(), - alive: alive.clone(), - frame_view: frame_view.clone(), + connected: Arc::clone(&connected), + alive: Arc::clone(&alive), + frame_view: Arc::clone(&frame_view), }; let _: std::thread::JoinHandle<()> = std::thread::Builder::new() diff --git a/puffin_http/src/server.rs b/puffin_http/src/server.rs index 833b120c..791e7e6e 100644 --- a/puffin_http/src/server.rs +++ b/puffin_http/src/server.rs @@ -248,7 +248,7 @@ impl Server { crossbeam_channel::unbounded(); let num_clients = Arc::new(AtomicUsize::default()); - let num_clients_cloned = num_clients.clone(); + let num_clients_cloned = Arc::clone(&num_clients); let join_handle = std::thread::Builder::new() .name("puffin-server".to_owned()) @@ -379,7 +379,7 @@ impl PuffinServerImpl { // Keep scope_collection up-to-date for new_scope in &frame.scope_delta { - self.scope_collection.insert(new_scope.clone()); + self.scope_collection.insert(Arc::clone(new_scope)); } // Nothing to send if no clients => Early return. @@ -408,7 +408,7 @@ impl PuffinServerImpl { self.clients.retain(|client| match &client.packet_tx { None => false, - Some(packet_tx) => match packet_tx.try_send(packet.clone()) { + Some(packet_tx) => match packet_tx.try_send(Arc::clone(&packet)) { Ok(()) => true, Err(crossbeam_channel::TrySendError::Disconnected(_)) => false, Err(crossbeam_channel::TrySendError::Full(_)) => {