Detailed changes
@@ -12,6 +12,19 @@
- Example: avoid `let _ = client.request(...).await?;` - use `client.request(...).await?;` instead
* When implementing async operations that may fail, ensure errors propagate to the UI layer so users get meaningful feedback.
* Never create files with `mod.rs` paths - prefer `src/some_module.rs` instead of `src/some_module/mod.rs`.
+* When creating new crates, prefer specifying the library root path in `Cargo.toml` using `[lib] path = "...rs"` instead of the default `lib.rs`, to maintain consistent and descriptive naming (e.g., `gpui.rs` or `main.rs`).
+* Avoid creative additions unless explicitly requested
+* Use full words for variable names (no abbreviations like "q" for "queue")
+* Use variable shadowing to scope clones in async contexts for clarity, minimizing the lifetime of borrowed references.
+ Example:
+ ```rust
+ executor.spawn({
+ let task_ran = task_ran.clone();
+ async move {
+ *task_ran.borrow_mut() = true;
+ }
+ });
+ ```
# GPUI
@@ -26,7 +26,7 @@ dependencies = [
"portable-pty",
"project",
"prompt_store",
- "rand 0.8.5",
+ "rand 0.9.1",
"serde",
"serde_json",
"settings",
@@ -79,7 +79,7 @@ dependencies = [
"log",
"pretty_assertions",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"serde_json",
"settings",
"text",
@@ -172,7 +172,7 @@ dependencies = [
"pretty_assertions",
"project",
"prompt_store",
- "rand 0.8.5",
+ "rand 0.9.1",
"ref-cast",
"rope",
"schemars",
@@ -408,7 +408,7 @@ dependencies = [
"project",
"prompt_store",
"proto",
- "rand 0.8.5",
+ "rand 0.9.1",
"release_channel",
"rope",
"rules_library",
@@ -834,7 +834,7 @@ dependencies = [
"project",
"prompt_store",
"proto",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"rpc",
"serde",
@@ -933,7 +933,7 @@ dependencies = [
"parking_lot",
"pretty_assertions",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"serde",
"serde_json",
@@ -985,7 +985,7 @@ dependencies = [
"pretty_assertions",
"project",
"prompt_store",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"reqwest_client",
"rust-embed",
@@ -2478,7 +2478,7 @@ dependencies = [
"language",
"log",
"pretty_assertions",
- "rand 0.8.5",
+ "rand 0.9.1",
"rope",
"serde_json",
"sum_tree",
@@ -2899,7 +2899,7 @@ dependencies = [
"language",
"log",
"postage",
- "rand 0.8.5",
+ "rand 0.9.1",
"release_channel",
"rpc",
"settings",
@@ -3086,7 +3086,7 @@ dependencies = [
"parking_lot",
"paths",
"postage",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"release_channel",
"rpc",
@@ -3335,7 +3335,7 @@ dependencies = [
"prometheus",
"prompt_store",
"prost 0.9.0",
- "rand 0.8.5",
+ "rand 0.9.1",
"recent_projects",
"release_channel",
"remote",
@@ -4697,7 +4697,7 @@ dependencies = [
"markdown",
"pretty_assertions",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"serde",
"serde_json",
"settings",
@@ -5068,7 +5068,7 @@ dependencies = [
"parking_lot",
"pretty_assertions",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"release_channel",
"rpc",
@@ -5563,7 +5563,7 @@ dependencies = [
"parking_lot",
"paths",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"release_channel",
"remote",
"reqwest_client",
@@ -6412,7 +6412,7 @@ dependencies = [
"log",
"parking_lot",
"pretty_assertions",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"rope",
"schemars",
@@ -7465,7 +7465,7 @@ dependencies = [
"pathfinder_geometry",
"postage",
"profiling",
- "rand 0.8.5",
+ "rand 0.9.1",
"raw-window-handle",
"refineable",
"reqwest_client",
@@ -9078,7 +9078,7 @@ dependencies = [
"parking_lot",
"postage",
"pretty_assertions",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"rpc",
"schemars",
@@ -10392,7 +10392,7 @@ dependencies = [
"parking_lot",
"pretty_assertions",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"rope",
"serde",
"settings",
@@ -12618,7 +12618,7 @@ dependencies = [
"postage",
"prettier",
"pretty_assertions",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"release_channel",
"remote",
@@ -13892,7 +13892,7 @@ dependencies = [
"ctor",
"gpui",
"log",
- "rand 0.8.5",
+ "rand 0.9.1",
"rayon",
"smallvec",
"sum_tree",
@@ -13921,7 +13921,7 @@ dependencies = [
"gpui",
"parking_lot",
"proto",
- "rand 0.8.5",
+ "rand 0.9.1",
"rsa",
"serde",
"serde_json",
@@ -14356,6 +14356,19 @@ dependencies = [
"windows-sys 0.59.0",
]
+[[package]]
+name = "scheduler"
+version = "0.1.0"
+dependencies = [
+ "async-task",
+ "chrono",
+ "futures 0.3.31",
+ "parking",
+ "parking_lot",
+ "rand 0.9.1",
+ "workspace-hack",
+]
+
[[package]]
name = "schema_generator"
version = "0.1.0"
@@ -15655,7 +15668,7 @@ name = "streaming_diff"
version = "0.1.0"
dependencies = [
"ordered-float 2.10.1",
- "rand 0.8.5",
+ "rand 0.9.1",
"rope",
"util",
"workspace-hack",
@@ -15769,7 +15782,7 @@ dependencies = [
"arrayvec",
"ctor",
"log",
- "rand 0.8.5",
+ "rand 0.9.1",
"rayon",
"workspace-hack",
"zlog",
@@ -16360,7 +16373,7 @@ dependencies = [
"futures 0.3.31",
"gpui",
"libc",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"release_channel",
"schemars",
@@ -16408,7 +16421,7 @@ dependencies = [
"language",
"log",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"schemars",
"search",
@@ -16440,7 +16453,7 @@ dependencies = [
"log",
"parking_lot",
"postage",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"rope",
"smallvec",
@@ -17797,7 +17810,7 @@ dependencies = [
"libc",
"log",
"nix 0.29.0",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"rust-embed",
"schemars",
@@ -18588,7 +18601,7 @@ dependencies = [
"futures 0.3.31",
"gpui",
"parking_lot",
- "rand 0.8.5",
+ "rand 0.9.1",
"workspace-hack",
"zlog",
]
@@ -20047,7 +20060,7 @@ dependencies = [
"paths",
"postage",
"pretty_assertions",
- "rand 0.8.5",
+ "rand 0.9.1",
"rpc",
"schemars",
"serde",
@@ -20812,7 +20825,7 @@ dependencies = [
"menu",
"postage",
"project",
- "rand 0.8.5",
+ "rand 0.9.1",
"regex",
"release_channel",
"reqwest_client",
@@ -131,6 +131,7 @@ members = [
"crates/refineable",
"crates/refineable/derive_refineable",
"crates/release_channel",
+ "crates/scheduler",
"crates/remote",
"crates/remote_server",
"crates/repl",
@@ -360,6 +361,7 @@ proto = { path = "crates/proto" }
recent_projects = { path = "crates/recent_projects" }
refineable = { path = "crates/refineable" }
release_channel = { path = "crates/release_channel" }
+scheduler = { path = "crates/scheduler" }
remote = { path = "crates/remote" }
remote_server = { path = "crates/remote_server" }
repl = { path = "crates/repl" }
@@ -444,6 +446,7 @@ async-fs = "2.1"
async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553" }
async-recursion = "1.0.0"
async-tar = "0.5.0"
+async-task = "4.7"
async-trait = "0.1"
async-tungstenite = "0.29.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
@@ -538,6 +541,7 @@ objc = "0.2"
open = "5.0.0"
ordered-float = "2.1.1"
palette = { version = "0.7.5", default-features = false, features = ["std"] }
+parking = "2.0"
parking_lot = "0.12.1"
partial-json-fixer = "0.5.3"
parse_int = "0.9"
@@ -560,7 +564,7 @@ prost-build = "0.9"
prost-types = "0.9"
pulldown-cmark = { version = "0.12.0", default-features = false }
quote = "1.0.9"
-rand = "0.8.5"
+rand = "0.9"
rayon = "1.8"
ref-cast = "1.0.24"
regex = "1.5"
@@ -2114,7 +2114,7 @@ mod tests {
use gpui::{App, AsyncApp, TestAppContext, WeakEntity};
use indoc::indoc;
use project::{FakeFs, Fs};
- use rand::Rng as _;
+ use rand::{distr, prelude::*};
use serde_json::json;
use settings::SettingsStore;
use smol::stream::StreamExt as _;
@@ -3057,8 +3057,8 @@ mod tests {
cx: &mut App,
) -> Task<gpui::Result<Entity<AcpThread>>> {
let session_id = acp::SessionId(
- rand::thread_rng()
- .sample_iter(&rand::distributions::Alphanumeric)
+ rand::rng()
+ .sample_iter(&distr::Alphanumeric)
.take(7)
.map(char::from)
.collect::<String>()
@@ -2218,7 +2218,7 @@ mod tests {
action_log.update(cx, |log, cx| log.buffer_read(buffer.clone(), cx));
for _ in 0..operations {
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
0..25 => {
action_log.update(cx, |log, cx| {
let range = buffer.read(cx).random_byte_range(0, &mut rng);
@@ -2237,7 +2237,7 @@ mod tests {
.unwrap();
}
_ => {
- let is_agent_edit = rng.gen_bool(0.5);
+ let is_agent_edit = rng.random_bool(0.5);
if is_agent_edit {
log::info!("agent edit");
} else {
@@ -2252,7 +2252,7 @@ mod tests {
}
}
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
quiesce(&action_log, &buffer, cx);
}
}
@@ -1139,7 +1139,7 @@ mod tests {
);
while !new_text.is_empty() {
let max_len = cmp::min(new_text.len(), 10);
- let len = rng.gen_range(1..=max_len);
+ let len = rng.random_range(1..=max_len);
let (chunk, suffix) = new_text.split_at(len);
chunks_tx.unbounded_send(chunk.to_string()).unwrap();
new_text = suffix;
@@ -1208,7 +1208,7 @@ mod tests {
);
while !new_text.is_empty() {
let max_len = cmp::min(new_text.len(), 10);
- let len = rng.gen_range(1..=max_len);
+ let len = rng.random_range(1..=max_len);
let (chunk, suffix) = new_text.split_at(len);
chunks_tx.unbounded_send(chunk.to_string()).unwrap();
new_text = suffix;
@@ -1277,7 +1277,7 @@ mod tests {
);
while !new_text.is_empty() {
let max_len = cmp::min(new_text.len(), 10);
- let len = rng.gen_range(1..=max_len);
+ let len = rng.random_range(1..=max_len);
let (chunk, suffix) = new_text.split_at(len);
chunks_tx.unbounded_send(chunk.to_string()).unwrap();
new_text = suffix;
@@ -764,7 +764,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
let network = Arc::new(Mutex::new(Network::new(rng.clone())));
let mut contexts = Vec::new();
- let num_peers = rng.gen_range(min_peers..=max_peers);
+ let num_peers = rng.random_range(min_peers..=max_peers);
let context_id = ContextId::new();
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
for i in 0..num_peers {
@@ -806,10 +806,10 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
|| !network.lock().is_idle()
|| network.lock().contains_disconnected_peers()
{
- let context_index = rng.gen_range(0..contexts.len());
+ let context_index = rng.random_range(0..contexts.len());
let context = &contexts[context_index];
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
0..=29 if mutation_count > 0 => {
log::info!("Context {}: edit buffer", context_index);
context.update(cx, |context, cx| {
@@ -874,10 +874,10 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
merge_same_roles: true,
})];
- let num_sections = rng.gen_range(0..=3);
+ let num_sections = rng.random_range(0..=3);
let mut section_start = 0;
for _ in 0..num_sections {
- let mut section_end = rng.gen_range(section_start..=output_text.len());
+ let mut section_end = rng.random_range(section_start..=output_text.len());
while !output_text.is_char_boundary(section_end) {
section_end += 1;
}
@@ -924,7 +924,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
75..=84 if mutation_count > 0 => {
context.update(cx, |context, cx| {
if let Some(message) = context.messages(cx).choose(&mut rng) {
- let new_status = match rng.gen_range(0..3) {
+ let new_status = match rng.random_range(0..3) {
0 => MessageStatus::Done,
1 => MessageStatus::Pending,
_ => MessageStatus::Error(SharedString::from("Random error")),
@@ -971,7 +971,7 @@ async fn test_random_context_collaboration(cx: &mut TestAppContext, mut rng: Std
network.lock().broadcast(replica_id, ops_to_send);
context.update(cx, |context, cx| context.apply_ops(ops_to_receive, cx));
- } else if rng.gen_bool(0.1) && replica_id != 0 {
+ } else if rng.random_bool(0.1) && replica_id != 0 {
log::info!("Context {}: disconnecting", context_index);
network.lock().disconnect_peer(replica_id);
} else if network.lock().has_unreceived(replica_id) {
@@ -1315,17 +1315,17 @@ mod tests {
#[gpui::test(iterations = 100)]
async fn test_random_indents(mut rng: StdRng) {
- let len = rng.gen_range(1..=100);
+ let len = rng.random_range(1..=100);
let new_text = util::RandomCharIter::new(&mut rng)
.with_simple_text()
.take(len)
.collect::<String>();
let new_text = new_text
.split('\n')
- .map(|line| format!("{}{}", " ".repeat(rng.gen_range(0..=8)), line))
+ .map(|line| format!("{}{}", " ".repeat(rng.random_range(0..=8)), line))
.collect::<Vec<_>>()
.join("\n");
- let delta = IndentDelta::Spaces(rng.gen_range(-4..=4));
+ let delta = IndentDelta::Spaces(rng.random_range(-4i8..=4i8) as isize);
let chunks = to_random_chunks(&mut rng, &new_text);
let new_text_chunks = stream::iter(chunks.iter().enumerate().map(|(index, chunk)| {
@@ -1357,7 +1357,7 @@ mod tests {
}
fn to_random_chunks(rng: &mut StdRng, input: &str) -> Vec<String> {
- let chunk_count = rng.gen_range(1..=cmp::min(input.len(), 50));
+ let chunk_count = rng.random_range(1..=cmp::min(input.len(), 50));
let mut chunk_indices = (0..input.len()).choose_multiple(rng, chunk_count);
chunk_indices.sort();
chunk_indices.push(input.len());
@@ -204,7 +204,7 @@ mod tests {
}
fn parse_random_chunks(input: &str, parser: &mut CreateFileParser, rng: &mut StdRng) -> String {
- let chunk_count = rng.gen_range(1..=cmp::min(input.len(), 50));
+ let chunk_count = rng.random_range(1..=cmp::min(input.len(), 50));
let mut chunk_indices = (0..input.len()).choose_multiple(rng, chunk_count);
chunk_indices.sort();
chunk_indices.push(input.len());
@@ -996,7 +996,7 @@ mod tests {
}
fn parse_random_chunks(input: &str, parser: &mut EditParser, rng: &mut StdRng) -> Vec<Edit> {
- let chunk_count = rng.gen_range(1..=cmp::min(input.len(), 50));
+ let chunk_count = rng.random_range(1..=cmp::min(input.len(), 50));
let mut chunk_indices = (0..input.len()).choose_multiple(rng, chunk_count);
chunk_indices.sort();
chunk_indices.push(input.len());
@@ -1399,7 +1399,7 @@ fn eval(
}
fn run_eval(eval: EvalInput, tx: mpsc::Sender<Result<EvalOutput>>) {
- let dispatcher = gpui::TestDispatcher::new(StdRng::from_entropy());
+ let dispatcher = gpui::TestDispatcher::new(StdRng::from_os_rng());
let mut cx = TestAppContext::build(dispatcher, None);
let output = cx.executor().block_test(async {
let test = EditAgentTest::new(&mut cx).await;
@@ -1707,7 +1707,7 @@ async fn retry_on_rate_limit<R>(mut request: impl AsyncFnMut() -> Result<R>) ->
};
if let Some(retry_after) = retry_delay {
- let jitter = retry_after.mul_f64(rand::thread_rng().gen_range(0.0..1.0));
+ let jitter = retry_after.mul_f64(rand::rng().random_range(0.0..1.0));
eprintln!("Attempt #{attempt}: Retry after {retry_after:?} + jitter of {jitter:?}");
Timer::after(retry_after + jitter).await;
} else {
@@ -771,7 +771,7 @@ mod tests {
}
fn to_random_chunks(rng: &mut StdRng, input: &str) -> Vec<String> {
- let chunk_count = rng.gen_range(1..=cmp::min(input.len(), 50));
+ let chunk_count = rng.random_range(1..=cmp::min(input.len(), 50));
let mut chunk_indices = (0..input.len()).choose_multiple(rng, chunk_count);
chunk_indices.sort();
chunk_indices.push(input.len());
@@ -2044,10 +2044,10 @@ mod tests {
#[gpui::test(iterations = 100)]
async fn test_staging_and_unstaging_hunks(cx: &mut TestAppContext, mut rng: StdRng) {
fn gen_line(rng: &mut StdRng) -> String {
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
"\n".to_owned()
} else {
- let c = rng.gen_range('A'..='Z');
+ let c = rng.random_range('A'..='Z');
format!("{c}{c}{c}\n")
}
}
@@ -2066,7 +2066,7 @@ mod tests {
old_lines.into_iter()
};
let mut result = String::new();
- let unchanged_count = rng.gen_range(0..=old_lines.len());
+ let unchanged_count = rng.random_range(0..=old_lines.len());
result +=
&old_lines
.by_ref()
@@ -2076,14 +2076,14 @@ mod tests {
s
});
while old_lines.len() > 0 {
- let deleted_count = rng.gen_range(0..=old_lines.len());
+ let deleted_count = rng.random_range(0..=old_lines.len());
let _advance = old_lines
.by_ref()
.take(deleted_count)
.map(|line| line.len() + 1)
.sum::<usize>();
let minimum_added = if deleted_count == 0 { 1 } else { 0 };
- let added_count = rng.gen_range(minimum_added..=5);
+ let added_count = rng.random_range(minimum_added..=5);
let addition = (0..added_count).map(|_| gen_line(rng)).collect::<String>();
result += &addition;
@@ -2092,7 +2092,8 @@ mod tests {
if blank_lines == old_lines.len() {
break;
};
- let unchanged_count = rng.gen_range((blank_lines + 1).max(1)..=old_lines.len());
+ let unchanged_count =
+ rng.random_range((blank_lines + 1).max(1)..=old_lines.len());
result += &old_lines.by_ref().take(unchanged_count).fold(
String::new(),
|mut s, line| {
@@ -2149,7 +2150,7 @@ mod tests {
)
});
let working_copy = working_copy.read_with(cx, |working_copy, _| working_copy.snapshot());
- let mut index_text = if rng.r#gen() {
+ let mut index_text = if rng.random() {
Rope::from(head_text.as_str())
} else {
working_copy.as_rope().clone()
@@ -2165,7 +2166,7 @@ mod tests {
}
for _ in 0..operations {
- let i = rng.gen_range(0..hunks.len());
+ let i = rng.random_range(0..hunks.len());
let hunk = &mut hunks[i];
let hunk_to_change = hunk.clone();
let stage = match hunk.secondary_status {
@@ -129,7 +129,7 @@ impl ChannelChat {
loaded_all_messages: false,
next_pending_message_id: 0,
last_acknowledged_id: None,
- rng: StdRng::from_entropy(),
+ rng: StdRng::from_os_rng(),
first_loaded_message_id: None,
_subscription: subscription.set_entity(&cx.entity(), &cx.to_async()),
}
@@ -183,7 +183,7 @@ impl ChannelChat {
let channel_id = self.channel_id;
let pending_id = ChannelMessageId::Pending(post_inc(&mut self.next_pending_message_id));
- let nonce = self.rng.r#gen();
+ let nonce = self.rng.random();
self.insert_messages(
SumTree::from_item(
ChannelMessage {
@@ -257,7 +257,7 @@ impl ChannelChat {
cx,
);
- let nonce: u128 = self.rng.r#gen();
+ let nonce: u128 = self.rng.random();
let request = self.rpc.request(proto::UpdateChannelMessage {
channel_id: self.channel_id.0,
@@ -691,7 +691,7 @@ impl Client {
#[cfg(any(test, feature = "test-support"))]
let mut rng = StdRng::seed_from_u64(0);
#[cfg(not(any(test, feature = "test-support")))]
- let mut rng = StdRng::from_entropy();
+ let mut rng = StdRng::from_os_rng();
let mut delay = INITIAL_RECONNECTION_DELAY;
loop {
@@ -721,8 +721,9 @@ impl Client {
},
cx,
);
- let jitter =
- Duration::from_millis(rng.gen_range(0..delay.as_millis() as u64));
+ let jitter = Duration::from_millis(
+ rng.random_range(0..delay.as_millis() as u64),
+ );
cx.background_executor().timer(delay + jitter).await;
delay = cmp::min(delay * 2, MAX_RECONNECTION_DELAY);
} else {
@@ -227,7 +227,7 @@ pub async fn verify_access_token(
#[cfg(test)]
mod test {
- use rand::thread_rng;
+ use rand::prelude::*;
use scrypt::password_hash::{PasswordHasher, SaltString};
use sea_orm::EntityTrait;
@@ -358,9 +358,42 @@ mod test {
None,
None,
params,
- &SaltString::generate(thread_rng()),
+ &SaltString::generate(PasswordHashRngCompat::new()),
)
.map_err(anyhow::Error::new)?
.to_string())
}
+
+ // TODO: remove once we password_hash v0.6 is released.
+ struct PasswordHashRngCompat(rand::rngs::ThreadRng);
+
+ impl PasswordHashRngCompat {
+ fn new() -> Self {
+ Self(rand::rng())
+ }
+ }
+
+ impl scrypt::password_hash::rand_core::RngCore for PasswordHashRngCompat {
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ fn try_fill_bytes(
+ &mut self,
+ dest: &mut [u8],
+ ) -> Result<(), scrypt::password_hash::rand_core::Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+ }
+
+ impl scrypt::password_hash::rand_core::CryptoRng for PasswordHashRngCompat {}
}
@@ -256,7 +256,7 @@ impl Database {
let test_options = self.test_options.as_ref().unwrap();
test_options.executor.simulate_random_delay().await;
let fail_probability = *test_options.query_failure_probability.lock();
- if test_options.executor.rng().gen_bool(fail_probability) {
+ if test_options.executor.rng().random_bool(fail_probability) {
return Err(anyhow!("simulated query failure"))?;
}
@@ -75,10 +75,10 @@ impl TestDb {
static LOCK: Mutex<()> = Mutex::new(());
let _guard = LOCK.lock();
- let mut rng = StdRng::from_entropy();
+ let mut rng = StdRng::from_os_rng();
let url = format!(
"postgres://postgres@localhost/zed-test-{}",
- rng.r#gen::<u128>()
+ rng.random::<u128>()
);
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
@@ -5746,7 +5746,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
let definitions;
let buffer_b2;
- if rng.r#gen() {
+ if rng.random() {
cx_a.run_until_parked();
cx_b.run_until_parked();
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
@@ -84,7 +84,7 @@ impl RandomizedTest for RandomChannelBufferTest {
}
loop {
- match rng.gen_range(0..100_u32) {
+ match rng.random_range(0..100_u32) {
0..=29 => {
let channel_name = client.channel_store().read_with(cx, |store, cx| {
store.ordered_channels().find_map(|(_, channel)| {
@@ -17,7 +17,7 @@ use project::{
DEFAULT_COMPLETION_CONTEXT, Project, ProjectPath, search::SearchQuery, search::SearchResult,
};
use rand::{
- distributions::{Alphanumeric, DistString},
+ distr::{self, SampleString},
prelude::*,
};
use serde::{Deserialize, Serialize};
@@ -168,19 +168,19 @@ impl RandomizedTest for ProjectCollaborationTest {
) -> ClientOperation {
let call = cx.read(ActiveCall::global);
loop {
- match rng.gen_range(0..100_u32) {
+ match rng.random_range(0..100_u32) {
// Mutate the call
0..=29 => {
// Respond to an incoming call
if call.read_with(cx, |call, _| call.incoming().borrow().is_some()) {
- break if rng.gen_bool(0.7) {
+ break if rng.random_bool(0.7) {
ClientOperation::AcceptIncomingCall
} else {
ClientOperation::RejectIncomingCall
};
}
- match rng.gen_range(0..100_u32) {
+ match rng.random_range(0..100_u32) {
// Invite a contact to the current call
0..=70 => {
let available_contacts =
@@ -212,7 +212,7 @@ impl RandomizedTest for ProjectCollaborationTest {
}
// Mutate projects
- 30..=59 => match rng.gen_range(0..100_u32) {
+ 30..=59 => match rng.random_range(0..100_u32) {
// Open a new project
0..=70 => {
// Open a remote project
@@ -270,7 +270,7 @@ impl RandomizedTest for ProjectCollaborationTest {
}
// Mutate project worktrees
- 81.. => match rng.gen_range(0..100_u32) {
+ 81.. => match rng.random_range(0..100_u32) {
// Add a worktree to a local project
0..=50 => {
let Some(project) = client.local_projects().choose(rng).cloned() else {
@@ -279,7 +279,7 @@ impl RandomizedTest for ProjectCollaborationTest {
let project_root_name = root_name_for_project(&project, cx);
let mut paths = client.fs().paths(false);
paths.remove(0);
- let new_root_path = if paths.is_empty() || rng.r#gen() {
+ let new_root_path = if paths.is_empty() || rng.random() {
Path::new(path!("/")).join(plan.next_root_dir_name())
} else {
paths.choose(rng).unwrap().clone()
@@ -309,7 +309,7 @@ impl RandomizedTest for ProjectCollaborationTest {
.choose(rng)
});
let Some(worktree) = worktree else { continue };
- let is_dir = rng.r#gen::<bool>();
+ let is_dir = rng.random::<bool>();
let mut full_path =
worktree.read_with(cx, |w, _| PathBuf::from(w.root_name()));
full_path.push(gen_file_name(rng));
@@ -334,7 +334,7 @@ impl RandomizedTest for ProjectCollaborationTest {
let project_root_name = root_name_for_project(&project, cx);
let is_local = project.read_with(cx, |project, _| project.is_local());
- match rng.gen_range(0..100_u32) {
+ match rng.random_range(0..100_u32) {
// Manipulate an existing buffer
0..=70 => {
let Some(buffer) = client
@@ -349,7 +349,7 @@ impl RandomizedTest for ProjectCollaborationTest {
let full_path = buffer
.read_with(cx, |buffer, cx| buffer.file().unwrap().full_path(cx));
- match rng.gen_range(0..100_u32) {
+ match rng.random_range(0..100_u32) {
// Close the buffer
0..=15 => {
break ClientOperation::CloseBuffer {
@@ -360,7 +360,7 @@ impl RandomizedTest for ProjectCollaborationTest {
}
// Save the buffer
16..=29 if buffer.read_with(cx, |b, _| b.is_dirty()) => {
- let detach = rng.gen_bool(0.3);
+ let detach = rng.random_bool(0.3);
break ClientOperation::SaveBuffer {
project_root_name,
is_local,
@@ -383,17 +383,17 @@ impl RandomizedTest for ProjectCollaborationTest {
_ => {
let offset = buffer.read_with(cx, |buffer, _| {
buffer.clip_offset(
- rng.gen_range(0..=buffer.len()),
+ rng.random_range(0..=buffer.len()),
language::Bias::Left,
)
});
- let detach = rng.r#gen();
+ let detach = rng.random();
break ClientOperation::RequestLspDataInBuffer {
project_root_name,
full_path,
offset,
is_local,
- kind: match rng.gen_range(0..5_u32) {
+ kind: match rng.random_range(0..5_u32) {
0 => LspRequestKind::Rename,
1 => LspRequestKind::Highlights,
2 => LspRequestKind::Definition,
@@ -407,8 +407,8 @@ impl RandomizedTest for ProjectCollaborationTest {
}
71..=80 => {
- let query = rng.gen_range('a'..='z').to_string();
- let detach = rng.gen_bool(0.3);
+ let query = rng.random_range('a'..='z').to_string();
+ let detach = rng.random_bool(0.3);
break ClientOperation::SearchProject {
project_root_name,
is_local,
@@ -460,7 +460,7 @@ impl RandomizedTest for ProjectCollaborationTest {
// Create or update a file or directory
96.. => {
- let is_dir = rng.r#gen::<bool>();
+ let is_dir = rng.random::<bool>();
let content;
let mut path;
let dir_paths = client.fs().directories(false);
@@ -470,11 +470,11 @@ impl RandomizedTest for ProjectCollaborationTest {
path = dir_paths.choose(rng).unwrap().clone();
path.push(gen_file_name(rng));
} else {
- content = Alphanumeric.sample_string(rng, 16);
+ content = distr::Alphanumeric.sample_string(rng, 16);
// Create a new file or overwrite an existing file
let file_paths = client.fs().files();
- if file_paths.is_empty() || rng.gen_bool(0.5) {
+ if file_paths.is_empty() || rng.random_bool(0.5) {
path = dir_paths.choose(rng).unwrap().clone();
path.push(gen_file_name(rng));
path.set_extension("rs");
@@ -1090,7 +1090,7 @@ impl RandomizedTest for ProjectCollaborationTest {
move |_, cx| {
let background = cx.background_executor();
let mut rng = background.rng();
- let count = rng.gen_range::<usize, _>(1..3);
+ let count = rng.random_range::<usize, _>(1..3);
let files = fs.as_fake().files();
let files = (0..count)
.map(|_| files.choose(&mut rng).unwrap().clone())
@@ -1117,12 +1117,12 @@ impl RandomizedTest for ProjectCollaborationTest {
let background = cx.background_executor();
let mut rng = background.rng();
- let highlight_count = rng.gen_range(1..=5);
+ let highlight_count = rng.random_range(1..=5);
for _ in 0..highlight_count {
- let start_row = rng.gen_range(0..100);
- let start_column = rng.gen_range(0..100);
- let end_row = rng.gen_range(0..100);
- let end_column = rng.gen_range(0..100);
+ let start_row = rng.random_range(0..100);
+ let start_column = rng.random_range(0..100);
+ let end_row = rng.random_range(0..100);
+ let end_column = rng.random_range(0..100);
let start = PointUtf16::new(start_row, start_column);
let end = PointUtf16::new(end_row, end_column);
let range =
@@ -1219,8 +1219,8 @@ impl RandomizedTest for ProjectCollaborationTest {
guest_project.remote_id(),
);
assert_eq!(
- guest_snapshot.entries(false, 0).collect::<Vec<_>>(),
- host_snapshot.entries(false, 0).collect::<Vec<_>>(),
+ guest_snapshot.entries(false, 0).map(null_out_entry_size).collect::<Vec<_>>(),
+ host_snapshot.entries(false, 0).map(null_out_entry_size).collect::<Vec<_>>(),
"{} has different snapshot than the host for worktree {:?} ({:?}) and project {:?}",
client.username,
host_snapshot.abs_path(),
@@ -1248,6 +1248,18 @@ impl RandomizedTest for ProjectCollaborationTest {
);
}
});
+
+ // A hack to work around a hack in
+ // https://github.com/zed-industries/zed/pull/16696 that wasn't
+ // detected until we upgraded the rng crate. This whole crate is
+ // going away with DeltaDB soon, so we hold our nose and
+ // continue.
+ fn null_out_entry_size(entry: &project::Entry) -> project::Entry {
+ project::Entry {
+ size: 0,
+ ..entry.clone()
+ }
+ }
}
let buffers = client.buffers().clone();
@@ -1422,7 +1434,7 @@ fn generate_git_operation(rng: &mut StdRng, client: &TestClient) -> GitOperation
.filter(|path| path.starts_with(repo_path))
.collect::<Vec<_>>();
- let count = rng.gen_range(0..=paths.len());
+ let count = rng.random_range(0..=paths.len());
paths.shuffle(rng);
paths.truncate(count);
@@ -1434,13 +1446,13 @@ fn generate_git_operation(rng: &mut StdRng, client: &TestClient) -> GitOperation
let repo_path = client.fs().directories(false).choose(rng).unwrap().clone();
- match rng.gen_range(0..100_u32) {
+ match rng.random_range(0..100_u32) {
0..=25 => {
let file_paths = generate_file_paths(&repo_path, rng, client);
let contents = file_paths
.into_iter()
- .map(|path| (path, Alphanumeric.sample_string(rng, 16)))
+ .map(|path| (path, distr::Alphanumeric.sample_string(rng, 16)))
.collect();
GitOperation::WriteGitIndex {
@@ -1449,7 +1461,8 @@ fn generate_git_operation(rng: &mut StdRng, client: &TestClient) -> GitOperation
}
}
26..=63 => {
- let new_branch = (rng.gen_range(0..10) > 3).then(|| Alphanumeric.sample_string(rng, 8));
+ let new_branch =
+ (rng.random_range(0..10) > 3).then(|| distr::Alphanumeric.sample_string(rng, 8));
GitOperation::WriteGitBranch {
repo_path,
@@ -1596,7 +1609,7 @@ fn choose_random_project(client: &TestClient, rng: &mut StdRng) -> Option<Entity
fn gen_file_name(rng: &mut StdRng) -> String {
let mut name = String::new();
for _ in 0..10 {
- let letter = rng.gen_range('a'..='z');
+ let letter = rng.random_range('a'..='z');
name.push(letter);
}
name
@@ -1604,7 +1617,7 @@ fn gen_file_name(rng: &mut StdRng) -> String {
fn gen_status(rng: &mut StdRng) -> FileStatus {
fn gen_tracked_status(rng: &mut StdRng) -> TrackedStatus {
- match rng.gen_range(0..3) {
+ match rng.random_range(0..3) {
0 => TrackedStatus {
index_status: StatusCode::Unmodified,
worktree_status: StatusCode::Unmodified,
@@ -1626,7 +1639,7 @@ fn gen_status(rng: &mut StdRng) -> FileStatus {
}
fn gen_unmerged_status_code(rng: &mut StdRng) -> UnmergedStatusCode {
- match rng.gen_range(0..3) {
+ match rng.random_range(0..3) {
0 => UnmergedStatusCode::Updated,
1 => UnmergedStatusCode::Added,
2 => UnmergedStatusCode::Deleted,
@@ -1634,7 +1647,7 @@ fn gen_status(rng: &mut StdRng) -> FileStatus {
}
}
- match rng.gen_range(0..2) {
+ match rng.random_range(0..2) {
0 => FileStatus::Unmerged(UnmergedStatus {
first_head: gen_unmerged_status_code(rng),
second_head: gen_unmerged_status_code(rng),
@@ -208,9 +208,9 @@ pub fn save_randomized_test_plan() {
impl<T: RandomizedTest> TestPlan<T> {
pub async fn new(server: &mut TestServer, mut rng: StdRng) -> Arc<Mutex<Self>> {
- let allow_server_restarts = rng.gen_bool(0.7);
- let allow_client_reconnection = rng.gen_bool(0.7);
- let allow_client_disconnection = rng.gen_bool(0.1);
+ let allow_server_restarts = rng.random_bool(0.7);
+ let allow_client_reconnection = rng.random_bool(0.7);
+ let allow_client_disconnection = rng.random_bool(0.1);
let mut users = Vec::new();
for ix in 0..max_peers() {
@@ -407,7 +407,7 @@ impl<T: RandomizedTest> TestPlan<T> {
}
Some(loop {
- break match self.rng.gen_range(0..100) {
+ break match self.rng.random_range(0..100) {
0..=29 if clients.len() < self.users.len() => {
let user = self
.users
@@ -421,13 +421,13 @@ impl<T: RandomizedTest> TestPlan<T> {
}
}
30..=34 if clients.len() > 1 && self.allow_client_disconnection => {
- let (client, cx) = &clients[self.rng.gen_range(0..clients.len())];
+ let (client, cx) = &clients[self.rng.random_range(0..clients.len())];
let user_id = client.current_user_id(cx);
self.operation_ix += 1;
ServerOperation::RemoveConnection { user_id }
}
35..=39 if clients.len() > 1 && self.allow_client_reconnection => {
- let (client, cx) = &clients[self.rng.gen_range(0..clients.len())];
+ let (client, cx) = &clients[self.rng.random_range(0..clients.len())];
let user_id = client.current_user_id(cx);
self.operation_ix += 1;
ServerOperation::BounceConnection { user_id }
@@ -439,12 +439,12 @@ impl<T: RandomizedTest> TestPlan<T> {
_ if !clients.is_empty() => {
let count = self
.rng
- .gen_range(1..10)
+ .random_range(1..10)
.min(self.max_operations - self.operation_ix);
let batch_id = util::post_inc(&mut self.next_batch_id);
let mut user_ids = (0..count)
.map(|_| {
- let ix = self.rng.gen_range(0..clients.len());
+ let ix = self.rng.random_range(0..clients.len());
let (client, cx) = &clients[ix];
client.current_user_id(cx)
})
@@ -453,7 +453,7 @@ impl<T: RandomizedTest> TestPlan<T> {
ServerOperation::MutateClients {
user_ids,
batch_id,
- quiesce: self.rng.gen_bool(0.7),
+ quiesce: self.rng.random_bool(0.7),
}
}
_ => continue,
@@ -682,7 +682,7 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
Default::default();
for _ in 0..operations {
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
// language server completes its diagnostic check
0..=20 if !updated_language_servers.is_empty() => {
let server_id = *updated_language_servers.iter().choose(&mut rng).unwrap();
@@ -691,7 +691,7 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
lsp_store.disk_based_diagnostics_finished(server_id, cx)
});
- if rng.gen_bool(0.5) {
+ if rng.random_bool(0.5) {
cx.run_until_parked();
}
}
@@ -701,7 +701,7 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
let (path, server_id, diagnostics) =
match current_diagnostics.iter_mut().choose(&mut rng) {
// update existing set of diagnostics
- Some(((path, server_id), diagnostics)) if rng.gen_bool(0.5) => {
+ Some(((path, server_id), diagnostics)) if rng.random_bool(0.5) => {
(path.clone(), *server_id, diagnostics)
}
@@ -709,13 +709,13 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
_ => {
let path: PathBuf =
format!(path!("/test/{}.rs"), post_inc(&mut next_filename)).into();
- let len = rng.gen_range(128..256);
+ let len = rng.random_range(128..256);
let content =
RandomCharIter::new(&mut rng).take(len).collect::<String>();
fs.insert_file(&path, content.into_bytes()).await;
let server_id = match language_server_ids.iter().choose(&mut rng) {
- Some(server_id) if rng.gen_bool(0.5) => *server_id,
+ Some(server_id) if rng.random_bool(0.5) => *server_id,
_ => {
let id = LanguageServerId(language_server_ids.len());
language_server_ids.push(id);
@@ -846,7 +846,7 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
let mut next_inlay_id = 0;
for _ in 0..operations {
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
// language server completes its diagnostic check
0..=20 if !updated_language_servers.is_empty() => {
let server_id = *updated_language_servers.iter().choose(&mut rng).unwrap();
@@ -855,7 +855,7 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
lsp_store.disk_based_diagnostics_finished(server_id, cx)
});
- if rng.gen_bool(0.5) {
+ if rng.random_bool(0.5) {
cx.run_until_parked();
}
}
@@ -864,7 +864,7 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
diagnostics.editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(window, cx);
if !snapshot.buffer_snapshot.is_empty() {
- let position = rng.gen_range(0..snapshot.buffer_snapshot.len());
+ let position = rng.random_range(0..snapshot.buffer_snapshot.len());
let position = snapshot.buffer_snapshot.clip_offset(position, Bias::Left);
log::info!(
"adding inlay at {position}/{}: {:?}",
@@ -890,7 +890,7 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
let (path, server_id, diagnostics) =
match current_diagnostics.iter_mut().choose(&mut rng) {
// update existing set of diagnostics
- Some(((path, server_id), diagnostics)) if rng.gen_bool(0.5) => {
+ Some(((path, server_id), diagnostics)) if rng.random_bool(0.5) => {
(path.clone(), *server_id, diagnostics)
}
@@ -898,13 +898,13 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
_ => {
let path: PathBuf =
format!(path!("/test/{}.rs"), post_inc(&mut next_filename)).into();
- let len = rng.gen_range(128..256);
+ let len = rng.random_range(128..256);
let content =
RandomCharIter::new(&mut rng).take(len).collect::<String>();
fs.insert_file(&path, content.into_bytes()).await;
let server_id = match language_server_ids.iter().choose(&mut rng) {
- Some(server_id) if rng.gen_bool(0.5) => *server_id,
+ Some(server_id) if rng.random_bool(0.5) => *server_id,
_ => {
let id = LanguageServerId(language_server_ids.len());
language_server_ids.push(id);
@@ -1589,10 +1589,10 @@ fn randomly_update_diagnostics_for_path(
next_id: &mut usize,
rng: &mut impl Rng,
) {
- let mutation_count = rng.gen_range(1..=3);
+ let mutation_count = rng.random_range(1..=3);
for _ in 0..mutation_count {
- if rng.gen_bool(0.3) && !diagnostics.is_empty() {
- let idx = rng.gen_range(0..diagnostics.len());
+ if rng.random_bool(0.3) && !diagnostics.is_empty() {
+ let idx = rng.random_range(0..diagnostics.len());
log::info!(" removing diagnostic at index {idx}");
diagnostics.remove(idx);
} else {
@@ -1601,7 +1601,7 @@ fn randomly_update_diagnostics_for_path(
let new_diagnostic = random_lsp_diagnostic(rng, fs, path, unique_id);
- let ix = rng.gen_range(0..=diagnostics.len());
+ let ix = rng.random_range(0..=diagnostics.len());
log::info!(
" inserting {} at index {ix}. {},{}..{},{}",
new_diagnostic.message,
@@ -1638,8 +1638,8 @@ fn random_lsp_diagnostic(
let file_content = fs.read_file_sync(path).unwrap();
let file_text = Rope::from(String::from_utf8_lossy(&file_content).as_ref());
- let start = rng.gen_range(0..file_text.len().saturating_add(ERROR_MARGIN));
- let end = rng.gen_range(start..file_text.len().saturating_add(ERROR_MARGIN));
+ let start = rng.random_range(0..file_text.len().saturating_add(ERROR_MARGIN));
+ let end = rng.random_range(start..file_text.len().saturating_add(ERROR_MARGIN));
let start_point = file_text.offset_to_point_utf16(start);
let end_point = file_text.offset_to_point_utf16(end);
@@ -1649,7 +1649,7 @@ fn random_lsp_diagnostic(
lsp::Position::new(end_point.row, end_point.column),
);
- let severity = if rng.gen_bool(0.5) {
+ let severity = if rng.random_bool(0.5) {
Some(lsp::DiagnosticSeverity::ERROR)
} else {
Some(lsp::DiagnosticSeverity::WARNING)
@@ -1657,13 +1657,14 @@ fn random_lsp_diagnostic(
let message = format!("diagnostic {unique_id}");
- let related_information = if rng.gen_bool(0.3) {
- let info_count = rng.gen_range(1..=3);
+ let related_information = if rng.random_bool(0.3) {
+ let info_count = rng.random_range(1..=3);
let mut related_info = Vec::with_capacity(info_count);
for i in 0..info_count {
- let info_start = rng.gen_range(0..file_text.len().saturating_add(ERROR_MARGIN));
- let info_end = rng.gen_range(info_start..file_text.len().saturating_add(ERROR_MARGIN));
+ let info_start = rng.random_range(0..file_text.len().saturating_add(ERROR_MARGIN));
+ let info_end =
+ rng.random_range(info_start..file_text.len().saturating_add(ERROR_MARGIN));
let info_start_point = file_text.offset_to_point_utf16(info_start);
let info_end_point = file_text.offset_to_point_utf16(info_end);
@@ -1552,15 +1552,15 @@ pub mod tests {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let mut tab_size = rng.gen_range(1..=4);
- let buffer_start_excerpt_header_height = rng.gen_range(1..=5);
- let excerpt_header_height = rng.gen_range(1..=5);
+ let mut tab_size = rng.random_range(1..=4);
+ let buffer_start_excerpt_header_height = rng.random_range(1..=5);
+ let excerpt_header_height = rng.random_range(1..=5);
let font_size = px(14.0);
let max_wrap_width = 300.0;
- let mut wrap_width = if rng.gen_bool(0.1) {
+ let mut wrap_width = if rng.random_bool(0.1) {
None
} else {
- Some(px(rng.gen_range(0.0..=max_wrap_width)))
+ Some(px(rng.random_range(0.0..=max_wrap_width)))
};
log::info!("tab size: {}", tab_size);
@@ -1571,8 +1571,8 @@ pub mod tests {
});
let buffer = cx.update(|cx| {
- if rng.r#gen() {
- let len = rng.gen_range(0..10);
+ if rng.random() {
+ let len = rng.random_range(0..10);
let text = util::RandomCharIter::new(&mut rng)
.take(len)
.collect::<String>();
@@ -1609,12 +1609,12 @@ pub mod tests {
log::info!("display text: {:?}", snapshot.text());
for _i in 0..operations {
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
0..=19 => {
- wrap_width = if rng.gen_bool(0.2) {
+ wrap_width = if rng.random_bool(0.2) {
None
} else {
- Some(px(rng.gen_range(0.0..=max_wrap_width)))
+ Some(px(rng.random_range(0.0..=max_wrap_width)))
};
log::info!("setting wrap width to {:?}", wrap_width);
map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
@@ -1634,28 +1634,27 @@ pub mod tests {
}
30..=44 => {
map.update(cx, |map, cx| {
- if rng.r#gen() || blocks.is_empty() {
+ if rng.random() || blocks.is_empty() {
let buffer = map.snapshot(cx).buffer_snapshot;
- let block_properties = (0..rng.gen_range(1..=1))
+ let block_properties = (0..rng.random_range(1..=1))
.map(|_| {
- let position =
- buffer.anchor_after(buffer.clip_offset(
- rng.gen_range(0..=buffer.len()),
- Bias::Left,
- ));
+ let position = buffer.anchor_after(buffer.clip_offset(
+ rng.random_range(0..=buffer.len()),
+ Bias::Left,
+ ));
- let placement = if rng.r#gen() {
+ let placement = if rng.random() {
BlockPlacement::Above(position)
} else {
BlockPlacement::Below(position)
};
- let height = rng.gen_range(1..5);
+ let height = rng.random_range(1..5);
log::info!(
"inserting block {:?} with height {}",
placement.as_ref().map(|p| p.to_point(&buffer)),
height
);
- let priority = rng.gen_range(1..100);
+ let priority = rng.random_range(1..100);
BlockProperties {
placement,
style: BlockStyle::Fixed,
@@ -1668,9 +1667,9 @@ pub mod tests {
blocks.extend(map.insert_blocks(block_properties, cx));
} else {
blocks.shuffle(&mut rng);
- let remove_count = rng.gen_range(1..=4.min(blocks.len()));
+ let remove_count = rng.random_range(1..=4.min(blocks.len()));
let block_ids_to_remove = (0..remove_count)
- .map(|_| blocks.remove(rng.gen_range(0..blocks.len())))
+ .map(|_| blocks.remove(rng.random_range(0..blocks.len())))
.collect();
log::info!("removing block ids {:?}", block_ids_to_remove);
map.remove_blocks(block_ids_to_remove, cx);
@@ -1679,16 +1678,16 @@ pub mod tests {
}
45..=79 => {
let mut ranges = Vec::new();
- for _ in 0..rng.gen_range(1..=3) {
+ for _ in 0..rng.random_range(1..=3) {
buffer.read_with(cx, |buffer, cx| {
let buffer = buffer.read(cx);
- let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
- let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
+ let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
+ let start = buffer.clip_offset(rng.random_range(0..=end), Left);
ranges.push(start..end);
});
}
- if rng.r#gen() && fold_count > 0 {
+ if rng.random() && fold_count > 0 {
log::info!("unfolding ranges: {:?}", ranges);
map.update(cx, |map, cx| {
map.unfold_intersecting(ranges, true, cx);
@@ -1727,8 +1726,8 @@ pub mod tests {
// Line boundaries
let buffer = &snapshot.buffer_snapshot;
for _ in 0..5 {
- let row = rng.gen_range(0..=buffer.max_point().row);
- let column = rng.gen_range(0..=buffer.line_len(MultiBufferRow(row)));
+ let row = rng.random_range(0..=buffer.max_point().row);
+ let column = rng.random_range(0..=buffer.line_len(MultiBufferRow(row)));
let point = buffer.clip_point(Point::new(row, column), Left);
let (prev_buffer_bound, prev_display_bound) = snapshot.prev_line_boundary(point);
@@ -1776,8 +1775,8 @@ pub mod tests {
let min_point = snapshot.clip_point(DisplayPoint::new(DisplayRow(0), 0), Left);
let max_point = snapshot.clip_point(snapshot.max_point(), Right);
for _ in 0..5 {
- let row = rng.gen_range(0..=snapshot.max_point().row().0);
- let column = rng.gen_range(0..=snapshot.line_len(DisplayRow(row)));
+ let row = rng.random_range(0..=snapshot.max_point().row().0);
+ let column = rng.random_range(0..=snapshot.line_len(DisplayRow(row)));
let point = snapshot.clip_point(DisplayPoint::new(DisplayRow(row), column), Left);
log::info!("Moving from point {:?}", point);
@@ -128,10 +128,10 @@ impl<T> BlockPlacement<T> {
}
}
- fn sort_order(&self) -> u8 {
+ fn tie_break(&self) -> u8 {
match self {
- BlockPlacement::Above(_) => 0,
- BlockPlacement::Replace(_) => 1,
+ BlockPlacement::Replace(_) => 0,
+ BlockPlacement::Above(_) => 1,
BlockPlacement::Near(_) => 2,
BlockPlacement::Below(_) => 3,
}
@@ -143,7 +143,7 @@ impl BlockPlacement<Anchor> {
self.start()
.cmp(other.start(), buffer)
.then_with(|| other.end().cmp(self.end(), buffer))
- .then_with(|| self.sort_order().cmp(&other.sort_order()))
+ .then_with(|| self.tie_break().cmp(&other.tie_break()))
}
fn to_wrap_row(&self, wrap_snapshot: &WrapSnapshot) -> Option<BlockPlacement<WrapRow>> {
@@ -847,6 +847,7 @@ impl BlockMap {
.start()
.cmp(placement_b.start())
.then_with(|| placement_b.end().cmp(placement_a.end()))
+ .then_with(|| placement_a.tie_break().cmp(&placement_b.tie_break()))
.then_with(|| {
if block_a.is_header() {
Ordering::Less
@@ -856,7 +857,6 @@ impl BlockMap {
Ordering::Equal
}
})
- .then_with(|| placement_a.sort_order().cmp(&placement_b.sort_order()))
.then_with(|| match (block_a, block_b) {
(
Block::ExcerptBoundary {
@@ -2922,21 +2922,21 @@ mod tests {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let wrap_width = if rng.gen_bool(0.2) {
+ let wrap_width = if rng.random_bool(0.2) {
None
} else {
- Some(px(rng.gen_range(0.0..=100.0)))
+ Some(px(rng.random_range(0.0..=100.0)))
};
let tab_size = 1.try_into().unwrap();
let font_size = px(14.0);
- let buffer_start_header_height = rng.gen_range(1..=5);
- let excerpt_header_height = rng.gen_range(1..=5);
+ let buffer_start_header_height = rng.random_range(1..=5);
+ let excerpt_header_height = rng.random_range(1..=5);
log::info!("Wrap width: {:?}", wrap_width);
log::info!("Excerpt Header Height: {:?}", excerpt_header_height);
- let is_singleton = rng.r#gen();
+ let is_singleton = rng.random();
let buffer = if is_singleton {
- let len = rng.gen_range(0..10);
+ let len = rng.random_range(0..10);
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
log::info!("initial singleton buffer text: {:?}", text);
cx.update(|cx| MultiBuffer::build_simple(&text, cx))
@@ -2966,30 +2966,30 @@ mod tests {
for _ in 0..operations {
let mut buffer_edits = Vec::new();
- match rng.gen_range(0..=100) {
+ match rng.random_range(0..=100) {
0..=19 => {
- let wrap_width = if rng.gen_bool(0.2) {
+ let wrap_width = if rng.random_bool(0.2) {
None
} else {
- Some(px(rng.gen_range(0.0..=100.0)))
+ Some(px(rng.random_range(0.0..=100.0)))
};
log::info!("Setting wrap width to {:?}", wrap_width);
wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
}
20..=39 => {
- let block_count = rng.gen_range(1..=5);
+ let block_count = rng.random_range(1..=5);
let block_properties = (0..block_count)
.map(|_| {
let buffer = cx.update(|cx| buffer.read(cx).read(cx).clone());
let offset =
- buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Left);
+ buffer.clip_offset(rng.random_range(0..=buffer.len()), Bias::Left);
let mut min_height = 0;
- let placement = match rng.gen_range(0..3) {
+ let placement = match rng.random_range(0..3) {
0 => {
min_height = 1;
let start = buffer.anchor_after(offset);
let end = buffer.anchor_after(buffer.clip_offset(
- rng.gen_range(offset..=buffer.len()),
+ rng.random_range(offset..=buffer.len()),
Bias::Left,
));
BlockPlacement::Replace(start..=end)
@@ -2998,7 +2998,7 @@ mod tests {
_ => BlockPlacement::Below(buffer.anchor_after(offset)),
};
- let height = rng.gen_range(min_height..5);
+ let height = rng.random_range(min_height..5);
BlockProperties {
style: BlockStyle::Fixed,
placement,
@@ -3040,7 +3040,7 @@ mod tests {
}
}
40..=59 if !block_map.custom_blocks.is_empty() => {
- let block_count = rng.gen_range(1..=4.min(block_map.custom_blocks.len()));
+ let block_count = rng.random_range(1..=4.min(block_map.custom_blocks.len()));
let block_ids_to_remove = block_map
.custom_blocks
.choose_multiple(&mut rng, block_count)
@@ -3095,8 +3095,8 @@ mod tests {
let mut folded_count = folded_buffers.len();
let mut unfolded_count = unfolded_buffers.len();
- let fold = !unfolded_buffers.is_empty() && rng.gen_bool(0.5);
- let unfold = !folded_buffers.is_empty() && rng.gen_bool(0.5);
+ let fold = !unfolded_buffers.is_empty() && rng.random_bool(0.5);
+ let unfold = !folded_buffers.is_empty() && rng.random_bool(0.5);
if !fold && !unfold {
log::info!(
"Noop fold/unfold operation. Unfolded buffers: {unfolded_count}, folded buffers: {folded_count}"
@@ -3107,7 +3107,7 @@ mod tests {
buffer.update(cx, |buffer, cx| {
if fold {
let buffer_to_fold =
- unfolded_buffers[rng.gen_range(0..unfolded_buffers.len())];
+ unfolded_buffers[rng.random_range(0..unfolded_buffers.len())];
log::info!("Folding {buffer_to_fold:?}");
let related_excerpts = buffer_snapshot
.excerpts()
@@ -3133,7 +3133,7 @@ mod tests {
}
if unfold {
let buffer_to_unfold =
- folded_buffers[rng.gen_range(0..folded_buffers.len())];
+ folded_buffers[rng.random_range(0..folded_buffers.len())];
log::info!("Unfolding {buffer_to_unfold:?}");
unfolded_count += 1;
folded_count -= 1;
@@ -3146,7 +3146,7 @@ mod tests {
}
_ => {
buffer.update(cx, |buffer, cx| {
- let mutation_count = rng.gen_range(1..=5);
+ let mutation_count = rng.random_range(1..=5);
let subscription = buffer.subscribe();
buffer.randomly_mutate(&mut rng, mutation_count, cx);
buffer_snapshot = buffer.snapshot(cx);
@@ -3331,7 +3331,7 @@ mod tests {
);
for start_row in 0..expected_row_count {
- let end_row = rng.gen_range(start_row + 1..=expected_row_count);
+ let end_row = rng.random_range(start_row + 1..=expected_row_count);
let mut expected_text = expected_lines[start_row..end_row].join("\n");
if end_row < expected_row_count {
expected_text.push('\n');
@@ -3426,8 +3426,8 @@ mod tests {
);
for _ in 0..10 {
- let end_row = rng.gen_range(1..=expected_lines.len());
- let start_row = rng.gen_range(0..end_row);
+ let end_row = rng.random_range(1..=expected_lines.len());
+ let start_row = rng.random_range(0..end_row);
let mut expected_longest_rows_in_range = vec![];
let mut longest_line_len_in_range = 0;
@@ -1771,9 +1771,9 @@ mod tests {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let len = rng.gen_range(0..10);
+ let len = rng.random_range(0..10);
let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
- let buffer = if rng.r#gen() {
+ let buffer = if rng.random() {
MultiBuffer::build_simple(&text, cx)
} else {
MultiBuffer::build_random(&mut rng, cx)
@@ -1790,7 +1790,7 @@ mod tests {
log::info!("text: {:?}", buffer_snapshot.text());
let mut buffer_edits = Vec::new();
let mut inlay_edits = Vec::new();
- match rng.gen_range(0..=100) {
+ match rng.random_range(0..=100) {
0..=39 => {
snapshot_edits.extend(map.randomly_mutate(&mut rng));
}
@@ -1800,7 +1800,7 @@ mod tests {
}
_ => buffer.update(cx, |buffer, cx| {
let subscription = buffer.subscribe();
- let edit_count = rng.gen_range(1..=5);
+ let edit_count = rng.random_range(1..=5);
buffer.randomly_mutate(&mut rng, edit_count, cx);
buffer_snapshot = buffer.snapshot(cx);
let edits = subscription.consume().into_inner();
@@ -1917,10 +1917,14 @@ mod tests {
}
for _ in 0..5 {
- let mut start = snapshot
- .clip_offset(FoldOffset(rng.gen_range(0..=snapshot.len().0)), Bias::Left);
- let mut end = snapshot
- .clip_offset(FoldOffset(rng.gen_range(0..=snapshot.len().0)), Bias::Right);
+ let mut start = snapshot.clip_offset(
+ FoldOffset(rng.random_range(0..=snapshot.len().0)),
+ Bias::Left,
+ );
+ let mut end = snapshot.clip_offset(
+ FoldOffset(rng.random_range(0..=snapshot.len().0)),
+ Bias::Right,
+ );
if start > end {
mem::swap(&mut start, &mut end);
}
@@ -1975,8 +1979,8 @@ mod tests {
for _ in 0..5 {
let end =
- buffer_snapshot.clip_offset(rng.gen_range(0..=buffer_snapshot.len()), Right);
- let start = buffer_snapshot.clip_offset(rng.gen_range(0..=end), Left);
+ buffer_snapshot.clip_offset(rng.random_range(0..=buffer_snapshot.len()), Right);
+ let start = buffer_snapshot.clip_offset(rng.random_range(0..=end), Left);
let expected_folds = map
.snapshot
.folds
@@ -2001,10 +2005,10 @@ mod tests {
let text = snapshot.text();
for _ in 0..5 {
- let start_row = rng.gen_range(0..=snapshot.max_point().row());
- let start_column = rng.gen_range(0..=snapshot.line_len(start_row));
- let end_row = rng.gen_range(0..=snapshot.max_point().row());
- let end_column = rng.gen_range(0..=snapshot.line_len(end_row));
+ let start_row = rng.random_range(0..=snapshot.max_point().row());
+ let start_column = rng.random_range(0..=snapshot.line_len(start_row));
+ let end_row = rng.random_range(0..=snapshot.max_point().row());
+ let end_column = rng.random_range(0..=snapshot.line_len(end_row));
let mut start =
snapshot.clip_point(FoldPoint::new(start_row, start_column), Bias::Left);
let mut end = snapshot.clip_point(FoldPoint::new(end_row, end_column), Bias::Right);
@@ -2109,17 +2113,17 @@ mod tests {
rng: &mut impl Rng,
) -> Vec<(FoldSnapshot, Vec<FoldEdit>)> {
let mut snapshot_edits = Vec::new();
- match rng.gen_range(0..=100) {
+ match rng.random_range(0..=100) {
0..=39 if !self.snapshot.folds.is_empty() => {
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
let buffer = &inlay_snapshot.buffer;
let mut to_unfold = Vec::new();
- for _ in 0..rng.gen_range(1..=3) {
- let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
- let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
+ for _ in 0..rng.random_range(1..=3) {
+ let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
+ let start = buffer.clip_offset(rng.random_range(0..=end), Left);
to_unfold.push(start..end);
}
- let inclusive = rng.r#gen();
+ let inclusive = rng.random();
log::info!("unfolding {:?} (inclusive: {})", to_unfold, inclusive);
let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]);
snapshot_edits.push((snapshot, edits));
@@ -2130,9 +2134,9 @@ mod tests {
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
let buffer = &inlay_snapshot.buffer;
let mut to_fold = Vec::new();
- for _ in 0..rng.gen_range(1..=2) {
- let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right);
- let start = buffer.clip_offset(rng.gen_range(0..=end), Left);
+ for _ in 0..rng.random_range(1..=2) {
+ let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
+ let start = buffer.clip_offset(rng.random_range(0..=end), Left);
to_fold.push((start..end, FoldPlaceholder::test()));
}
log::info!("folding {:?}", to_fold);
@@ -719,14 +719,18 @@ impl InlayMap {
let mut to_remove = Vec::new();
let mut to_insert = Vec::new();
let snapshot = &mut self.snapshot;
- for i in 0..rng.gen_range(1..=5) {
- if self.inlays.is_empty() || rng.r#gen() {
+ for i in 0..rng.random_range(1..=5) {
+ if self.inlays.is_empty() || rng.random() {
let position = snapshot.buffer.random_byte_range(0, rng).start;
- let bias = if rng.r#gen() { Bias::Left } else { Bias::Right };
- let len = if rng.gen_bool(0.01) {
+ let bias = if rng.random() {
+ Bias::Left
+ } else {
+ Bias::Right
+ };
+ let len = if rng.random_bool(0.01) {
0
} else {
- rng.gen_range(1..=5)
+ rng.random_range(1..=5)
};
let text = util::RandomCharIter::new(&mut *rng)
.filter(|ch| *ch != '\r')
@@ -1665,8 +1669,8 @@ mod tests {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let len = rng.gen_range(0..30);
- let buffer = if rng.r#gen() {
+ let len = rng.random_range(0..30);
+ let buffer = if rng.random() {
let text = util::RandomCharIter::new(&mut rng)
.take(len)
.collect::<String>();
@@ -1683,7 +1687,7 @@ mod tests {
let mut prev_inlay_text = inlay_snapshot.text();
let mut buffer_edits = Vec::new();
- match rng.gen_range(0..=100) {
+ match rng.random_range(0..=100) {
0..=50 => {
let (snapshot, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
log::info!("mutated text: {:?}", snapshot.text());
@@ -1691,7 +1695,7 @@ mod tests {
}
_ => buffer.update(cx, |buffer, cx| {
let subscription = buffer.subscribe();
- let edit_count = rng.gen_range(1..=5);
+ let edit_count = rng.random_range(1..=5);
buffer.randomly_mutate(&mut rng, edit_count, cx);
buffer_snapshot = buffer.snapshot(cx);
let edits = subscription.consume().into_inner();
@@ -1740,7 +1744,7 @@ mod tests {
}
let mut text_highlights = TextHighlights::default();
- let text_highlight_count = rng.gen_range(0_usize..10);
+ let text_highlight_count = rng.random_range(0_usize..10);
let mut text_highlight_ranges = (0..text_highlight_count)
.map(|_| buffer_snapshot.random_byte_range(0, &mut rng))
.collect::<Vec<_>>();
@@ -1762,10 +1766,10 @@ mod tests {
let mut inlay_highlights = InlayHighlights::default();
if !inlays.is_empty() {
- let inlay_highlight_count = rng.gen_range(0..inlays.len());
+ let inlay_highlight_count = rng.random_range(0..inlays.len());
let mut inlay_indices = BTreeSet::default();
while inlay_indices.len() < inlay_highlight_count {
- inlay_indices.insert(rng.gen_range(0..inlays.len()));
+ inlay_indices.insert(rng.random_range(0..inlays.len()));
}
let new_highlights = TreeMap::from_ordered_entries(
inlay_indices
@@ -1782,8 +1786,8 @@ mod tests {
}),
n => {
let inlay_text = inlay.text.to_string();
- let mut highlight_end = rng.gen_range(1..n);
- let mut highlight_start = rng.gen_range(0..highlight_end);
+ let mut highlight_end = rng.random_range(1..n);
+ let mut highlight_start = rng.random_range(0..highlight_end);
while !inlay_text.is_char_boundary(highlight_end) {
highlight_end += 1;
}
@@ -1805,9 +1809,9 @@ mod tests {
}
for _ in 0..5 {
- let mut end = rng.gen_range(0..=inlay_snapshot.len().0);
+ let mut end = rng.random_range(0..=inlay_snapshot.len().0);
end = expected_text.clip_offset(end, Bias::Right);
- let mut start = rng.gen_range(0..=end);
+ let mut start = rng.random_range(0..=end);
start = expected_text.clip_offset(start, Bias::Right);
let range = InlayOffset(start)..InlayOffset(end);
@@ -736,9 +736,9 @@ mod tests {
#[gpui::test(iterations = 100)]
fn test_random_tabs(cx: &mut gpui::App, mut rng: StdRng) {
- let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
- let len = rng.gen_range(0..30);
- let buffer = if rng.r#gen() {
+ let tab_size = NonZeroU32::new(rng.random_range(1..=4)).unwrap();
+ let len = rng.random_range(0..30);
+ let buffer = if rng.random() {
let text = util::RandomCharIter::new(&mut rng)
.take(len)
.collect::<String>();
@@ -769,11 +769,11 @@ mod tests {
);
for _ in 0..5 {
- let end_row = rng.gen_range(0..=text.max_point().row);
- let end_column = rng.gen_range(0..=text.line_len(end_row));
+ let end_row = rng.random_range(0..=text.max_point().row);
+ let end_column = rng.random_range(0..=text.line_len(end_row));
let mut end = TabPoint(text.clip_point(Point::new(end_row, end_column), Bias::Right));
- let start_row = rng.gen_range(0..=text.max_point().row);
- let start_column = rng.gen_range(0..=text.line_len(start_row));
+ let start_row = rng.random_range(0..=text.max_point().row);
+ let start_column = rng.random_range(0..=text.line_len(start_row));
let mut start =
TabPoint(text.clip_point(Point::new(start_row, start_column), Bias::Left));
if start > end {
@@ -1215,12 +1215,12 @@ mod tests {
.unwrap_or(10);
let text_system = cx.read(|cx| cx.text_system().clone());
- let mut wrap_width = if rng.gen_bool(0.1) {
+ let mut wrap_width = if rng.random_bool(0.1) {
None
} else {
- Some(px(rng.gen_range(0.0..=1000.0)))
+ Some(px(rng.random_range(0.0..=1000.0)))
};
- let tab_size = NonZeroU32::new(rng.gen_range(1..=4)).unwrap();
+ let tab_size = NonZeroU32::new(rng.random_range(1..=4)).unwrap();
let font = test_font();
let _font_id = text_system.resolve_font(&font);
@@ -1230,10 +1230,10 @@ mod tests {
log::info!("Wrap width: {:?}", wrap_width);
let buffer = cx.update(|cx| {
- if rng.r#gen() {
+ if rng.random() {
MultiBuffer::build_random(&mut rng, cx)
} else {
- let len = rng.gen_range(0..10);
+ let len = rng.random_range(0..10);
let text = util::RandomCharIter::new(&mut rng)
.take(len)
.collect::<String>();
@@ -1281,12 +1281,12 @@ mod tests {
log::info!("{} ==============================================", _i);
let mut buffer_edits = Vec::new();
- match rng.gen_range(0..=100) {
+ match rng.random_range(0..=100) {
0..=19 => {
- wrap_width = if rng.gen_bool(0.2) {
+ wrap_width = if rng.random_bool(0.2) {
None
} else {
- Some(px(rng.gen_range(0.0..=1000.0)))
+ Some(px(rng.random_range(0.0..=1000.0)))
};
log::info!("Setting wrap width to {:?}", wrap_width);
wrap_map.update(cx, |map, cx| map.set_wrap_width(wrap_width, cx));
@@ -1317,7 +1317,7 @@ mod tests {
_ => {
buffer.update(cx, |buffer, cx| {
let subscription = buffer.subscribe();
- let edit_count = rng.gen_range(1..=5);
+ let edit_count = rng.random_range(1..=5);
buffer.randomly_mutate(&mut rng, edit_count, cx);
buffer_snapshot = buffer.snapshot(cx);
buffer_edits.extend(subscription.consume());
@@ -1341,7 +1341,7 @@ mod tests {
snapshot.verify_chunks(&mut rng);
edits.push((snapshot, wrap_edits));
- if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) && rng.gen_bool(0.4) {
+ if wrap_map.read_with(cx, |map, _| map.is_rewrapping()) && rng.random_bool(0.4) {
log::info!("Waiting for wrapping to finish");
while wrap_map.read_with(cx, |map, _| map.is_rewrapping()) {
notifications.next().await.unwrap();
@@ -1479,8 +1479,8 @@ mod tests {
impl WrapSnapshot {
fn verify_chunks(&mut self, rng: &mut impl Rng) {
for _ in 0..5 {
- let mut end_row = rng.gen_range(0..=self.max_point().row());
- let start_row = rng.gen_range(0..=end_row);
+ let mut end_row = rng.random_range(0..=self.max_point().row());
+ let start_row = rng.random_range(0..=end_row);
end_row += 1;
let mut expected_text = self.text_chunks(start_row).collect::<String>();
@@ -164,7 +164,7 @@ use project::{
DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
},
};
-use rand::{seq::SliceRandom, thread_rng};
+use rand::seq::SliceRandom;
use rpc::{ErrorCode, ErrorExt, proto::PeerId};
use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
use selections_collection::{
@@ -10971,7 +10971,7 @@ impl Editor {
}
pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
- self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
+ self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
}
fn manipulate_lines<M>(
@@ -1107,7 +1107,7 @@ mod tests {
init_test(cx);
let fs = FakeFs::new(cx.executor());
- let buffer_initial_text_len = rng.gen_range(5..15);
+ let buffer_initial_text_len = rng.random_range(5..15);
let mut buffer_initial_text = Rope::from(
RandomCharIter::new(&mut rng)
.take(buffer_initial_text_len)
@@ -1159,7 +1159,7 @@ mod tests {
git_blame.update(cx, |blame, cx| blame.check_invariants(cx));
for _ in 0..operations {
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
0..=19 => {
log::info!("quiescing");
cx.executor().run_until_parked();
@@ -1202,8 +1202,8 @@ mod tests {
let mut blame_entries = Vec::new();
for ix in 0..5 {
if last_row < max_row {
- let row_start = rng.gen_range(last_row..max_row);
- let row_end = rng.gen_range(row_start + 1..cmp::min(row_start + 3, max_row) + 1);
+ let row_start = rng.random_range(last_row..max_row);
+ let row_end = rng.random_range(row_start + 1..cmp::min(row_start + 3, max_row) + 1);
blame_entries.push(blame_entry(&ix.to_string(), row_start..row_end));
last_row = row_end;
} else {
@@ -38,58 +38,58 @@ pub struct Quote {
impl Quote {
pub fn random() -> Self {
use rand::Rng;
- let mut rng = rand::thread_rng();
+ let mut rng = rand::rng();
// simulate a base price in a realistic range
- let prev_close = rng.gen_range(100.0..200.0);
- let change = rng.gen_range(-5.0..5.0);
+ let prev_close = rng.random_range(100.0..200.0);
+ let change = rng.random_range(-5.0..5.0);
let last_done = prev_close + change;
- let open = prev_close + rng.gen_range(-3.0..3.0);
- let high = (prev_close + rng.gen_range::<f64, _>(0.0..10.0)).max(open);
- let low = (prev_close - rng.gen_range::<f64, _>(0.0..10.0)).min(open);
- let timestamp = Duration::from_secs(rng.gen_range(0..86400));
- let volume = rng.gen_range(1_000_000..100_000_000);
+ let open = prev_close + rng.random_range(-3.0..3.0);
+ let high = (prev_close + rng.random_range::<f64, _>(0.0..10.0)).max(open);
+ let low = (prev_close - rng.random_range::<f64, _>(0.0..10.0)).min(open);
+ let timestamp = Duration::from_secs(rng.random_range(0..86400));
+ let volume = rng.random_range(1_000_000..100_000_000);
let turnover = last_done * volume as f64;
let symbol = {
let mut ticker = String::new();
- if rng.gen_bool(0.5) {
+ if rng.random_bool(0.5) {
ticker.push_str(&format!(
"{:03}.{}",
- rng.gen_range(100..1000),
- rng.gen_range(0..10)
+ rng.random_range(100..1000),
+ rng.random_range(0..10)
));
} else {
ticker.push_str(&format!(
"{}{}",
- rng.gen_range('A'..='Z'),
- rng.gen_range('A'..='Z')
+ rng.random_range('A'..='Z'),
+ rng.random_range('A'..='Z')
));
}
- ticker.push_str(&format!(".{}", rng.gen_range('A'..='Z')));
+ ticker.push_str(&format!(".{}", rng.random_range('A'..='Z')));
ticker
};
let name = format!(
"{} {} - #{}",
symbol,
- rng.gen_range(1..100),
- rng.gen_range(10000..100000)
+ rng.random_range(1..100),
+ rng.random_range(10000..100000)
);
- let ttm = rng.gen_range(0.0..10.0);
- let market_cap = rng.gen_range(1_000_000.0..10_000_000.0);
- let float_cap = market_cap + rng.gen_range(1_000.0..10_000.0);
- let shares = rng.gen_range(100.0..1000.0);
+ let ttm = rng.random_range(0.0..10.0);
+ let market_cap = rng.random_range(1_000_000.0..10_000_000.0);
+ let float_cap = market_cap + rng.random_range(1_000.0..10_000.0);
+ let shares = rng.random_range(100.0..1000.0);
let pb = market_cap / shares;
let pe = market_cap / shares;
let eps = market_cap / shares;
- let dividend = rng.gen_range(0.0..10.0);
- let dividend_yield = rng.gen_range(0.0..10.0);
- let dividend_per_share = rng.gen_range(0.0..10.0);
+ let dividend = rng.random_range(0.0..10.0);
+ let dividend_yield = rng.random_range(0.0..10.0);
+ let dividend_per_share = rng.random_range(0.0..10.0);
let dividend_date = SharedString::new(format!(
"{}-{}-{}",
- rng.gen_range(2000..2023),
- rng.gen_range(1..12),
- rng.gen_range(1..28)
+ rng.random_range(2000..2023),
+ rng.random_range(1..12),
+ rng.random_range(1..28)
));
- let dividend_payment = rng.gen_range(0.0..10.0);
+ let dividend_payment = rng.random_range(0.0..10.0);
Self {
name: name.into(),
@@ -144,7 +144,7 @@ impl TestAppContext {
/// Create a single TestAppContext, for non-multi-client tests
pub fn single() -> Self {
- let dispatcher = TestDispatcher::new(StdRng::from_entropy());
+ let dispatcher = TestDispatcher::new(StdRng::seed_from_u64(0));
Self::build(dispatcher, None)
}
@@ -309,12 +309,12 @@ mod tests {
let mut expected_quads: Vec<(Bounds<f32>, u32)> = Vec::new();
// Insert a random number of random AABBs into the tree.
- let num_bounds = rng.gen_range(1..=max_bounds);
+ let num_bounds = rng.random_range(1..=max_bounds);
for _ in 0..num_bounds {
- let min_x: f32 = rng.gen_range(-100.0..100.0);
- let min_y: f32 = rng.gen_range(-100.0..100.0);
- let width: f32 = rng.gen_range(0.0..50.0);
- let height: f32 = rng.gen_range(0.0..50.0);
+ let min_x: f32 = rng.random_range(-100.0..100.0);
+ let min_y: f32 = rng.random_range(-100.0..100.0);
+ let width: f32 = rng.random_range(0.0..50.0);
+ let height: f32 = rng.random_range(0.0..50.0);
let bounds = Bounds {
origin: Point { x: min_x, y: min_y },
size: Size { width, height },
@@ -118,7 +118,7 @@ impl TestDispatcher {
}
YieldNow {
- count: self.state.lock().random.gen_range(0..10),
+ count: self.state.lock().random.random_range(0..10),
}
}
@@ -151,11 +151,11 @@ impl TestDispatcher {
if deprioritized_background_len == 0 {
return false;
}
- let ix = state.random.gen_range(0..deprioritized_background_len);
+ let ix = state.random.random_range(0..deprioritized_background_len);
main_thread = false;
runnable = state.deprioritized_background.swap_remove(ix);
} else {
- main_thread = state.random.gen_ratio(
+ main_thread = state.random.random_ratio(
foreground_len as u32,
(foreground_len + background_len) as u32,
);
@@ -170,7 +170,7 @@ impl TestDispatcher {
.pop_front()
.unwrap();
} else {
- let ix = state.random.gen_range(0..background_len);
+ let ix = state.random.random_range(0..background_len);
runnable = state.background.swap_remove(ix);
};
};
@@ -241,7 +241,7 @@ impl TestDispatcher {
pub fn gen_block_on_ticks(&self) -> usize {
let mut lock = self.state.lock();
let block_on_ticks = lock.block_on_ticks.clone();
- lock.random.gen_range(block_on_ticks)
+ lock.random.random_range(block_on_ticks)
}
}
@@ -94,7 +94,11 @@ impl WindowsPlatform {
}
let directx_devices = DirectXDevices::new().context("Creating DirectX devices")?;
let (main_sender, main_receiver) = flume::unbounded::<Runnable>();
- let validation_number = rand::random::<usize>();
+ let validation_number = if usize::BITS == 64 {
+ rand::random::<u64>() as usize
+ } else {
+ rand::random::<u32>() as usize
+ };
let raw_window_handles = Arc::new(RwLock::new(SmallVec::new()));
let text_system = Arc::new(
DirectWriteTextSystem::new(&directx_devices)
@@ -2842,12 +2842,12 @@ impl Buffer {
let new_start = last_end.map_or(0, |last_end| last_end + 1);
let mut range = self.random_byte_range(new_start, rng);
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
mem::swap(&mut range.start, &mut range.end);
}
last_end = Some(range.end);
- let new_text_len = rng.gen_range(0..10);
+ let new_text_len = rng.random_range(0..10);
let mut new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
new_text = new_text.to_uppercase();
@@ -3013,7 +3013,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let base_text_len = rng.gen_range(0..10);
+ let base_text_len = rng.random_range(0..10);
let base_text = RandomCharIter::new(&mut rng)
.take(base_text_len)
.collect::<String>();
@@ -3022,7 +3022,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
let network = Arc::new(Mutex::new(Network::new(rng.clone())));
let base_buffer = cx.new(|cx| Buffer::local(base_text.as_str(), cx));
- for i in 0..rng.gen_range(min_peers..=max_peers) {
+ for i in 0..rng.random_range(min_peers..=max_peers) {
let buffer = cx.new(|cx| {
let state = base_buffer.read(cx).to_proto(cx);
let ops = cx
@@ -3035,7 +3035,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
.map(|op| proto::deserialize_operation(op).unwrap()),
cx,
);
- buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
+ buffer.set_group_interval(Duration::from_millis(rng.random_range(0..=200)));
let network = network.clone();
cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
if let BufferEvent::Operation {
@@ -3066,11 +3066,11 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
let mut next_diagnostic_id = 0;
let mut active_selections = BTreeMap::default();
loop {
- let replica_index = rng.gen_range(0..replica_ids.len());
+ let replica_index = rng.random_range(0..replica_ids.len());
let replica_id = replica_ids[replica_index];
let buffer = &mut buffers[replica_index];
let mut new_buffer = None;
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
0..=29 if mutation_count != 0 => {
buffer.update(cx, |buffer, cx| {
buffer.start_transaction_at(now);
@@ -3082,13 +3082,13 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
}
30..=39 if mutation_count != 0 => {
buffer.update(cx, |buffer, cx| {
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
log::info!("peer {} clearing active selections", replica_id);
active_selections.remove(&replica_id);
buffer.remove_active_selections(cx);
} else {
let mut selections = Vec::new();
- for id in 0..rng.gen_range(1..=5) {
+ for id in 0..rng.random_range(1..=5) {
let range = buffer.random_byte_range(0, &mut rng);
selections.push(Selection {
id,
@@ -3111,7 +3111,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
mutation_count -= 1;
}
40..=49 if mutation_count != 0 && replica_id == 0 => {
- let entry_count = rng.gen_range(1..=5);
+ let entry_count = rng.random_range(1..=5);
buffer.update(cx, |buffer, cx| {
let diagnostics = DiagnosticSet::new(
(0..entry_count).map(|_| {
@@ -3166,7 +3166,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
new_buffer.replica_id(),
new_buffer.text()
);
- new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
+ new_buffer.set_group_interval(Duration::from_millis(rng.random_range(0..=200)));
let network = network.clone();
cx.subscribe(&cx.entity(), move |buffer, _, event, _| {
if let BufferEvent::Operation {
@@ -3238,7 +3238,7 @@ fn test_random_collaboration(cx: &mut App, mut rng: StdRng) {
_ => {}
}
- now += Duration::from_millis(rng.gen_range(0..=200));
+ now += Duration::from_millis(rng.random_range(0..=200));
buffers.extend(new_buffer);
for buffer in &buffers {
@@ -3320,23 +3320,23 @@ fn test_trailing_whitespace_ranges(mut rng: StdRng) {
// Generate a random multi-line string containing
// some lines with trailing whitespace.
let mut text = String::new();
- for _ in 0..rng.gen_range(0..16) {
- for _ in 0..rng.gen_range(0..36) {
- text.push(match rng.gen_range(0..10) {
+ for _ in 0..rng.random_range(0..16) {
+ for _ in 0..rng.random_range(0..36) {
+ text.push(match rng.random_range(0..10) {
0..=1 => ' ',
3 => '\t',
- _ => rng.gen_range('a'..='z'),
+ _ => rng.random_range('a'..='z'),
});
}
text.push('\n');
}
- match rng.gen_range(0..10) {
+ match rng.random_range(0..10) {
// sometimes remove the last newline
0..=1 => drop(text.pop()), //
// sometimes add extra newlines
- 2..=3 => text.push_str(&"\n".repeat(rng.gen_range(1..5))),
+ 2..=3 => text.push_str(&"\n".repeat(rng.random_range(1..5))),
_ => {}
}
@@ -3580,7 +3580,7 @@ impl MultiBuffer {
pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::App) -> Entity<Self> {
cx.new(|cx| {
let mut multibuffer = MultiBuffer::new(Capability::ReadWrite);
- let mutation_count = rng.gen_range(1..=5);
+ let mutation_count = rng.random_range(1..=5);
multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
multibuffer
})
@@ -3603,16 +3603,17 @@ impl MultiBuffer {
}
let new_start = last_end.map_or(0, |last_end| last_end + 1);
- let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right);
- let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right);
+ let end =
+ snapshot.clip_offset(rng.random_range(new_start..=snapshot.len()), Bias::Right);
+ let start = snapshot.clip_offset(rng.random_range(new_start..=end), Bias::Right);
last_end = Some(end);
let mut range = start..end;
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
mem::swap(&mut range.start, &mut range.end);
}
- let new_text_len = rng.gen_range(0..10);
+ let new_text_len = rng.random_range(0..10);
let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
edits.push((range, new_text.into()));
@@ -3639,18 +3640,18 @@ impl MultiBuffer {
let mut buffers = Vec::new();
for _ in 0..mutation_count {
- if rng.gen_bool(0.05) {
+ if rng.random_bool(0.05) {
log::info!("Clearing multi-buffer");
self.clear(cx);
continue;
- } else if rng.gen_bool(0.1) && !self.excerpt_ids().is_empty() {
+ } else if rng.random_bool(0.1) && !self.excerpt_ids().is_empty() {
let ids = self.excerpt_ids();
let mut excerpts = HashSet::default();
- for _ in 0..rng.gen_range(0..ids.len()) {
+ for _ in 0..rng.random_range(0..ids.len()) {
excerpts.extend(ids.choose(rng).copied());
}
- let line_count = rng.gen_range(0..5);
+ let line_count = rng.random_range(0..5);
log::info!("Expanding excerpts {excerpts:?} by {line_count} lines");
@@ -3664,8 +3665,8 @@ impl MultiBuffer {
}
let excerpt_ids = self.excerpt_ids();
- if excerpt_ids.is_empty() || (rng.r#gen() && excerpt_ids.len() < max_excerpts) {
- let buffer_handle = if rng.r#gen() || self.buffers.borrow().is_empty() {
+ if excerpt_ids.is_empty() || (rng.random() && excerpt_ids.len() < max_excerpts) {
+ let buffer_handle = if rng.random() || self.buffers.borrow().is_empty() {
let text = RandomCharIter::new(&mut *rng).take(10).collect::<String>();
buffers.push(cx.new(|cx| Buffer::local(text, cx)));
let buffer = buffers.last().unwrap().read(cx);
@@ -3687,11 +3688,11 @@ impl MultiBuffer {
let buffer = buffer_handle.read(cx);
let buffer_text = buffer.text();
- let ranges = (0..rng.gen_range(0..5))
+ let ranges = (0..rng.random_range(0..5))
.map(|_| {
let end_ix =
- buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right);
- let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
+ buffer.clip_offset(rng.random_range(0..=buffer.len()), Bias::Right);
+ let start_ix = buffer.clip_offset(rng.random_range(0..=end_ix), Bias::Left);
ExcerptRange::new(start_ix..end_ix)
})
.collect::<Vec<_>>();
@@ -3708,7 +3709,7 @@ impl MultiBuffer {
let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx);
log::info!("Inserted with ids: {:?}", excerpt_id);
} else {
- let remove_count = rng.gen_range(1..=excerpt_ids.len());
+ let remove_count = rng.random_range(1..=excerpt_ids.len());
let mut excerpts_to_remove = excerpt_ids
.choose_multiple(rng, remove_count)
.cloned()
@@ -3730,7 +3731,7 @@ impl MultiBuffer {
) {
use rand::prelude::*;
- if rng.gen_bool(0.7) || self.singleton {
+ if rng.random_bool(0.7) || self.singleton {
let buffer = self
.buffers
.borrow()
@@ -3740,7 +3741,7 @@ impl MultiBuffer {
if let Some(buffer) = buffer {
buffer.update(cx, |buffer, cx| {
- if rng.r#gen() {
+ if rng.random() {
buffer.randomly_edit(rng, mutation_count, cx);
} else {
buffer.randomly_undo_redo(rng, cx);
@@ -6388,8 +6389,8 @@ impl MultiBufferSnapshot {
#[cfg(any(test, feature = "test-support"))]
impl MultiBufferSnapshot {
pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
- let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
- let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
+ let end = self.clip_offset(rng.random_range(start_offset..=self.len()), Bias::Right);
+ let start = self.clip_offset(rng.random_range(start_offset..=end), Bias::Right);
start..end
}
@@ -2491,12 +2491,12 @@ async fn test_random_set_ranges(cx: &mut TestAppContext, mut rng: StdRng) {
for _ in 0..operations {
let snapshot = buf.update(cx, |buf, _| buf.snapshot());
- let num_ranges = rng.gen_range(0..=10);
+ let num_ranges = rng.random_range(0..=10);
let max_row = snapshot.max_point().row;
let mut ranges = (0..num_ranges)
.map(|_| {
- let start = rng.gen_range(0..max_row);
- let end = rng.gen_range(start + 1..max_row + 1);
+ let start = rng.random_range(0..max_row);
+ let end = rng.random_range(start + 1..max_row + 1);
Point::row_range(start..end)
})
.collect::<Vec<_>>();
@@ -2562,11 +2562,11 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let mut needs_diff_calculation = false;
for _ in 0..operations {
- match rng.gen_range(0..100) {
+ match rng.random_range(0..100) {
0..=14 if !buffers.is_empty() => {
let buffer = buffers.choose(&mut rng).unwrap();
buffer.update(cx, |buf, cx| {
- let edit_count = rng.gen_range(1..5);
+ let edit_count = rng.random_range(1..5);
buf.randomly_edit(&mut rng, edit_count, cx);
log::info!("buffer text:\n{}", buf.text());
needs_diff_calculation = true;
@@ -2577,11 +2577,11 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
multibuffer.update(cx, |multibuffer, cx| {
let ids = multibuffer.excerpt_ids();
let mut excerpts = HashSet::default();
- for _ in 0..rng.gen_range(0..ids.len()) {
+ for _ in 0..rng.random_range(0..ids.len()) {
excerpts.extend(ids.choose(&mut rng).copied());
}
- let line_count = rng.gen_range(0..5);
+ let line_count = rng.random_range(0..5);
let excerpt_ixs = excerpts
.iter()
@@ -2600,7 +2600,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
}
20..=29 if !reference.excerpts.is_empty() => {
let mut ids_to_remove = vec![];
- for _ in 0..rng.gen_range(1..=3) {
+ for _ in 0..rng.random_range(1..=3) {
let Some(excerpt) = reference.excerpts.choose(&mut rng) else {
break;
};
@@ -2620,8 +2620,12 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let multibuffer =
multibuffer.read_with(cx, |multibuffer, cx| multibuffer.snapshot(cx));
let offset =
- multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left);
- let bias = if rng.r#gen() { Bias::Left } else { Bias::Right };
+ multibuffer.clip_offset(rng.random_range(0..=multibuffer.len()), Bias::Left);
+ let bias = if rng.random() {
+ Bias::Left
+ } else {
+ Bias::Right
+ };
log::info!("Creating anchor at {} with bias {:?}", offset, bias);
anchors.push(multibuffer.anchor_at(offset, bias));
anchors.sort_by(|a, b| a.cmp(b, &multibuffer));
@@ -2654,7 +2658,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
45..=55 if !reference.excerpts.is_empty() => {
multibuffer.update(cx, |multibuffer, cx| {
let snapshot = multibuffer.snapshot(cx);
- let excerpt_ix = rng.gen_range(0..reference.excerpts.len());
+ let excerpt_ix = rng.random_range(0..reference.excerpts.len());
let excerpt = &reference.excerpts[excerpt_ix];
let start = excerpt.range.start;
let end = excerpt.range.end;
@@ -2691,7 +2695,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
});
}
_ => {
- let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
+ let buffer_handle = if buffers.is_empty() || rng.random_bool(0.4) {
let mut base_text = util::RandomCharIter::new(&mut rng)
.take(256)
.collect::<String>();
@@ -2708,7 +2712,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
buffers.choose(&mut rng).unwrap()
};
- let prev_excerpt_ix = rng.gen_range(0..=reference.excerpts.len());
+ let prev_excerpt_ix = rng.random_range(0..=reference.excerpts.len());
let prev_excerpt_id = reference
.excerpts
.get(prev_excerpt_ix)
@@ -2716,8 +2720,8 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let excerpt_ix = (prev_excerpt_ix + 1).min(reference.excerpts.len());
let (range, anchor_range) = buffer_handle.read_with(cx, |buffer, _| {
- let end_row = rng.gen_range(0..=buffer.max_point().row);
- let start_row = rng.gen_range(0..=end_row);
+ let end_row = rng.random_range(0..=buffer.max_point().row);
+ let start_row = rng.random_range(0..=end_row);
let end_ix = buffer.point_to_offset(Point::new(end_row, 0));
let start_ix = buffer.point_to_offset(Point::new(start_row, 0));
let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix);
@@ -2766,7 +2770,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
}
}
- if rng.gen_bool(0.3) {
+ if rng.random_bool(0.3) {
multibuffer.update(cx, |multibuffer, cx| {
old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe()));
})
@@ -2815,7 +2819,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
pretty_assertions::assert_eq!(actual_row_infos, expected_row_infos);
for _ in 0..5 {
- let start_row = rng.gen_range(0..=expected_row_infos.len());
+ let start_row = rng.random_range(0..=expected_row_infos.len());
assert_eq!(
snapshot
.row_infos(MultiBufferRow(start_row as u32))
@@ -2872,8 +2876,8 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
let text_rope = Rope::from(expected_text.as_str());
for _ in 0..10 {
- let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
- let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
+ let end_ix = text_rope.clip_offset(rng.random_range(0..=text_rope.len()), Bias::Right);
+ let start_ix = text_rope.clip_offset(rng.random_range(0..=end_ix), Bias::Left);
let text_for_range = snapshot
.text_for_range(start_ix..end_ix)
@@ -2908,7 +2912,7 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
}
for _ in 0..10 {
- let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right);
+ let end_ix = text_rope.clip_offset(rng.random_range(0..=text_rope.len()), Bias::Right);
assert_eq!(
snapshot.reversed_chars_at(end_ix).collect::<String>(),
expected_text[..end_ix].chars().rev().collect::<String>(),
@@ -2916,8 +2920,8 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
}
for _ in 0..10 {
- let end_ix = rng.gen_range(0..=text_rope.len());
- let start_ix = rng.gen_range(0..=end_ix);
+ let end_ix = rng.random_range(0..=text_rope.len());
+ let start_ix = rng.random_range(0..=end_ix);
assert_eq!(
snapshot
.bytes_in_range(start_ix..end_ix)
@@ -3761,7 +3761,7 @@ impl LspStore {
worktree_store,
languages: languages.clone(),
language_server_statuses: Default::default(),
- nonce: StdRng::from_entropy().r#gen(),
+ nonce: StdRng::from_os_rng().random(),
diagnostic_summaries: HashMap::default(),
lsp_server_capabilities: HashMap::default(),
lsp_document_colors: HashMap::default(),
@@ -3823,7 +3823,7 @@ impl LspStore {
worktree_store,
languages: languages.clone(),
language_server_statuses: Default::default(),
- nonce: StdRng::from_entropy().r#gen(),
+ nonce: StdRng::from_os_rng().random(),
diagnostic_summaries: HashMap::default(),
lsp_server_capabilities: HashMap::default(),
lsp_document_colors: HashMap::default(),
@@ -7661,7 +7661,7 @@ async fn test_staging_random_hunks(
.unwrap_or(20);
// Try to induce races between diff recalculation and index writes.
- if rng.gen_bool(0.5) {
+ if rng.random_bool(0.5) {
executor.deprioritize(*CALCULATE_DIFF_TASK);
}
@@ -7717,7 +7717,7 @@ async fn test_staging_random_hunks(
assert_eq!(hunks.len(), 6);
for _i in 0..operations {
- let hunk_ix = rng.gen_range(0..hunks.len());
+ let hunk_ix = rng.random_range(0..hunks.len());
let hunk = &mut hunks[hunk_ix];
let row = hunk.range.start.row;
@@ -7735,7 +7735,7 @@ async fn test_staging_random_hunks(
hunk.secondary_status = SecondaryHunkAdditionPending;
}
- for _ in 0..rng.gen_range(0..10) {
+ for _ in 0..rng.random_range(0..10) {
log::info!("yielding");
cx.executor().simulate_random_delay().await;
}
@@ -28,11 +28,11 @@ fn generate_random_rope_ranges(mut rng: StdRng, rope: &Rope) -> Vec<Range<usize>
let mut start = 0;
for _ in 0..num_ranges {
let range_start = rope.clip_offset(
- rng.gen_range(start..=(start + range_max_len)),
+ rng.random_range(start..=(start + range_max_len)),
sum_tree::Bias::Left,
);
let range_end = rope.clip_offset(
- rng.gen_range(range_start..(range_start + range_max_len)),
+ rng.random_range(range_start..(range_start + range_max_len)),
sum_tree::Bias::Right,
);
@@ -52,7 +52,7 @@ fn generate_random_rope_points(mut rng: StdRng, rope: &Rope) -> Vec<Point> {
let mut points = Vec::new();
for _ in 0..num_points {
- points.push(rope.offset_to_point(rng.gen_range(0..rope.len())));
+ points.push(rope.offset_to_point(rng.random_range(0..rope.len())));
}
points
}
@@ -612,7 +612,7 @@ mod tests {
#[gpui::test(iterations = 100)]
fn test_random_chunks(mut rng: StdRng) {
- let chunk_len = rng.gen_range(0..=MAX_BASE);
+ let chunk_len = rng.random_range(0..=MAX_BASE);
let text = RandomCharIter::new(&mut rng)
.take(chunk_len)
.collect::<String>();
@@ -627,8 +627,8 @@ mod tests {
verify_chunk(chunk.as_slice(), text);
for _ in 0..10 {
- let mut start = rng.gen_range(0..=chunk.text.len());
- let mut end = rng.gen_range(start..=chunk.text.len());
+ let mut start = rng.random_range(0..=chunk.text.len());
+ let mut end = rng.random_range(start..=chunk.text.len());
while !chunk.text.is_char_boundary(start) {
start -= 1;
}
@@ -645,7 +645,7 @@ mod tests {
#[gpui::test(iterations = 1000)]
fn test_nth_set_bit_random(mut rng: StdRng) {
- let set_count = rng.gen_range(0..=128);
+ let set_count = rng.random_range(0..=128);
let mut set_bits = (0..128).choose_multiple(&mut rng, set_count);
set_bits.sort();
let mut n = 0;
@@ -1610,9 +1610,9 @@ mod tests {
let mut expected = String::new();
let mut actual = Rope::new();
for _ in 0..operations {
- let end_ix = clip_offset(&expected, rng.gen_range(0..=expected.len()), Right);
- let start_ix = clip_offset(&expected, rng.gen_range(0..=end_ix), Left);
- let len = rng.gen_range(0..=64);
+ let end_ix = clip_offset(&expected, rng.random_range(0..=expected.len()), Right);
+ let start_ix = clip_offset(&expected, rng.random_range(0..=end_ix), Left);
+ let len = rng.random_range(0..=64);
let new_text: String = RandomCharIter::new(&mut rng).take(len).collect();
let mut new_actual = Rope::new();
@@ -1629,8 +1629,8 @@ mod tests {
log::info!("text: {:?}", expected);
for _ in 0..5 {
- let end_ix = clip_offset(&expected, rng.gen_range(0..=expected.len()), Right);
- let start_ix = clip_offset(&expected, rng.gen_range(0..=end_ix), Left);
+ let end_ix = clip_offset(&expected, rng.random_range(0..=expected.len()), Right);
+ let start_ix = clip_offset(&expected, rng.random_range(0..=end_ix), Left);
let actual_text = actual.chunks_in_range(start_ix..end_ix).collect::<String>();
assert_eq!(actual_text, &expected[start_ix..end_ix]);
@@ -1695,14 +1695,14 @@ mod tests {
);
// Check that next_line/prev_line work correctly from random positions
- let mut offset = rng.gen_range(start_ix..=end_ix);
+ let mut offset = rng.random_range(start_ix..=end_ix);
while !expected.is_char_boundary(offset) {
offset -= 1;
}
chunks.seek(offset);
for _ in 0..5 {
- if rng.r#gen() {
+ if rng.random() {
let expected_next_line_start = expected[offset..end_ix]
.find('\n')
.map(|newline_ix| offset + newline_ix + 1);
@@ -1791,8 +1791,8 @@ mod tests {
}
assert!((start_ix..=end_ix).contains(&chunks.offset()));
- if rng.r#gen() {
- offset = rng.gen_range(start_ix..=end_ix);
+ if rng.random() {
+ offset = rng.random_range(start_ix..=end_ix);
while !expected.is_char_boundary(offset) {
offset -= 1;
}
@@ -1876,8 +1876,8 @@ mod tests {
}
for _ in 0..5 {
- let end_ix = clip_offset(&expected, rng.gen_range(0..=expected.len()), Right);
- let start_ix = clip_offset(&expected, rng.gen_range(0..=end_ix), Left);
+ let end_ix = clip_offset(&expected, rng.random_range(0..=expected.len()), Right);
+ let start_ix = clip_offset(&expected, rng.random_range(0..=end_ix), Left);
assert_eq!(
actual.cursor(start_ix).summary::<TextSummary>(end_ix),
TextSummary::from(&expected[start_ix..end_ix])
@@ -1,6 +1,6 @@
use anyhow::{Context as _, Result};
use base64::prelude::*;
-use rand::{Rng as _, thread_rng};
+use rand::prelude::*;
use rsa::pkcs1::{DecodeRsaPublicKey, EncodeRsaPublicKey};
use rsa::traits::PaddingScheme;
use rsa::{Oaep, Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
@@ -31,7 +31,7 @@ pub struct PrivateKey(RsaPrivateKey);
/// Generate a public and private key for asymmetric encryption.
pub fn keypair() -> Result<(PublicKey, PrivateKey)> {
- let mut rng = thread_rng();
+ let mut rng = RsaRngCompat::new();
let bits = 2048;
let private_key = RsaPrivateKey::new(&mut rng, bits)?;
let public_key = RsaPublicKey::from(&private_key);
@@ -40,10 +40,10 @@ pub fn keypair() -> Result<(PublicKey, PrivateKey)> {
/// Generate a random 64-character base64 string.
pub fn random_token() -> String {
- let mut rng = thread_rng();
+ let mut rng = rand::rng();
let mut token_bytes = [0; 48];
for byte in token_bytes.iter_mut() {
- *byte = rng.r#gen();
+ *byte = rng.random();
}
BASE64_URL_SAFE.encode(token_bytes)
}
@@ -52,7 +52,7 @@ impl PublicKey {
/// Convert a string to a base64-encoded string that can only be decoded with the corresponding
/// private key.
pub fn encrypt_string(&self, string: &str, format: EncryptionFormat) -> Result<String> {
- let mut rng = thread_rng();
+ let mut rng = RsaRngCompat::new();
let bytes = string.as_bytes();
let encrypted_bytes = match format {
EncryptionFormat::V0 => self.0.encrypt(&mut rng, Pkcs1v15Encrypt, bytes),
@@ -107,6 +107,36 @@ impl TryFrom<String> for PublicKey {
}
}
+// TODO: remove once we rsa v0.10 is released.
+struct RsaRngCompat(rand::rngs::ThreadRng);
+
+impl RsaRngCompat {
+ fn new() -> Self {
+ Self(rand::rng())
+ }
+}
+
+impl rsa::signature::rand_core::RngCore for RsaRngCompat {
+ fn next_u32(&mut self) -> u32 {
+ self.0.next_u32()
+ }
+
+ fn next_u64(&mut self) -> u64 {
+ self.0.next_u64()
+ }
+
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ self.0.fill_bytes(dest);
+ }
+
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rsa::signature::rand_core::Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+impl rsa::signature::rand_core::CryptoRng for RsaRngCompat {}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -0,0 +1,25 @@
+[package]
+name = "scheduler"
+version = "0.1.0"
+edition.workspace = true
+publish.workspace = true
+license = "Apache-2.0"
+
+[lints]
+workspace = true
+
+[lib]
+path = "src/scheduler.rs"
+doctest = false
+
+[features]
+test-support = []
+
+[dependencies]
+async-task.workspace = true
+chrono.workspace = true
+futures.workspace = true
+parking.workspace = true
+parking_lot.workspace = true
+rand.workspace = true
+workspace-hack.workspace = true
@@ -0,0 +1 @@
+../../LICENSE-APACHE
@@ -0,0 +1,34 @@
+use chrono::{DateTime, Duration, Utc};
+use parking_lot::Mutex;
+
+pub trait Clock {
+ fn now(&self) -> DateTime<Utc>;
+}
+
+pub struct TestClock {
+ now: Mutex<DateTime<Utc>>,
+}
+
+impl TestClock {
+ pub fn new() -> Self {
+ const START_TIME: &str = "2025-07-01T23:59:58-00:00";
+ let now = DateTime::parse_from_rfc3339(START_TIME).unwrap().to_utc();
+ Self {
+ now: Mutex::new(now),
+ }
+ }
+
+ pub fn set_now(&self, now: DateTime<Utc>) {
+ *self.now.lock() = now;
+ }
+
+ pub fn advance(&self, duration: Duration) {
+ *self.now.lock() += duration;
+ }
+}
+
+impl Clock for TestClock {
+ fn now(&self) -> DateTime<Utc> {
+ *self.now.lock()
+ }
+}
@@ -0,0 +1,137 @@
+use crate::{Scheduler, SessionId, Timer};
+use std::{
+ future::Future,
+ marker::PhantomData,
+ pin::Pin,
+ rc::Rc,
+ sync::Arc,
+ task::{Context, Poll},
+ time::Duration,
+};
+
+#[derive(Clone)]
+pub struct ForegroundExecutor {
+ session_id: SessionId,
+ scheduler: Arc<dyn Scheduler>,
+ not_send: PhantomData<Rc<()>>,
+}
+
+impl ForegroundExecutor {
+ pub fn spawn<F>(&self, future: F) -> Task<F::Output>
+ where
+ F: Future + 'static,
+ F::Output: 'static,
+ {
+ let session_id = self.session_id;
+ let scheduler = Arc::clone(&self.scheduler);
+ let (runnable, task) = async_task::spawn_local(future, move |runnable| {
+ scheduler.schedule_foreground(session_id, runnable);
+ });
+ runnable.schedule();
+ Task(TaskState::Spawned(task))
+ }
+
+ pub fn timer(&self, duration: Duration) -> Timer {
+ self.scheduler.timer(duration)
+ }
+}
+
+impl ForegroundExecutor {
+ pub fn new(session_id: SessionId, scheduler: Arc<dyn Scheduler>) -> Self {
+ assert!(
+ scheduler.is_main_thread(),
+ "ForegroundExecutor must be created on the same thread as the Scheduler"
+ );
+ Self {
+ session_id,
+ scheduler,
+ not_send: PhantomData,
+ }
+ }
+}
+
+impl BackgroundExecutor {
+ pub fn new(scheduler: Arc<dyn Scheduler>) -> Self {
+ Self { scheduler }
+ }
+}
+
+pub struct BackgroundExecutor {
+ scheduler: Arc<dyn Scheduler>,
+}
+
+impl BackgroundExecutor {
+ pub fn spawn<F>(&self, future: F) -> Task<F::Output>
+ where
+ F: Future + Send + 'static,
+ F::Output: Send + 'static,
+ {
+ let scheduler = Arc::clone(&self.scheduler);
+ let (runnable, task) = async_task::spawn(future, move |runnable| {
+ scheduler.schedule_background(runnable);
+ });
+ runnable.schedule();
+ Task(TaskState::Spawned(task))
+ }
+
+ pub fn block_on<Fut: Future>(&self, future: Fut) -> Fut::Output {
+ self.scheduler.block_on(future)
+ }
+
+ pub fn block_with_timeout<Fut: Unpin + Future>(
+ &self,
+ future: &mut Fut,
+ timeout: Duration,
+ ) -> Option<Fut::Output> {
+ self.scheduler.block_with_timeout(future, timeout)
+ }
+
+ pub fn timer(&self, duration: Duration) -> Timer {
+ self.scheduler.timer(duration)
+ }
+}
+
+/// Task is a primitive that allows work to happen in the background.
+///
+/// It implements [`Future`] so you can `.await` on it.
+///
+/// If you drop a task it will be cancelled immediately. Calling [`Task::detach`] allows
+/// the task to continue running, but with no way to return a value.
+#[must_use]
+#[derive(Debug)]
+pub struct Task<T>(TaskState<T>);
+
+#[derive(Debug)]
+enum TaskState<T> {
+ /// A task that is ready to return a value
+ Ready(Option<T>),
+
+ /// A task that is currently running.
+ Spawned(async_task::Task<T>),
+}
+
+impl<T> Task<T> {
+ /// Creates a new task that will resolve with the value
+ pub fn ready(val: T) -> Self {
+ Task(TaskState::Ready(Some(val)))
+ }
+
+ /// Detaching a task runs it to completion in the background
+ pub fn detach(self) {
+ match self {
+ Task(TaskState::Ready(_)) => {}
+ Task(TaskState::Spawned(task)) => task.detach(),
+ }
+ }
+}
+
+impl<T> Future for Task<T> {
+ type Output = T;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+ match unsafe { self.get_unchecked_mut() } {
+ Task(TaskState::Ready(val)) => Poll::Ready(val.take().unwrap()),
+ Task(TaskState::Spawned(task)) => Pin::new(task).poll(cx),
+ }
+ }
+}
@@ -0,0 +1,63 @@
+mod clock;
+mod executor;
+mod test_scheduler;
+#[cfg(test)]
+mod tests;
+
+pub use clock::*;
+pub use executor::*;
+pub use test_scheduler::*;
+
+use async_task::Runnable;
+use futures::{FutureExt as _, channel::oneshot, future::LocalBoxFuture};
+use std::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll},
+ time::Duration,
+};
+
+pub trait Scheduler: Send + Sync {
+ fn block(&self, future: LocalBoxFuture<()>, timeout: Option<Duration>);
+ fn schedule_foreground(&self, session_id: SessionId, runnable: Runnable);
+ fn schedule_background(&self, runnable: Runnable);
+ fn timer(&self, timeout: Duration) -> Timer;
+ fn is_main_thread(&self) -> bool;
+}
+
+impl dyn Scheduler {
+ pub fn block_on<Fut: Future>(&self, future: Fut) -> Fut::Output {
+ let mut output = None;
+ self.block(async { output = Some(future.await) }.boxed_local(), None);
+ output.unwrap()
+ }
+
+ pub fn block_with_timeout<Fut: Unpin + Future>(
+ &self,
+ future: &mut Fut,
+ timeout: Duration,
+ ) -> Option<Fut::Output> {
+ let mut output = None;
+ self.block(
+ async { output = Some(future.await) }.boxed_local(),
+ Some(timeout),
+ );
+ output
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct SessionId(u16);
+
+pub struct Timer(oneshot::Receiver<()>);
+
+impl Future for Timer {
+ type Output = ();
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
+ match self.0.poll_unpin(cx) {
+ Poll::Ready(_) => Poll::Ready(()),
+ Poll::Pending => Poll::Pending,
+ }
+ }
+}
@@ -0,0 +1,352 @@
+use crate::{
+ BackgroundExecutor, Clock as _, ForegroundExecutor, Scheduler, SessionId, TestClock, Timer,
+};
+use async_task::Runnable;
+use chrono::{DateTime, Duration as ChronoDuration, Utc};
+use futures::{FutureExt as _, channel::oneshot, future::LocalBoxFuture};
+use parking_lot::Mutex;
+use rand::prelude::*;
+use std::{
+ collections::VecDeque,
+ future::Future,
+ panic::{self, AssertUnwindSafe},
+ pin::Pin,
+ sync::{
+ Arc,
+ atomic::{AtomicBool, Ordering::SeqCst},
+ },
+ task::{Context, Poll, Wake, Waker},
+ thread,
+ time::{Duration, Instant},
+};
+
+pub struct TestScheduler {
+ clock: Arc<TestClock>,
+ rng: Arc<Mutex<StdRng>>,
+ state: Mutex<SchedulerState>,
+ pub thread_id: thread::ThreadId,
+ pub config: SchedulerConfig,
+}
+
+impl TestScheduler {
+ /// Run a test once with default configuration (seed 0)
+ pub fn once<R>(f: impl AsyncFnOnce(Arc<TestScheduler>) -> R) -> R {
+ Self::with_seed(0, f)
+ }
+
+ /// Run a test multiple times with sequential seeds (0, 1, 2, ...)
+ pub fn many<R>(iterations: usize, mut f: impl AsyncFnMut(Arc<TestScheduler>) -> R) -> Vec<R> {
+ (0..iterations as u64)
+ .map(|seed| {
+ let mut unwind_safe_f = AssertUnwindSafe(&mut f);
+ match panic::catch_unwind(move || Self::with_seed(seed, &mut *unwind_safe_f)) {
+ Ok(result) => result,
+ Err(error) => {
+ eprintln!("Failing Seed: {seed}");
+ panic::resume_unwind(error);
+ }
+ }
+ })
+ .collect()
+ }
+
+ /// Run a test once with a specific seed
+ pub fn with_seed<R>(seed: u64, f: impl AsyncFnOnce(Arc<TestScheduler>) -> R) -> R {
+ let scheduler = Arc::new(TestScheduler::new(SchedulerConfig::with_seed(seed)));
+ let future = f(scheduler.clone());
+ let result = scheduler.block_on(future);
+ scheduler.run();
+ result
+ }
+
+ pub fn new(config: SchedulerConfig) -> Self {
+ Self {
+ rng: Arc::new(Mutex::new(StdRng::seed_from_u64(config.seed))),
+ state: Mutex::new(SchedulerState {
+ runnables: VecDeque::new(),
+ timers: Vec::new(),
+ randomize_order: config.randomize_order,
+ allow_parking: config.allow_parking,
+ next_session_id: SessionId(0),
+ }),
+ thread_id: thread::current().id(),
+ clock: Arc::new(TestClock::new()),
+ config,
+ }
+ }
+
+ pub fn clock(&self) -> Arc<TestClock> {
+ self.clock.clone()
+ }
+
+ pub fn rng(&self) -> Arc<Mutex<StdRng>> {
+ self.rng.clone()
+ }
+
+ /// Create a foreground executor for this scheduler
+ pub fn foreground(self: &Arc<Self>) -> ForegroundExecutor {
+ let session_id = {
+ let mut state = self.state.lock();
+ state.next_session_id.0 += 1;
+ state.next_session_id
+ };
+ ForegroundExecutor::new(session_id, self.clone())
+ }
+
+ /// Create a background executor for this scheduler
+ pub fn background(self: &Arc<Self>) -> BackgroundExecutor {
+ BackgroundExecutor::new(self.clone())
+ }
+
+ pub fn block_on<Fut: Future>(&self, future: Fut) -> Fut::Output {
+ (self as &dyn Scheduler).block_on(future)
+ }
+
+ pub fn yield_random(&self) -> Yield {
+ Yield(self.rng.lock().random_range(0..20))
+ }
+
+ pub fn run(&self) {
+ while self.step() || self.advance_clock() {
+ // Continue until no work remains
+ }
+ }
+
+ fn step(&self) -> bool {
+ let elapsed_timers = {
+ let mut state = self.state.lock();
+ let end_ix = state
+ .timers
+ .partition_point(|timer| timer.expiration <= self.clock.now());
+ state.timers.drain(..end_ix).collect::<Vec<_>>()
+ };
+
+ if !elapsed_timers.is_empty() {
+ return true;
+ }
+
+ let runnable = self.state.lock().runnables.pop_front();
+ if let Some(runnable) = runnable {
+ runnable.run();
+ return true;
+ }
+
+ false
+ }
+
+ fn advance_clock(&self) -> bool {
+ if let Some(timer) = self.state.lock().timers.first() {
+ self.clock.set_now(timer.expiration);
+ true
+ } else {
+ false
+ }
+ }
+}
+
+impl Scheduler for TestScheduler {
+ fn is_main_thread(&self) -> bool {
+ thread::current().id() == self.thread_id
+ }
+
+ fn schedule_foreground(&self, session_id: SessionId, runnable: Runnable) {
+ let mut state = self.state.lock();
+ let ix = if state.randomize_order {
+ let start_ix = state
+ .runnables
+ .iter()
+ .rposition(|task| task.session_id == Some(session_id))
+ .map_or(0, |ix| ix + 1);
+ self.rng
+ .lock()
+ .random_range(start_ix..=state.runnables.len())
+ } else {
+ state.runnables.len()
+ };
+ state.runnables.insert(
+ ix,
+ ScheduledRunnable {
+ session_id: Some(session_id),
+ runnable,
+ },
+ );
+ }
+
+ fn schedule_background(&self, runnable: Runnable) {
+ let mut state = self.state.lock();
+ let ix = if state.randomize_order {
+ self.rng.lock().random_range(0..=state.runnables.len())
+ } else {
+ state.runnables.len()
+ };
+ state.runnables.insert(
+ ix,
+ ScheduledRunnable {
+ session_id: None,
+ runnable,
+ },
+ );
+ }
+
+ fn timer(&self, duration: Duration) -> Timer {
+ let (tx, rx) = oneshot::channel();
+ let expiration = self.clock.now() + ChronoDuration::from_std(duration).unwrap();
+ let state = &mut *self.state.lock();
+ state.timers.push(ScheduledTimer {
+ expiration,
+ _notify: tx,
+ });
+ state.timers.sort_by_key(|timer| timer.expiration);
+ Timer(rx)
+ }
+
+ /// Block until the given future completes, with an optional timeout. If the
+ /// future is unable to make progress at any moment before the timeout and
+ /// no other tasks or timers remain, we panic unless parking is allowed. If
+ /// parking is allowed, we block up to the timeout or indefinitely if none
+ /// is provided. This is to allow testing a mix of deterministic and
+ /// non-deterministic async behavior, such as when interacting with I/O in
+ /// an otherwise deterministic test.
+ fn block(&self, mut future: LocalBoxFuture<()>, timeout: Option<Duration>) {
+ let (parker, unparker) = parking::pair();
+ let deadline = timeout.map(|timeout| Instant::now() + timeout);
+ let awoken = Arc::new(AtomicBool::new(false));
+ let waker = Waker::from(Arc::new(WakerFn::new({
+ let awoken = awoken.clone();
+ move || {
+ awoken.store(true, SeqCst);
+ unparker.unpark();
+ }
+ })));
+ let max_ticks = if timeout.is_some() {
+ self.rng
+ .lock()
+ .random_range(0..=self.config.max_timeout_ticks)
+ } else {
+ usize::MAX
+ };
+ let mut cx = Context::from_waker(&waker);
+
+ for _ in 0..max_ticks {
+ let Poll::Pending = future.poll_unpin(&mut cx) else {
+ break;
+ };
+
+ let mut stepped = None;
+ while self.rng.lock().random() && stepped.unwrap_or(true) {
+ *stepped.get_or_insert(false) |= self.step();
+ }
+
+ let stepped = stepped.unwrap_or(true);
+ let awoken = awoken.swap(false, SeqCst);
+ if !stepped && !awoken && !self.advance_clock() {
+ if self.state.lock().allow_parking {
+ if !park(&parker, deadline) {
+ break;
+ }
+ } else if deadline.is_some() {
+ break;
+ } else {
+ panic!("Parking forbidden");
+ }
+ }
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct SchedulerConfig {
+ pub seed: u64,
+ pub randomize_order: bool,
+ pub allow_parking: bool,
+ pub max_timeout_ticks: usize,
+}
+
+impl SchedulerConfig {
+ pub fn with_seed(seed: u64) -> Self {
+ Self {
+ seed,
+ ..Default::default()
+ }
+ }
+}
+
+impl Default for SchedulerConfig {
+ fn default() -> Self {
+ Self {
+ seed: 0,
+ randomize_order: true,
+ allow_parking: false,
+ max_timeout_ticks: 1000,
+ }
+ }
+}
+
+struct ScheduledRunnable {
+ session_id: Option<SessionId>,
+ runnable: Runnable,
+}
+
+impl ScheduledRunnable {
+ fn run(self) {
+ self.runnable.run();
+ }
+}
+
+struct ScheduledTimer {
+ expiration: DateTime<Utc>,
+ _notify: oneshot::Sender<()>,
+}
+
+struct SchedulerState {
+ runnables: VecDeque<ScheduledRunnable>,
+ timers: Vec<ScheduledTimer>,
+ randomize_order: bool,
+ allow_parking: bool,
+ next_session_id: SessionId,
+}
+
+struct WakerFn<F> {
+ f: F,
+}
+
+impl<F: Fn()> WakerFn<F> {
+ fn new(f: F) -> Self {
+ Self { f }
+ }
+}
+
+impl<F: Fn()> Wake for WakerFn<F> {
+ fn wake(self: Arc<Self>) {
+ (self.f)();
+ }
+
+ fn wake_by_ref(self: &Arc<Self>) {
+ (self.f)();
+ }
+}
+
+pub struct Yield(usize);
+
+impl Future for Yield {
+ type Output = ();
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+ if self.0 == 0 {
+ Poll::Ready(())
+ } else {
+ self.0 -= 1;
+ cx.waker().wake_by_ref();
+ Poll::Pending
+ }
+ }
+}
+
+fn park(parker: &parking::Parker, deadline: Option<Instant>) -> bool {
+ if let Some(deadline) = deadline {
+ parker.park_deadline(deadline)
+ } else {
+ parker.park();
+ true
+ }
+}
@@ -0,0 +1,348 @@
+use super::*;
+use futures::{
+ FutureExt,
+ channel::{mpsc, oneshot},
+ executor::block_on,
+ future,
+ sink::SinkExt,
+ stream::{FuturesUnordered, StreamExt},
+};
+use std::{
+ cell::RefCell,
+ collections::{BTreeSet, HashSet},
+ pin::Pin,
+ rc::Rc,
+ sync::Arc,
+ task::{Context, Poll},
+};
+
+#[test]
+fn test_foreground_executor_spawn() {
+ let result = TestScheduler::once(async |scheduler| {
+ let task = scheduler.foreground().spawn(async move { 42 });
+ task.await
+ });
+ assert_eq!(result, 42);
+}
+
+#[test]
+fn test_background_executor_spawn() {
+ TestScheduler::once(async |scheduler| {
+ let task = scheduler.background().spawn(async move { 42 });
+ let result = task.await;
+ assert_eq!(result, 42);
+ });
+}
+
+#[test]
+fn test_foreground_ordering() {
+ let mut traces = HashSet::new();
+
+ TestScheduler::many(100, async |scheduler| {
+ #[derive(Hash, PartialEq, Eq)]
+ struct TraceEntry {
+ session: usize,
+ task: usize,
+ }
+
+ let trace = Rc::new(RefCell::new(Vec::new()));
+
+ let foreground_1 = scheduler.foreground();
+ for task in 0..10 {
+ foreground_1
+ .spawn({
+ let trace = trace.clone();
+ async move {
+ trace.borrow_mut().push(TraceEntry { session: 0, task });
+ }
+ })
+ .detach();
+ }
+
+ let foreground_2 = scheduler.foreground();
+ for task in 0..10 {
+ foreground_2
+ .spawn({
+ let trace = trace.clone();
+ async move {
+ trace.borrow_mut().push(TraceEntry { session: 1, task });
+ }
+ })
+ .detach();
+ }
+
+ scheduler.run();
+
+ assert_eq!(
+ trace
+ .borrow()
+ .iter()
+ .filter(|entry| entry.session == 0)
+ .map(|entry| entry.task)
+ .collect::<Vec<_>>(),
+ (0..10).collect::<Vec<_>>()
+ );
+ assert_eq!(
+ trace
+ .borrow()
+ .iter()
+ .filter(|entry| entry.session == 1)
+ .map(|entry| entry.task)
+ .collect::<Vec<_>>(),
+ (0..10).collect::<Vec<_>>()
+ );
+
+ traces.insert(trace.take());
+ });
+
+ assert!(traces.len() > 1, "Expected at least two traces");
+}
+
+#[test]
+fn test_timer_ordering() {
+ TestScheduler::many(1, async |scheduler| {
+ let background = scheduler.background();
+ let futures = FuturesUnordered::new();
+ futures.push(
+ async {
+ background.timer(Duration::from_millis(100)).await;
+ 2
+ }
+ .boxed(),
+ );
+ futures.push(
+ async {
+ background.timer(Duration::from_millis(50)).await;
+ 1
+ }
+ .boxed(),
+ );
+ futures.push(
+ async {
+ background.timer(Duration::from_millis(150)).await;
+ 3
+ }
+ .boxed(),
+ );
+ assert_eq!(futures.collect::<Vec<_>>().await, vec![1, 2, 3]);
+ });
+}
+
+#[test]
+fn test_send_from_bg_to_fg() {
+ TestScheduler::once(async |scheduler| {
+ let foreground = scheduler.foreground();
+ let background = scheduler.background();
+
+ let (sender, receiver) = oneshot::channel::<i32>();
+
+ background
+ .spawn(async move {
+ sender.send(42).unwrap();
+ })
+ .detach();
+
+ let task = foreground.spawn(async move { receiver.await.unwrap() });
+ let result = task.await;
+ assert_eq!(result, 42);
+ });
+}
+
+#[test]
+fn test_randomize_order() {
+ // Test deterministic mode: different seeds should produce same execution order
+ let mut deterministic_results = HashSet::new();
+ for seed in 0..10 {
+ let config = SchedulerConfig {
+ seed,
+ randomize_order: false,
+ ..Default::default()
+ };
+ let order = block_on(capture_execution_order(config));
+ assert_eq!(order.len(), 6);
+ deterministic_results.insert(order);
+ }
+
+ // All deterministic runs should produce the same result
+ assert_eq!(
+ deterministic_results.len(),
+ 1,
+ "Deterministic mode should always produce same execution order"
+ );
+
+ // Test randomized mode: different seeds can produce different execution orders
+ let mut randomized_results = HashSet::new();
+ for seed in 0..20 {
+ let config = SchedulerConfig::with_seed(seed);
+ let order = block_on(capture_execution_order(config));
+ assert_eq!(order.len(), 6);
+ randomized_results.insert(order);
+ }
+
+ // Randomized mode should produce multiple different execution orders
+ assert!(
+ randomized_results.len() > 1,
+ "Randomized mode should produce multiple different orders"
+ );
+}
+
+async fn capture_execution_order(config: SchedulerConfig) -> Vec<String> {
+ let scheduler = Arc::new(TestScheduler::new(config));
+ let foreground = scheduler.foreground();
+ let background = scheduler.background();
+
+ let (sender, receiver) = mpsc::unbounded::<String>();
+
+ // Spawn foreground tasks
+ for i in 0..3 {
+ let mut sender = sender.clone();
+ foreground
+ .spawn(async move {
+ sender.send(format!("fg-{}", i)).await.ok();
+ })
+ .detach();
+ }
+
+ // Spawn background tasks
+ for i in 0..3 {
+ let mut sender = sender.clone();
+ background
+ .spawn(async move {
+ sender.send(format!("bg-{}", i)).await.ok();
+ })
+ .detach();
+ }
+
+ drop(sender); // Close sender to signal no more messages
+ scheduler.run();
+
+ receiver.collect().await
+}
+
+#[test]
+fn test_block() {
+ let scheduler = Arc::new(TestScheduler::new(SchedulerConfig::default()));
+ let executor = BackgroundExecutor::new(scheduler);
+ let (tx, rx) = oneshot::channel();
+
+ // Spawn background task to send value
+ let _ = executor
+ .spawn(async move {
+ tx.send(42).unwrap();
+ })
+ .detach();
+
+ // Block on receiving the value
+ let result = executor.block_on(async { rx.await.unwrap() });
+ assert_eq!(result, 42);
+}
+
+#[test]
+#[should_panic(expected = "Parking forbidden")]
+fn test_parking_panics() {
+ let scheduler = Arc::new(TestScheduler::new(SchedulerConfig::default()));
+ let executor = BackgroundExecutor::new(scheduler);
+ executor.block_on(future::pending::<()>());
+}
+
+#[test]
+fn test_block_with_parking() {
+ let config = SchedulerConfig {
+ allow_parking: true,
+ ..Default::default()
+ };
+ let scheduler = Arc::new(TestScheduler::new(config));
+ let executor = BackgroundExecutor::new(scheduler);
+ let (tx, rx) = oneshot::channel();
+
+ // Spawn background task to send value
+ let _ = executor
+ .spawn(async move {
+ tx.send(42).unwrap();
+ })
+ .detach();
+
+ // Block on receiving the value (will park if needed)
+ let result = executor.block_on(async { rx.await.unwrap() });
+ assert_eq!(result, 42);
+}
+
+#[test]
+fn test_helper_methods() {
+ // Test the once method
+ let result = TestScheduler::once(async |scheduler: Arc<TestScheduler>| {
+ let background = scheduler.background();
+ background.spawn(async { 42 }).await
+ });
+ assert_eq!(result, 42);
+
+ // Test the many method
+ let results = TestScheduler::many(3, async |scheduler: Arc<TestScheduler>| {
+ let background = scheduler.background();
+ background.spawn(async { 10 }).await
+ });
+ assert_eq!(results, vec![10, 10, 10]);
+
+ // Test the with_seed method
+ let result = TestScheduler::with_seed(123, async |scheduler: Arc<TestScheduler>| {
+ let background = scheduler.background();
+
+ // Spawn a background task and wait for its result
+ let task = background.spawn(async { 99 });
+ task.await
+ });
+ assert_eq!(result, 99);
+}
+
+#[test]
+fn test_block_with_timeout() {
+ // Test case: future completes within timeout
+ TestScheduler::once(async |scheduler| {
+ let background = scheduler.background();
+ let mut future = future::ready(42);
+ let output = background.block_with_timeout(&mut future, Duration::from_millis(100));
+ assert_eq!(output, Some(42));
+ });
+
+ // Test case: future times out
+ TestScheduler::once(async |scheduler| {
+ let background = scheduler.background();
+ let mut future = future::pending::<()>();
+ let output = background.block_with_timeout(&mut future, Duration::from_millis(50));
+ assert_eq!(output, None);
+ });
+
+ // Test case: future makes progress via timer but still times out
+ let mut results = BTreeSet::new();
+ TestScheduler::many(100, async |scheduler| {
+ let background = scheduler.background();
+ let mut task = background.spawn(async move {
+ Yield { polls: 10 }.await;
+ 42
+ });
+ let output = background.block_with_timeout(&mut task, Duration::from_millis(50));
+ results.insert(output);
+ });
+ assert_eq!(
+ results.into_iter().collect::<Vec<_>>(),
+ vec![None, Some(42)]
+ );
+}
+
+struct Yield {
+ polls: usize,
+}
+
+impl Future for Yield {
+ type Output = ();
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ self.polls -= 1;
+ if self.polls == 0 {
+ Poll::Ready(())
+ } else {
+ cx.waker().wake_by_ref();
+ Poll::Pending
+ }
+ }
+}
@@ -945,7 +945,7 @@ mod tests {
let mut new_len = 0;
while new_len < new.len() {
- let mut chunk_len = rng.gen_range(1..=new.len() - new_len);
+ let mut chunk_len = rng.random_range(1..=new.len() - new_len);
while !new.is_char_boundary(new_len + chunk_len) {
chunk_len += 1;
}
@@ -1034,14 +1034,14 @@ mod tests {
fn randomly_edit(text: &str, rng: &mut impl Rng) -> String {
let mut result = String::from(text);
- let edit_count = rng.gen_range(1..=5);
+ let edit_count = rng.random_range(1..=5);
fn random_char_range(text: &str, rng: &mut impl Rng) -> (usize, usize) {
- let mut start = rng.gen_range(0..=text.len());
+ let mut start = rng.random_range(0..=text.len());
while !text.is_char_boundary(start) {
start -= 1;
}
- let mut end = rng.gen_range(start..=text.len());
+ let mut end = rng.random_range(start..=text.len());
while !text.is_char_boundary(end) {
end += 1;
}
@@ -1049,11 +1049,11 @@ mod tests {
}
for _ in 0..edit_count {
- match rng.gen_range(0..3) {
+ match rng.random_range(0..3) {
0 => {
// Insert
let (pos, _) = random_char_range(&result, rng);
- let insert_len = rng.gen_range(1..=5);
+ let insert_len = rng.random_range(1..=5);
let insert_text: String = random_text(rng, insert_len);
result.insert_str(pos, &insert_text);
}
@@ -909,7 +909,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
- use rand::{distributions, prelude::*};
+ use rand::{distr::StandardUniform, prelude::*};
use std::cmp;
#[ctor::ctor]
@@ -951,24 +951,24 @@ mod tests {
let rng = &mut rng;
let mut tree = SumTree::<u8>::default();
- let count = rng.gen_range(0..10);
- if rng.r#gen() {
- tree.extend(rng.sample_iter(distributions::Standard).take(count), &());
+ let count = rng.random_range(0..10);
+ if rng.random() {
+ tree.extend(rng.sample_iter(StandardUniform).take(count), &());
} else {
let items = rng
- .sample_iter(distributions::Standard)
+ .sample_iter(StandardUniform)
.take(count)
.collect::<Vec<_>>();
tree.par_extend(items, &());
}
for _ in 0..num_operations {
- let splice_end = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
- let splice_start = rng.gen_range(0..splice_end + 1);
- let count = rng.gen_range(0..10);
+ let splice_end = rng.random_range(0..tree.extent::<Count>(&()).0 + 1);
+ let splice_start = rng.random_range(0..splice_end + 1);
+ let count = rng.random_range(0..10);
let tree_end = tree.extent::<Count>(&());
let new_items = rng
- .sample_iter(distributions::Standard)
+ .sample_iter(StandardUniform)
.take(count)
.collect::<Vec<u8>>();
@@ -978,7 +978,7 @@ mod tests {
tree = {
let mut cursor = tree.cursor::<Count>(&());
let mut new_tree = cursor.slice(&Count(splice_start), Bias::Right);
- if rng.r#gen() {
+ if rng.random() {
new_tree.extend(new_items, &());
} else {
new_tree.par_extend(new_items, &());
@@ -1005,7 +1005,7 @@ mod tests {
.filter(|(_, item)| (item & 1) == 0)
.collect::<Vec<_>>();
- let mut item_ix = if rng.r#gen() {
+ let mut item_ix = if rng.random() {
filter_cursor.next();
0
} else {
@@ -1022,12 +1022,12 @@ mod tests {
filter_cursor.next();
item_ix += 1;
- while item_ix > 0 && rng.gen_bool(0.2) {
+ while item_ix > 0 && rng.random_bool(0.2) {
log::info!("prev");
filter_cursor.prev();
item_ix -= 1;
- if item_ix == 0 && rng.gen_bool(0.2) {
+ if item_ix == 0 && rng.random_bool(0.2) {
filter_cursor.prev();
assert_eq!(filter_cursor.item(), None);
assert_eq!(filter_cursor.start().0, 0);
@@ -1039,9 +1039,9 @@ mod tests {
let mut before_start = false;
let mut cursor = tree.cursor::<Count>(&());
- let start_pos = rng.gen_range(0..=reference_items.len());
+ let start_pos = rng.random_range(0..=reference_items.len());
cursor.seek(&Count(start_pos), Bias::Right);
- let mut pos = rng.gen_range(start_pos..=reference_items.len());
+ let mut pos = rng.random_range(start_pos..=reference_items.len());
cursor.seek_forward(&Count(pos), Bias::Right);
for i in 0..10 {
@@ -1084,10 +1084,18 @@ mod tests {
}
for _ in 0..10 {
- let end = rng.gen_range(0..tree.extent::<Count>(&()).0 + 1);
- let start = rng.gen_range(0..end + 1);
- let start_bias = if rng.r#gen() { Bias::Left } else { Bias::Right };
- let end_bias = if rng.r#gen() { Bias::Left } else { Bias::Right };
+ let end = rng.random_range(0..tree.extent::<Count>(&()).0 + 1);
+ let start = rng.random_range(0..end + 1);
+ let start_bias = if rng.random() {
+ Bias::Left
+ } else {
+ Bias::Right
+ };
+ let end_bias = if rng.random() {
+ Bias::Left
+ } else {
+ Bias::Right
+ };
let mut cursor = tree.cursor::<Count>(&());
cursor.seek(&Count(start), start_bias);
@@ -2198,7 +2198,7 @@ mod tests {
};
use collections::HashMap;
use gpui::{Pixels, Point, TestAppContext, bounds, point, size};
- use rand::{Rng, distributions::Alphanumeric, rngs::ThreadRng, thread_rng};
+ use rand::{Rng, distr, rngs::ThreadRng};
#[ignore = "Test is flaky on macOS, and doesn't run on Windows"]
#[gpui::test]
@@ -2249,13 +2249,14 @@ mod tests {
#[test]
fn test_mouse_to_cell_test() {
- let mut rng = thread_rng();
+ let mut rng = rand::rng();
const ITERATIONS: usize = 10;
const PRECISION: usize = 1000;
for _ in 0..ITERATIONS {
- let viewport_cells = rng.gen_range(15..20);
- let cell_size = rng.gen_range(5 * PRECISION..20 * PRECISION) as f32 / PRECISION as f32;
+ let viewport_cells = rng.random_range(15..20);
+ let cell_size =
+ rng.random_range(5 * PRECISION..20 * PRECISION) as f32 / PRECISION as f32;
let size = crate::TerminalBounds {
cell_width: Pixels::from(cell_size),
@@ -2277,8 +2278,8 @@ mod tests {
for col in 0..(viewport_cells - 1) {
let col = col as usize;
- let row_offset = rng.gen_range(0..PRECISION) as f32 / PRECISION as f32;
- let col_offset = rng.gen_range(0..PRECISION) as f32 / PRECISION as f32;
+ let row_offset = rng.random_range(0..PRECISION) as f32 / PRECISION as f32;
+ let col_offset = rng.random_range(0..PRECISION) as f32 / PRECISION as f32;
let mouse_pos = point(
Pixels::from(col as f32 * cell_size + col_offset),
@@ -2298,7 +2299,7 @@ mod tests {
#[test]
fn test_mouse_to_cell_clamp() {
- let mut rng = thread_rng();
+ let mut rng = rand::rng();
let size = crate::TerminalBounds {
cell_width: Pixels::from(10.),
@@ -2336,7 +2337,7 @@ mod tests {
for _ in 0..((size.height() / size.line_height()) as usize) {
let mut row_vec = Vec::new();
for _ in 0..((size.width() / size.cell_width()) as usize) {
- let cell_char = rng.sample(Alphanumeric) as char;
+ let cell_char = rng.sample(distr::Alphanumeric) as char;
row_vec.push(cell_char)
}
cells.push(row_vec)
@@ -106,13 +106,13 @@ mod tests {
let mut rhs = Default::default();
while lhs == rhs {
lhs = Locator(
- (0..rng.gen_range(1..=5))
- .map(|_| rng.gen_range(0..=100))
+ (0..rng.random_range(1..=5))
+ .map(|_| rng.random_range(0..=100))
.collect(),
);
rhs = Locator(
- (0..rng.gen_range(1..=5))
- .map(|_| rng.gen_range(0..=100))
+ (0..rng.random_range(1..=5))
+ .map(|_| rng.random_range(0..=100))
.collect(),
);
}
@@ -65,8 +65,8 @@ impl<T: Clone, R: rand::Rng> Network<T, R> {
for message in &messages {
// Insert one or more duplicates of this message, potentially *before* the previous
// message sent by this peer to simulate out-of-order delivery.
- for _ in 0..self.rng.gen_range(1..4) {
- let insertion_index = self.rng.gen_range(0..inbox.len() + 1);
+ for _ in 0..self.rng.random_range(1..4) {
+ let insertion_index = self.rng.random_range(0..inbox.len() + 1);
inbox.insert(
insertion_index,
Envelope {
@@ -85,7 +85,7 @@ impl<T: Clone, R: rand::Rng> Network<T, R> {
pub fn receive(&mut self, receiver: ReplicaId) -> Vec<T> {
let inbox = self.inboxes.get_mut(&receiver).unwrap();
- let count = self.rng.gen_range(0..inbox.len() + 1);
+ let count = self.rng.random_range(0..inbox.len() + 1);
inbox
.drain(0..count)
.map(|envelope| envelope.message)
@@ -497,8 +497,8 @@ mod tests {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(20);
- let initial_chars = (0..rng.gen_range(0..=100))
- .map(|_| rng.gen_range(b'a'..=b'z') as char)
+ let initial_chars = (0..rng.random_range(0..=100))
+ .map(|_| rng.random_range(b'a'..=b'z') as char)
.collect::<Vec<_>>();
log::info!("initial chars: {:?}", initial_chars);
@@ -517,11 +517,11 @@ mod tests {
break;
}
- let end = rng.gen_range(last_edit_end..=expected_chars.len());
- let start = rng.gen_range(last_edit_end..=end);
+ let end = rng.random_range(last_edit_end..=expected_chars.len());
+ let start = rng.random_range(last_edit_end..=end);
let old_len = end - start;
- let mut new_len = rng.gen_range(0..=3);
+ let mut new_len = rng.random_range(0..=3);
if start == end && new_len == 0 {
new_len += 1;
}
@@ -529,7 +529,7 @@ mod tests {
last_edit_end = start + new_len + 1;
let new_chars = (0..new_len)
- .map(|_| rng.gen_range(b'A'..=b'Z') as char)
+ .map(|_| rng.random_range(b'A'..=b'Z') as char)
.collect::<Vec<_>>();
log::info!(
" editing {:?}: {:?}",
@@ -36,14 +36,14 @@ fn test_random_edits(mut rng: StdRng) {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let reference_string_len = rng.gen_range(0..3);
+ let reference_string_len = rng.random_range(0..3);
let mut reference_string = RandomCharIter::new(&mut rng)
.take(reference_string_len)
.collect::<String>();
let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), reference_string.clone());
LineEnding::normalize(&mut reference_string);
- buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
+ buffer.set_group_interval(Duration::from_millis(rng.random_range(0..=200)));
let mut buffer_versions = Vec::new();
log::info!(
"buffer text {:?}, version: {:?}",
@@ -64,7 +64,7 @@ fn test_random_edits(mut rng: StdRng) {
buffer.version()
);
- if rng.gen_bool(0.25) {
+ if rng.random_bool(0.25) {
buffer.randomly_undo_redo(&mut rng);
reference_string = buffer.text();
log::info!(
@@ -82,7 +82,7 @@ fn test_random_edits(mut rng: StdRng) {
buffer.check_invariants();
- if rng.gen_bool(0.3) {
+ if rng.random_bool(0.3) {
buffer_versions.push((buffer.clone(), buffer.subscribe()));
}
}
@@ -112,8 +112,9 @@ fn test_random_edits(mut rng: StdRng) {
);
for _ in 0..5 {
- let end_ix = old_buffer.clip_offset(rng.gen_range(0..=old_buffer.len()), Bias::Right);
- let start_ix = old_buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
+ let end_ix =
+ old_buffer.clip_offset(rng.random_range(0..=old_buffer.len()), Bias::Right);
+ let start_ix = old_buffer.clip_offset(rng.random_range(0..=end_ix), Bias::Left);
let range = old_buffer.anchor_before(start_ix)..old_buffer.anchor_after(end_ix);
let mut old_text = old_buffer.text_for_range(range.clone()).collect::<String>();
let edits = buffer
@@ -731,7 +732,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
.unwrap_or(10);
- let base_text_len = rng.gen_range(0..10);
+ let base_text_len = rng.random_range(0..10);
let base_text = RandomCharIter::new(&mut rng)
.take(base_text_len)
.collect::<String>();
@@ -741,7 +742,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
for i in 0..peers {
let mut buffer = Buffer::new(i as ReplicaId, BufferId::new(1).unwrap(), base_text.clone());
- buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200));
+ buffer.history.group_interval = Duration::from_millis(rng.random_range(0..=200));
buffers.push(buffer);
replica_ids.push(i as u16);
network.add_peer(i as u16);
@@ -751,10 +752,10 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
let mut mutation_count = operations;
loop {
- let replica_index = rng.gen_range(0..peers);
+ let replica_index = rng.random_range(0..peers);
let replica_id = replica_ids[replica_index];
let buffer = &mut buffers[replica_index];
- match rng.gen_range(0..=100) {
+ match rng.random_range(0..=100) {
0..=50 if mutation_count != 0 => {
let op = buffer.randomly_edit(&mut rng, 5).1;
network.broadcast(buffer.replica_id, vec![op]);
@@ -1818,8 +1818,8 @@ impl Buffer {
}
pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
- let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
- let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
+ let end = self.clip_offset(rng.random_range(start_offset..=self.len()), Bias::Right);
+ let start = self.clip_offset(rng.random_range(start_offset..=end), Bias::Right);
start..end
}
@@ -1841,7 +1841,7 @@ impl Buffer {
let range = self.random_byte_range(new_start, rng);
last_end = Some(range.end);
- let new_text_len = rng.gen_range(0..10);
+ let new_text_len = rng.random_range(0..10);
let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect();
edits.push((range, new_text.into()));
@@ -1877,7 +1877,7 @@ impl Buffer {
use rand::prelude::*;
let mut ops = Vec::new();
- for _ in 0..rng.gen_range(1..=5) {
+ for _ in 0..rng.random_range(1..=5) {
if let Some(entry) = self.history.undo_stack.choose(rng) {
let transaction = entry.transaction.clone();
log::info!(
@@ -815,7 +815,8 @@ pub fn defer<F: FnOnce()>(f: F) -> Deferred<F> {
#[cfg(any(test, feature = "test-support"))]
mod rng {
- use rand::{Rng, seq::SliceRandom};
+ use rand::prelude::*;
+
pub struct RandomCharIter<T: Rng> {
rng: T,
simple_text: bool,
@@ -840,18 +841,18 @@ mod rng {
fn next(&mut self) -> Option<Self::Item> {
if self.simple_text {
- return if self.rng.gen_range(0..100) < 5 {
+ return if self.rng.random_range(0..100) < 5 {
Some('\n')
} else {
- Some(self.rng.gen_range(b'a'..b'z' + 1).into())
+ Some(self.rng.random_range(b'a'..b'z' + 1).into())
};
}
- match self.rng.gen_range(0..100) {
+ match self.rng.random_range(0..100) {
// whitespace
0..=19 => [' ', '\n', '\r', '\t'].choose(&mut self.rng).copied(),
// two-byte greek letters
- 20..=32 => char::from_u32(self.rng.gen_range(('α' as u32)..('ω' as u32 + 1))),
+ 20..=32 => char::from_u32(self.rng.random_range(('α' as u32)..('ω' as u32 + 1))),
// // three-byte characters
33..=45 => ['✋', '✅', '❌', '❎', '⭐']
.choose(&mut self.rng)
@@ -859,7 +860,7 @@ mod rng {
// // four-byte characters
46..=58 => ['🍐', '🏀', '🍗', '🎉'].choose(&mut self.rng).copied(),
// ascii letters
- _ => Some(self.rng.gen_range(b'a'..b'z' + 1).into()),
+ _ => Some(self.rng.random_range(b'a'..b'z' + 1).into()),
}
}
}
@@ -1464,7 +1464,7 @@ async fn test_random_worktree_operations_during_initial_scan(
tree.as_local().unwrap().snapshot().check_invariants(true)
});
- if rng.gen_bool(0.6) {
+ if rng.random_bool(0.6) {
snapshots.push(worktree.read_with(cx, |tree, _| tree.as_local().unwrap().snapshot()));
}
}
@@ -1551,7 +1551,7 @@ async fn test_random_worktree_changes(cx: &mut TestAppContext, mut rng: StdRng)
let mut snapshots = Vec::new();
let mut mutations_len = operations;
while mutations_len > 1 {
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
worktree
.update(cx, |worktree, cx| {
randomly_mutate_worktree(worktree, &mut rng, cx)
@@ -1563,8 +1563,8 @@ async fn test_random_worktree_changes(cx: &mut TestAppContext, mut rng: StdRng)
}
let buffered_event_count = fs.as_fake().buffered_event_count();
- if buffered_event_count > 0 && rng.gen_bool(0.3) {
- let len = rng.gen_range(0..=buffered_event_count);
+ if buffered_event_count > 0 && rng.random_bool(0.3) {
+ let len = rng.random_range(0..=buffered_event_count);
log::info!("flushing {} events", len);
fs.as_fake().flush_events(len);
} else {
@@ -1573,7 +1573,7 @@ async fn test_random_worktree_changes(cx: &mut TestAppContext, mut rng: StdRng)
}
cx.executor().run_until_parked();
- if rng.gen_bool(0.2) {
+ if rng.random_bool(0.2) {
log::info!("storing snapshot {}", snapshots.len());
let snapshot = worktree.read_with(cx, |tree, _| tree.as_local().unwrap().snapshot());
snapshots.push(snapshot);
@@ -1701,7 +1701,7 @@ fn randomly_mutate_worktree(
let snapshot = worktree.snapshot();
let entry = snapshot.entries(false, 0).choose(rng).unwrap();
- match rng.gen_range(0_u32..100) {
+ match rng.random_range(0_u32..100) {
0..=33 if entry.path.as_ref() != Path::new("") => {
log::info!("deleting entry {:?} ({})", entry.path, entry.id.0);
worktree.delete_entry(entry.id, false, cx).unwrap()
@@ -1733,7 +1733,7 @@ fn randomly_mutate_worktree(
_ => {
if entry.is_dir() {
let child_path = entry.path.join(random_filename(rng));
- let is_dir = rng.gen_bool(0.3);
+ let is_dir = rng.random_bool(0.3);
log::info!(
"creating {} at {:?}",
if is_dir { "dir" } else { "file" },
@@ -1776,11 +1776,11 @@ async fn randomly_mutate_fs(
}
}
- if (files.is_empty() && dirs.len() == 1) || rng.gen_bool(insertion_probability) {
+ if (files.is_empty() && dirs.len() == 1) || rng.random_bool(insertion_probability) {
let path = dirs.choose(rng).unwrap();
let new_path = path.join(random_filename(rng));
- if rng.r#gen() {
+ if rng.random() {
log::info!(
"creating dir {:?}",
new_path.strip_prefix(root_path).unwrap()
@@ -1793,7 +1793,7 @@ async fn randomly_mutate_fs(
);
fs.create_file(&new_path, Default::default()).await.unwrap();
}
- } else if rng.gen_bool(0.05) {
+ } else if rng.random_bool(0.05) {
let ignore_dir_path = dirs.choose(rng).unwrap();
let ignore_path = ignore_dir_path.join(*GITIGNORE);
@@ -1808,11 +1808,11 @@ async fn randomly_mutate_fs(
.cloned()
.collect::<Vec<_>>();
let files_to_ignore = {
- let len = rng.gen_range(0..=subfiles.len());
+ let len = rng.random_range(0..=subfiles.len());
subfiles.choose_multiple(rng, len)
};
let dirs_to_ignore = {
- let len = rng.gen_range(0..subdirs.len());
+ let len = rng.random_range(0..subdirs.len());
subdirs.choose_multiple(rng, len)
};
@@ -1848,7 +1848,7 @@ async fn randomly_mutate_fs(
file_path.into_iter().chain(dir_path).choose(rng).unwrap()
};
- let is_rename = rng.r#gen();
+ let is_rename = rng.random();
if is_rename {
let new_path_parent = dirs
.iter()
@@ -1857,7 +1857,7 @@ async fn randomly_mutate_fs(
.unwrap();
let overwrite_existing_dir =
- !old_path.starts_with(new_path_parent) && rng.gen_bool(0.3);
+ !old_path.starts_with(new_path_parent) && rng.random_bool(0.3);
let new_path = if overwrite_existing_dir {
fs.remove_dir(
new_path_parent,
@@ -1919,7 +1919,7 @@ async fn randomly_mutate_fs(
fn random_filename(rng: &mut impl Rng) -> String {
(0..6)
- .map(|_| rng.sample(rand::distributions::Alphanumeric))
+ .map(|_| rng.sample(rand::distr::Alphanumeric))
.map(char::from)
.collect()
}
@@ -149,7 +149,7 @@ mod tests {
let mut rng = rand::thread_rng();
let mut numbers = Vec::new();
for _ in 0..5 {
- numbers.push(rng.gen_range(1..101));
+ numbers.push(rng.random_range(1..101));
}
numbers
}
@@ -208,7 +208,7 @@ mod tests {
<|editable_region_end|>
let mut numbers = Vec::new();
for _ in 0..5 {
- numbers.push(rng.gen_range(1..101));
+ numbers.push(rng.random_range(1..101));
```"#}
);
}