Properly use `static` instead of `const` for global types that need a single init (#35955)

Kirill Bulatov created

Release Notes:

- N/A

Change summary

Cargo.toml                                                  |  1 
crates/assistant_tools/src/edit_agent/create_file_parser.rs | 13 +-
crates/docs_preprocessor/src/main.rs                        | 13 +-
crates/gpui/src/platform/mac/platform.rs                    | 34 +++---
crates/onboarding/src/theme_preview.rs                      | 29 +++--
crates/zeta/src/license_detection.rs                        |  6 
6 files changed, 55 insertions(+), 41 deletions(-)

Detailed changes

Cargo.toml 🔗

@@ -839,6 +839,7 @@ style = { level = "allow", priority = -1 }
 module_inception = { level = "deny" }
 question_mark = { level = "deny" }
 redundant_closure = { level = "deny" }
+declare_interior_mutable_const = { level = "deny" }
 # Individual rules that have violations in the codebase:
 type_complexity = "allow"
 # We often return trait objects from `new` functions.

crates/assistant_tools/src/edit_agent/create_file_parser.rs 🔗

@@ -1,10 +1,11 @@
+use std::sync::OnceLock;
+
 use regex::Regex;
 use smallvec::SmallVec;
-use std::cell::LazyCell;
 use util::debug_panic;
 
-const START_MARKER: LazyCell<Regex> = LazyCell::new(|| Regex::new(r"\n?```\S*\n").unwrap());
-const END_MARKER: LazyCell<Regex> = LazyCell::new(|| Regex::new(r"(^|\n)```\s*$").unwrap());
+static START_MARKER: OnceLock<Regex> = OnceLock::new();
+static END_MARKER: OnceLock<Regex> = OnceLock::new();
 
 #[derive(Debug)]
 pub enum CreateFileParserEvent {
@@ -43,10 +44,12 @@ impl CreateFileParser {
         self.buffer.push_str(chunk);
 
         let mut edit_events = SmallVec::new();
+        let start_marker_regex = START_MARKER.get_or_init(|| Regex::new(r"\n?```\S*\n").unwrap());
+        let end_marker_regex = END_MARKER.get_or_init(|| Regex::new(r"(^|\n)```\s*$").unwrap());
         loop {
             match &mut self.state {
                 ParserState::Pending => {
-                    if let Some(m) = START_MARKER.find(&self.buffer) {
+                    if let Some(m) = start_marker_regex.find(&self.buffer) {
                         self.buffer.drain(..m.end());
                         self.state = ParserState::WithinText;
                     } else {
@@ -65,7 +68,7 @@ impl CreateFileParser {
                     break;
                 }
                 ParserState::Finishing => {
-                    if let Some(m) = END_MARKER.find(&self.buffer) {
+                    if let Some(m) = end_marker_regex.find(&self.buffer) {
                         self.buffer.drain(m.start()..);
                     }
                     if !self.buffer.is_empty() {

crates/docs_preprocessor/src/main.rs 🔗

@@ -8,7 +8,7 @@ use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
 use std::io::{self, Read};
 use std::process;
-use std::sync::LazyLock;
+use std::sync::{LazyLock, OnceLock};
 use util::paths::PathExt;
 
 static KEYMAP_MACOS: LazyLock<KeymapFile> = LazyLock::new(|| {
@@ -388,7 +388,7 @@ fn handle_postprocessing() -> Result<()> {
         let meta_title = format!("{} | {}", page_title, meta_title);
         zlog::trace!(logger => "Updating {:?}", pretty_path(&file, &root_dir));
         let contents = contents.replace("#description#", meta_description);
-        let contents = TITLE_REGEX
+        let contents = title_regex()
             .replace(&contents, |_: &regex::Captures| {
                 format!("<title>{}</title>", meta_title)
             })
@@ -404,10 +404,8 @@ fn handle_postprocessing() -> Result<()> {
     ) -> &'a std::path::Path {
         &path.strip_prefix(&root).unwrap_or(&path)
     }
-    const TITLE_REGEX: std::cell::LazyCell<Regex> =
-        std::cell::LazyCell::new(|| Regex::new(r"<title>\s*(.*?)\s*</title>").unwrap());
     fn extract_title_from_page(contents: &str, pretty_path: &std::path::Path) -> String {
-        let title_tag_contents = &TITLE_REGEX
+        let title_tag_contents = &title_regex()
             .captures(&contents)
             .with_context(|| format!("Failed to find title in {:?}", pretty_path))
             .expect("Page has <title> element")[1];
@@ -420,3 +418,8 @@ fn handle_postprocessing() -> Result<()> {
         title
     }
 }
+
+fn title_regex() -> &'static Regex {
+    static TITLE_REGEX: OnceLock<Regex> = OnceLock::new();
+    TITLE_REGEX.get_or_init(|| Regex::new(r"<title>\s*(.*?)\s*</title>").unwrap())
+}

crates/gpui/src/platform/mac/platform.rs 🔗

@@ -47,7 +47,7 @@ use objc::{
 use parking_lot::Mutex;
 use ptr::null_mut;
 use std::{
-    cell::{Cell, LazyCell},
+    cell::Cell,
     convert::TryInto,
     ffi::{CStr, OsStr, c_void},
     os::{raw::c_char, unix::ffi::OsStrExt},
@@ -56,7 +56,7 @@ use std::{
     ptr,
     rc::Rc,
     slice, str,
-    sync::Arc,
+    sync::{Arc, OnceLock},
 };
 use strum::IntoEnumIterator;
 use util::ResultExt;
@@ -296,18 +296,7 @@ impl MacPlatform {
         actions: &mut Vec<Box<dyn Action>>,
         keymap: &Keymap,
     ) -> id {
-        const DEFAULT_CONTEXT: LazyCell<Vec<KeyContext>> = LazyCell::new(|| {
-            let mut workspace_context = KeyContext::new_with_defaults();
-            workspace_context.add("Workspace");
-            let mut pane_context = KeyContext::new_with_defaults();
-            pane_context.add("Pane");
-            let mut editor_context = KeyContext::new_with_defaults();
-            editor_context.add("Editor");
-
-            pane_context.extend(&editor_context);
-            workspace_context.extend(&pane_context);
-            vec![workspace_context]
-        });
+        static DEFAULT_CONTEXT: OnceLock<Vec<KeyContext>> = OnceLock::new();
 
         unsafe {
             match item {
@@ -323,9 +312,20 @@ impl MacPlatform {
                     let keystrokes = keymap
                         .bindings_for_action(action.as_ref())
                         .find_or_first(|binding| {
-                            binding
-                                .predicate()
-                                .is_none_or(|predicate| predicate.eval(&DEFAULT_CONTEXT))
+                            binding.predicate().is_none_or(|predicate| {
+                                predicate.eval(DEFAULT_CONTEXT.get_or_init(|| {
+                                    let mut workspace_context = KeyContext::new_with_defaults();
+                                    workspace_context.add("Workspace");
+                                    let mut pane_context = KeyContext::new_with_defaults();
+                                    pane_context.add("Pane");
+                                    let mut editor_context = KeyContext::new_with_defaults();
+                                    editor_context.add("Editor");
+
+                                    pane_context.extend(&editor_context);
+                                    workspace_context.extend(&pane_context);
+                                    vec![workspace_context]
+                                }))
+                            })
                         })
                         .map(|binding| binding.keystrokes());
 

crates/onboarding/src/theme_preview.rs 🔗

@@ -1,6 +1,9 @@
 #![allow(unused, dead_code)]
 use gpui::{Hsla, Length};
-use std::sync::Arc;
+use std::{
+    cell::LazyCell,
+    sync::{Arc, OnceLock},
+};
 use theme::{Theme, ThemeColors, ThemeRegistry};
 use ui::{
     IntoElement, RenderOnce, component_prelude::Documented, prelude::*, utils::inner_corner_radius,
@@ -22,6 +25,18 @@ pub struct ThemePreviewTile {
     style: ThemePreviewStyle,
 }
 
+fn child_radius() -> Pixels {
+    static CHILD_RADIUS: OnceLock<Pixels> = OnceLock::new();
+    *CHILD_RADIUS.get_or_init(|| {
+        inner_corner_radius(
+            ThemePreviewTile::ROOT_RADIUS,
+            ThemePreviewTile::ROOT_BORDER,
+            ThemePreviewTile::ROOT_PADDING,
+            ThemePreviewTile::CHILD_BORDER,
+        )
+    })
+}
+
 impl ThemePreviewTile {
     pub const SKELETON_HEIGHT_DEFAULT: Pixels = px(2.);
     pub const SIDEBAR_SKELETON_ITEM_COUNT: usize = 8;
@@ -30,14 +45,6 @@ impl ThemePreviewTile {
     pub const ROOT_BORDER: Pixels = px(2.0);
     pub const ROOT_PADDING: Pixels = px(2.0);
     pub const CHILD_BORDER: Pixels = px(1.0);
-    pub const CHILD_RADIUS: std::cell::LazyCell<Pixels> = std::cell::LazyCell::new(|| {
-        inner_corner_radius(
-            Self::ROOT_RADIUS,
-            Self::ROOT_BORDER,
-            Self::ROOT_PADDING,
-            Self::CHILD_BORDER,
-        )
-    });
 
     pub fn new(theme: Arc<Theme>, seed: f32) -> Self {
         Self {
@@ -222,7 +229,7 @@ impl ThemePreviewTile {
             .child(
                 div()
                     .size_full()
-                    .rounded(*Self::CHILD_RADIUS)
+                    .rounded(child_radius())
                     .border(Self::CHILD_BORDER)
                     .border_color(theme.colors().border)
                     .child(Self::render_editor(
@@ -250,7 +257,7 @@ impl ThemePreviewTile {
                 h_flex()
                     .size_full()
                     .relative()
-                    .rounded(*Self::CHILD_RADIUS)
+                    .rounded(child_radius())
                     .border(Self::CHILD_BORDER)
                     .border_color(border_color)
                     .overflow_hidden()

crates/zeta/src/license_detection.rs 🔗

@@ -14,7 +14,7 @@ use util::ResultExt as _;
 use worktree::ChildEntriesOptions;
 
 /// Matches the most common license locations, with US and UK English spelling.
-const LICENSE_FILE_NAME_REGEX: LazyLock<regex::bytes::Regex> = LazyLock::new(|| {
+static LICENSE_FILE_NAME_REGEX: LazyLock<regex::bytes::Regex> = LazyLock::new(|| {
     regex::bytes::RegexBuilder::new(
         "^ \
         (?: license | licence) \
@@ -29,7 +29,7 @@ const LICENSE_FILE_NAME_REGEX: LazyLock<regex::bytes::Regex> = LazyLock::new(||
 });
 
 fn is_license_eligible_for_data_collection(license: &str) -> bool {
-    const LICENSE_REGEXES: LazyLock<Vec<Regex>> = LazyLock::new(|| {
+    static LICENSE_REGEXES: LazyLock<Vec<Regex>> = LazyLock::new(|| {
         [
             include_str!("license_detection/apache.regex"),
             include_str!("license_detection/isc.regex"),
@@ -47,7 +47,7 @@ fn is_license_eligible_for_data_collection(license: &str) -> bool {
 
 /// Canonicalizes the whitespace of license text and license regexes.
 fn canonicalize_license_text(license: &str) -> String {
-    const PARAGRAPH_SEPARATOR_REGEX: LazyLock<Regex> =
+    static PARAGRAPH_SEPARATOR_REGEX: LazyLock<Regex> =
         LazyLock::new(|| Regex::new(r"\s*\n\s*\n\s*").unwrap());
 
     PARAGRAPH_SEPARATOR_REGEX