Property tests: the order of changes never changes the state 37c299cec358
Random edit sessions in two or three diverging clones (inserts, deletes, replacements, new and removed files, so most cases conflict) are rebuilt in shuffled orders through State::add_unchecked and in random dependency orders through State::add. Every order must validate and give identical checkpoint bytes, heads and materialized trees; the checkpoint must restore the same state; and pushing the clones in a random order must give a fresh clone that state too. 32 cases per run, via proptest.
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-09-27 23:08 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
37c299cec358d02a66552773afc4503b5c3b271ce09deea42475aed98cfea061- Depends on
- 135212de5370 2b5ee371060e 750251b21a96 e993a086c13f ff0af1ee299d
- Depended on by
- 2cd40ea1c04c f874dc8659c2 8d80356371c5 e7ddd552b619 1d360c91a289
- In bookmarks
- agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
- In tags
- v0.1.0 v0.10.0 v0.11.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
- Edits
- 22 atoms, 3 tree operations, 4 files
Browse the tree at this change
added crates/oxy-core/tests/commutativity.proptest-regressions +7 −0
| 1 | + | # Seeds for failure cases proptest has generated in the past. It is |
|
| 2 | + | # automatically read and these particular cases re-run before any |
|
| 3 | + | # novel cases are generated. |
|
| 4 | + | # |
|
| 5 | + | # It is recommended to check this file in to source control so that |
|
| 6 | + | # everyone who runs the test benefits from these saved cases. |
|
| 7 | + | cc 150dc6c3551a31ba699711e0bebca2b54b29cbf003a0e8e9035d978f4bcfd65d # shrinks to sessions = [[[Insert { file: 0, at: 82, word: 2 }]], [[Insert { file: 3, at: 15216962264731610119, word: 0 }, Replace { file: 1, at: 1617507299102404918, word: 0 }, Delete { file: 1, at: 6875205767748926991 }, Delete { file: 0, at: 4285533219516317091 }], [Delete { file: 0, at: 14950834157168413373 }, Delete { file: 3, at: 7384109036823047037 }, Delete { file: 0, at: 15334878224541300421 }, Insert { file: 3, at: 6722035807729590280, word: 2 }], [Insert { file: 3, at: 5966679767442278895, word: 2 }, Replace { file: 1, at: 17587470115659482894, word: 0 }]]], seed = 2287439951785091165 |
added crates/oxy-core/tests/commutativity.rs +252 −0
| 1 | + | //! Property tests for spec §7.3: a state is a function of its set of |
|
| 2 | + | //! changes, never of the order they arrived in. |
|
| 3 | + | //! |
|
| 4 | + | //! Each case seeds a repository with a few files, lets two or three clones |
|
| 5 | + | //! diverge through random edit sessions (inserts, deletes, replacements, |
|
| 6 | + | //! new and removed files, so conflicts happen too), then rebuilds the |
|
| 7 | + | //! union of every clone's changes in many orders: arbitrary orders through |
|
| 8 | + | //! `State::add_unchecked` and random dependency-respecting orders through |
|
| 9 | + | //! `State::add`. Every order must validate and give byte-identical |
|
| 10 | + | //! checkpoints and identical materialized trees. Finally the clones push |
|
| 11 | + | //! to one origin in a random order and a fresh clone must see that state, |
|
| 12 | + | //! and a checkpoint of the state must restore it exactly. |
|
| 13 | + | ||
| 14 | + | use oxy_core::objects::Change; |
|
| 15 | + | use oxy_core::repo::Repo; |
|
| 16 | + | use oxy_core::state::State; |
|
| 17 | + | use proptest::prelude::*; |
|
| 18 | + | use rand::rngs::StdRng; |
|
| 19 | + | use rand::seq::SliceRandom; |
|
| 20 | + | use rand::{Rng, SeedableRng}; |
|
| 21 | + | use std::collections::{BTreeMap, BTreeSet}; |
|
| 22 | + | use std::path::Path; |
|
| 23 | + | ||
| 24 | + | /// Point `$OXY_HOME` at a throwaway directory once per test process. |
|
| 25 | + | fn hermetic() { |
|
| 26 | + | static ONCE: std::sync::Once = std::sync::Once::new(); |
|
| 27 | + | static DIR: std::sync::OnceLock<tempfile::TempDir> = std::sync::OnceLock::new(); |
|
| 28 | + | ONCE.call_once(|| { |
|
| 29 | + | let d = tempfile::tempdir().unwrap(); |
|
| 30 | + | std::env::set_var("OXY_HOME", d.path()); |
|
| 31 | + | DIR.set(d).ok(); |
|
| 32 | + | }); |
|
| 33 | + | } |
|
| 34 | + | ||
| 35 | + | /// Files the edits address; the first `SEEDED` exist in the base state. |
|
| 36 | + | const FILES: [&str; 4] = ["a.txt", "b.txt", "dir/c.txt", "d.txt"]; |
|
| 37 | + | const SEEDED: usize = 3; |
|
| 38 | + | ||
| 39 | + | /// A few short lines, so identical lines are common and the diff has |
|
| 40 | + | /// to choose between equally good alignments. |
|
| 41 | + | const WORDS: [&str; 5] = ["alpha\n", "beta\n", "gamma\n", "delta\n", "alpha\n"]; |
|
| 42 | + | ||
| 43 | + | #[derive(Clone, Debug)] |
|
| 44 | + | enum Edit { |
|
| 45 | + | Insert { file: usize, at: usize, word: usize }, |
|
| 46 | + | Delete { file: usize, at: usize }, |
|
| 47 | + | Replace { file: usize, at: usize, word: usize }, |
|
| 48 | + | Remove { file: usize }, |
|
| 49 | + | } |
|
| 50 | + | ||
| 51 | + | fn edit() -> impl Strategy<Value = Edit> { |
|
| 52 | + | let file = 0..FILES.len(); |
|
| 53 | + | prop_oneof![ |
|
| 54 | + | 4 => (file.clone(), any::<usize>(), 0..WORDS.len()).prop_map(|(file, at, word)| Edit::Insert { file, at, word }), |
|
| 55 | + | 3 => (file.clone(), any::<usize>()).prop_map(|(file, at)| Edit::Delete { file, at }), |
|
| 56 | + | 3 => (file.clone(), any::<usize>(), 0..WORDS.len()).prop_map(|(file, at, word)| Edit::Replace { file, at, word }), |
|
| 57 | + | 1 => file.prop_map(|file| Edit::Remove { file }), |
|
| 58 | + | ] |
|
| 59 | + | } |
|
| 60 | + | ||
| 61 | + | /// One clone's session: a few commits of a few edits each. |
|
| 62 | + | fn session() -> impl Strategy<Value = Vec<Vec<Edit>>> { |
|
| 63 | + | prop::collection::vec(prop::collection::vec(edit(), 1..5), 1..4) |
|
| 64 | + | } |
|
| 65 | + | ||
| 66 | + | fn lines(root: &Path, rel: &str) -> Option<Vec<String>> { |
|
| 67 | + | let text = std::fs::read_to_string(root.join(rel)).ok()?; |
|
| 68 | + | Some(text.split_inclusive('\n').map(String::from).collect()) |
|
| 69 | + | } |
|
| 70 | + | ||
| 71 | + | fn apply(root: &Path, e: &Edit) { |
|
| 72 | + | let file = match e { |
|
| 73 | + | Edit::Remove { file } => { |
|
| 74 | + | let _ = std::fs::remove_file(root.join(FILES[*file])); |
|
| 75 | + | return; |
|
| 76 | + | } |
|
| 77 | + | Edit::Insert { file, .. } | Edit::Delete { file, .. } | Edit::Replace { file, .. } => *file, |
|
| 78 | + | }; |
|
| 79 | + | let mut l = lines(root, FILES[file]).unwrap_or_default(); |
|
| 80 | + | match *e { |
|
| 81 | + | Edit::Insert { at, word, .. } => l.insert(at % (l.len() + 1), WORDS[word].to_string()), |
|
| 82 | + | Edit::Delete { at, .. } if !l.is_empty() => { |
|
| 83 | + | let i = at % l.len(); |
|
| 84 | + | l.remove(i); |
|
| 85 | + | } |
|
| 86 | + | Edit::Replace { at, word, .. } if !l.is_empty() => { |
|
| 87 | + | let i = at % l.len(); |
|
| 88 | + | l[i] = WORDS[word].to_string(); |
|
| 89 | + | } |
|
| 90 | + | _ => {} |
|
| 91 | + | } |
|
| 92 | + | let path = root.join(FILES[file]); |
|
| 93 | + | std::fs::create_dir_all(path.parent().unwrap()).unwrap(); |
|
| 94 | + | std::fs::write(path, l.concat()).unwrap(); |
|
| 95 | + | } |
|
| 96 | + | ||
| 97 | + | /// Every change reachable from `repo`'s bookmark heads. |
|
| 98 | + | fn changes_of(repo: &Repo, into: &mut BTreeMap<oxy_core::hash::ChangeHash, Change>) { |
|
| 99 | + | let mut stack = repo.bookmark_heads().unwrap(); |
|
| 100 | + | while let Some(h) = stack.pop() { |
|
| 101 | + | if into.contains_key(&h) { |
|
| 102 | + | continue; |
|
| 103 | + | } |
|
| 104 | + | let c = repo.store().get_change(&h).unwrap(); |
|
| 105 | + | stack.extend(c.deps.iter().copied()); |
|
| 106 | + | into.insert(h, c); |
|
| 107 | + | } |
|
| 108 | + | } |
|
| 109 | + | ||
| 110 | + | /// What must not depend on order: the checkpoint bytes, the heads and |
|
| 111 | + | /// the materialized tree. |
|
| 112 | + | fn fingerprint( |
|
| 113 | + | state: &State, |
|
| 114 | + | ) -> ( |
|
| 115 | + | Vec<u8>, |
|
| 116 | + | BTreeSet<oxy_core::hash::ChangeHash>, |
|
| 117 | + | oxy_core::tree::TreeView, |
|
| 118 | + | BTreeMap<String, oxy_core::state::FileState>, |
|
| 119 | + | ) { |
|
| 120 | + | let snap = state.materialize(); |
|
| 121 | + | ( |
|
| 122 | + | state.checkpoint_payload(), |
|
| 123 | + | state.heads().into_iter().collect(), |
|
| 124 | + | snap.tree, |
|
| 125 | + | snap.files, |
|
| 126 | + | ) |
|
| 127 | + | } |
|
| 128 | + | ||
| 129 | + | fn run_case(sessions: Vec<Vec<Vec<Edit>>>, seed: u64) -> Result<(), TestCaseError> { |
|
| 130 | + | hermetic(); |
|
| 131 | + | let dir = tempfile::tempdir().unwrap(); |
|
| 132 | + | let root = dir.path(); |
|
| 133 | + | let origin_path = root.join("origin"); |
|
| 134 | + | Repo::init(&origin_path).unwrap(); |
|
| 135 | + | let url = origin_path.to_string_lossy().to_string(); |
|
| 136 | + | ||
| 137 | + | // The shared base. |
|
| 138 | + | let seed_repo = Repo::clone(&url, &root.join("seed")).unwrap(); |
|
| 139 | + | for (i, f) in FILES.iter().take(SEEDED).enumerate() { |
|
| 140 | + | let p = root.join("seed").join(f); |
|
| 141 | + | std::fs::create_dir_all(p.parent().unwrap()).unwrap(); |
|
| 142 | + | std::fs::write(p, WORDS[..=i + 1].concat()).unwrap(); |
|
| 143 | + | } |
|
| 144 | + | seed_repo.commit("base", &[]).unwrap(); |
|
| 145 | + | assert!(seed_repo |
|
| 146 | + | .push("origin", false) |
|
| 147 | + | .unwrap() |
|
| 148 | + | .iter() |
|
| 149 | + | .all(|r| r.ok)); |
|
| 150 | + | ||
| 151 | + | // Diverge. |
|
| 152 | + | let mut clones = Vec::new(); |
|
| 153 | + | for (n, session) in sessions.iter().enumerate() { |
|
| 154 | + | let wc = root.join(format!("clone{n}")); |
|
| 155 | + | let repo = Repo::clone(&url, &wc).unwrap(); |
|
| 156 | + | for (k, commit) in session.iter().enumerate() { |
|
| 157 | + | for e in commit { |
|
| 158 | + | apply(&wc, e); |
|
| 159 | + | } |
|
| 160 | + | let s = repo.snapshot("oxy status").unwrap(); |
|
| 161 | + | if s.statuses.is_empty() { |
|
| 162 | + | continue; |
|
| 163 | + | } |
|
| 164 | + | repo.commit(&format!("clone {n} commit {k}"), &[]).unwrap(); |
|
| 165 | + | } |
|
| 166 | + | clones.push(repo); |
|
| 167 | + | } |
|
| 168 | + | ||
| 169 | + | let mut all = BTreeMap::new(); |
|
| 170 | + | for c in &clones { |
|
| 171 | + | changes_of(c, &mut all); |
|
| 172 | + | } |
|
| 173 | + | let changes: Vec<Change> = all.values().cloned().collect(); |
|
| 174 | + | ||
| 175 | + | // The reference: every change, sorted by hash. |
|
| 176 | + | let mut reference = State::new(); |
|
| 177 | + | for c in &changes { |
|
| 178 | + | reference.add_unchecked(c.clone()); |
|
| 179 | + | } |
|
| 180 | + | prop_assert!(reference.validate().is_ok()); |
|
| 181 | + | let want = fingerprint(&reference); |
|
| 182 | + | // A checkpoint restores the same state. |
|
| 183 | + | let restored = State::from_checkpoint_payload(&want.0).unwrap(); |
|
| 184 | + | prop_assert!( |
|
| 185 | + | fingerprint(&restored) == want, |
|
| 186 | + | "checkpoint round trip changed the state" |
|
| 187 | + | ); |
|
| 188 | + | ||
| 189 | + | let mut rng = StdRng::seed_from_u64(seed); |
|
| 190 | + | for _ in 0..4 { |
|
| 191 | + | // Any order at all. |
|
| 192 | + | let mut order = changes.clone(); |
|
| 193 | + | order.shuffle(&mut rng); |
|
| 194 | + | let mut st = State::new(); |
|
| 195 | + | for c in order { |
|
| 196 | + | st.add_unchecked(c); |
|
| 197 | + | } |
|
| 198 | + | prop_assert!(st.validate().is_ok()); |
|
| 199 | + | prop_assert!( |
|
| 200 | + | fingerprint(&st) == want, |
|
| 201 | + | "unchecked order changed the state" |
|
| 202 | + | ); |
|
| 203 | + | ||
| 204 | + | // A random order that respects dependencies, the order a fetch sees. |
|
| 205 | + | let mut pending: Vec<&Change> = changes.iter().collect(); |
|
| 206 | + | let mut st = State::new(); |
|
| 207 | + | while !pending.is_empty() { |
|
| 208 | + | let ready: Vec<usize> = (0..pending.len()) |
|
| 209 | + | .filter(|&i| pending[i].deps.iter().all(|d| st.contains(d))) |
|
| 210 | + | .collect(); |
|
| 211 | + | prop_assert!(!ready.is_empty(), "dependency cycle"); |
|
| 212 | + | let pick = ready[rng.gen_range(0..ready.len())]; |
|
| 213 | + | st.add(pending.swap_remove(pick).clone()).unwrap(); |
|
| 214 | + | } |
|
| 215 | + | prop_assert!( |
|
| 216 | + | fingerprint(&st) == want, |
|
| 217 | + | "dependency order changed the state" |
|
| 218 | + | ); |
|
| 219 | + | } |
|
| 220 | + | ||
| 221 | + | // Through the protocol: push in a random order, then a fresh clone. |
|
| 222 | + | let mut order: Vec<usize> = (0..clones.len()).collect(); |
|
| 223 | + | order.shuffle(&mut rng); |
|
| 224 | + | for i in order { |
|
| 225 | + | let c = &clones[i]; |
|
| 226 | + | // A clone behind the origin is told to pull first, as a user is. |
|
| 227 | + | if !c |
|
| 228 | + | .push("origin", false) |
|
| 229 | + | .is_ok_and(|r| r.iter().all(|r| r.ok)) |
|
| 230 | + | { |
|
| 231 | + | c.pull("origin").unwrap(); |
|
| 232 | + | prop_assert!( |
|
| 233 | + | c.push("origin", false).unwrap().iter().all(|r| r.ok), |
|
| 234 | + | "push after pull" |
|
| 235 | + | ); |
|
| 236 | + | } |
|
| 237 | + | } |
|
| 238 | + | let fresh = Repo::clone(&url, &root.join("fresh")).unwrap(); |
|
| 239 | + | let heads = fresh.bookmark_heads().unwrap(); |
|
| 240 | + | let pushed = fresh.load_state_full(&heads).unwrap(); |
|
| 241 | + | prop_assert!(fingerprint(&pushed) == want, "the pushed state differs"); |
|
| 242 | + | Ok(()) |
|
| 243 | + | } |
|
| 244 | + | ||
| 245 | + | proptest! { |
|
| 246 | + | #![proptest_config(ProptestConfig { cases: 32, ..ProptestConfig::default() })] |
|
| 247 | + | ||
| 248 | + | #[test] |
|
| 249 | + | fn order_of_changes_is_irrelevant(sessions in prop::collection::vec(session(), 2..4), seed in any::<u64>()) { |
|
| 250 | + | run_case(sessions, seed)?; |
|
| 251 | + | } |
|
| 252 | + | } |
modified Cargo.lock +143 −4
| … | 231 unchanged lines |
||
| 232 | 232 | checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" |
|
| 233 | 233 | ||
| 234 | 234 | [[package]] |
|
| 235 | + | name = "bit-set" |
|
| 236 | + | version = "0.8.0" |
|
| 237 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 238 | + | checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" |
|
| 239 | + | dependencies = [ |
|
| 240 | + | "bit-vec 0.8.0", |
|
| 241 | + | ] |
|
| 242 | + | ||
| 243 | + | [[package]] |
|
| 235 | 244 | name = "bit-vec" |
|
| 245 | + | version = "0.8.0" |
|
| 246 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 247 | + | checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" |
|
| 248 | + | ||
| 249 | + | [[package]] |
|
| 250 | + | name = "bit-vec" |
|
| 236 | 251 | version = "0.9.1" |
|
| 237 | 252 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 238 | 253 | checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" |
|
| … | 449 unchanged lines |
||
| 688 | 703 | ||
| 689 | 704 | [[package]] |
|
| 690 | 705 | name = "getrandom" |
|
| 706 | + | version = "0.3.4" |
|
| 707 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 708 | + | checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" |
|
| 709 | + | dependencies = [ |
|
| 710 | + | "cfg-if", |
|
| 711 | + | "libc", |
|
| 712 | + | "r-efi 5.3.0", |
|
| 713 | + | "wasip2", |
|
| 714 | + | ] |
|
| 715 | + | ||
| 716 | + | [[package]] |
|
| 717 | + | name = "getrandom" |
|
| 691 | 718 | version = "0.4.3" |
|
| 692 | 719 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 693 | 720 | checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" |
|
| 694 | 721 | dependencies = [ |
|
| 695 | 722 | "cfg-if", |
|
| 696 | 723 | "libc", |
|
| 697 | - | "r-efi", |
|
| 724 | + | "r-efi 6.0.0", |
|
| 698 | 725 | "rand_core 0.10.1", |
|
| 699 | 726 | ] |
|
| 700 | 727 | ||
| … | 520 unchanged lines |
||
| 1221 | 1248 | "hex", |
|
| 1222 | 1249 | "ignore", |
|
| 1223 | 1250 | "ml-dsa", |
|
| 1224 | - | "rand", |
|
| 1251 | + | "proptest", |
|
| 1252 | + | "rand 0.8.8", |
|
| 1225 | 1253 | "rustls", |
|
| 1226 | 1254 | "rustls-pemfile", |
|
| 1227 | 1255 | "similar", |
|
| … | 95 unchanged lines |
||
| 1323 | 1351 | ] |
|
| 1324 | 1352 | ||
| 1325 | 1353 | [[package]] |
|
| 1354 | + | name = "proptest" |
|
| 1355 | + | version = "1.11.0" |
|
| 1356 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1357 | + | checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" |
|
| 1358 | + | dependencies = [ |
|
| 1359 | + | "bit-set", |
|
| 1360 | + | "bit-vec 0.8.0", |
|
| 1361 | + | "bitflags", |
|
| 1362 | + | "num-traits", |
|
| 1363 | + | "rand 0.9.5", |
|
| 1364 | + | "rand_chacha 0.9.0", |
|
| 1365 | + | "rand_xorshift", |
|
| 1366 | + | "regex-syntax", |
|
| 1367 | + | "rusty-fork", |
|
| 1368 | + | "tempfile", |
|
| 1369 | + | "unarray", |
|
| 1370 | + | ] |
|
| 1371 | + | ||
| 1372 | + | [[package]] |
|
| 1373 | + | name = "quick-error" |
|
| 1374 | + | version = "1.2.3" |
|
| 1375 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1376 | + | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" |
|
| 1377 | + | ||
| 1378 | + | [[package]] |
|
| 1326 | 1379 | name = "quote" |
|
| 1327 | 1380 | version = "1.0.47" |
|
| 1328 | 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 4 unchanged lines |
||
| 1333 | 1386 | ||
| 1334 | 1387 | [[package]] |
|
| 1335 | 1388 | name = "r-efi" |
|
| 1389 | + | version = "5.3.0" |
|
| 1390 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1391 | + | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" |
|
| 1392 | + | ||
| 1393 | + | [[package]] |
|
| 1394 | + | name = "r-efi" |
|
| 1336 | 1395 | version = "6.0.0" |
|
| 1337 | 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1338 | 1397 | checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" |
|
| … | 5 unchanged lines |
||
| 1344 | 1403 | checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" |
|
| 1345 | 1404 | dependencies = [ |
|
| 1346 | 1405 | "libc", |
|
| 1347 | - | "rand_chacha", |
|
| 1406 | + | "rand_chacha 0.3.1", |
|
| 1348 | 1407 | "rand_core 0.6.4", |
|
| 1349 | 1408 | ] |
|
| 1350 | 1409 | ||
| 1351 | 1410 | [[package]] |
|
| 1411 | + | name = "rand" |
|
| 1412 | + | version = "0.9.5" |
|
| 1413 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1414 | + | checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" |
|
| 1415 | + | dependencies = [ |
|
| 1416 | + | "rand_chacha 0.9.0", |
|
| 1417 | + | "rand_core 0.9.5", |
|
| 1418 | + | ] |
|
| 1419 | + | ||
| 1420 | + | [[package]] |
|
| 1352 | 1421 | name = "rand_chacha" |
|
| 1353 | 1422 | version = "0.3.1" |
|
| 1354 | 1423 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 4 unchanged lines |
||
| 1359 | 1428 | ] |
|
| 1360 | 1429 | ||
| 1361 | 1430 | [[package]] |
|
| 1431 | + | name = "rand_chacha" |
|
| 1432 | + | version = "0.9.0" |
|
| 1433 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1434 | + | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" |
|
| 1435 | + | dependencies = [ |
|
| 1436 | + | "ppv-lite86", |
|
| 1437 | + | "rand_core 0.9.5", |
|
| 1438 | + | ] |
|
| 1439 | + | ||
| 1440 | + | [[package]] |
|
| 1362 | 1441 | name = "rand_core" |
|
| 1363 | 1442 | version = "0.6.4" |
|
| 1364 | 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 4 unchanged lines |
||
| 1369 | 1448 | ||
| 1370 | 1449 | [[package]] |
|
| 1371 | 1450 | name = "rand_core" |
|
| 1451 | + | version = "0.9.5" |
|
| 1452 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1453 | + | checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" |
|
| 1454 | + | dependencies = [ |
|
| 1455 | + | "getrandom 0.3.4", |
|
| 1456 | + | ] |
|
| 1457 | + | ||
| 1458 | + | [[package]] |
|
| 1459 | + | name = "rand_core" |
|
| 1372 | 1460 | version = "0.10.1" |
|
| 1373 | 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1374 | 1462 | checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" |
|
| 1375 | 1463 | ||
| 1376 | 1464 | [[package]] |
|
| 1465 | + | name = "rand_xorshift" |
|
| 1466 | + | version = "0.4.0" |
|
| 1467 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1468 | + | checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" |
|
| 1469 | + | dependencies = [ |
|
| 1470 | + | "rand_core 0.9.5", |
|
| 1471 | + | ] |
|
| 1472 | + | ||
| 1473 | + | [[package]] |
|
| 1377 | 1474 | name = "rcgen" |
|
| 1378 | 1475 | version = "0.14.10" |
|
| 1379 | 1476 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 120 unchanged lines |
||
| 1500 | 1597 | checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" |
|
| 1501 | 1598 | ||
| 1502 | 1599 | [[package]] |
|
| 1600 | + | name = "rusty-fork" |
|
| 1601 | + | version = "0.3.1" |
|
| 1602 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 1603 | + | checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" |
|
| 1604 | + | dependencies = [ |
|
| 1605 | + | "fnv", |
|
| 1606 | + | "quick-error", |
|
| 1607 | + | "tempfile", |
|
| 1608 | + | "wait-timeout", |
|
| 1609 | + | ] |
|
| 1610 | + | ||
| 1611 | + | [[package]] |
|
| 1503 | 1612 | name = "ryu" |
|
| 1504 | 1613 | version = "1.0.23" |
|
| 1505 | 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 434 unchanged lines |
||
| 1940 | 2049 | checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" |
|
| 1941 | 2050 | ||
| 1942 | 2051 | [[package]] |
|
| 2052 | + | name = "unarray" |
|
| 2053 | + | version = "0.1.4" |
|
| 2054 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 2055 | + | checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" |
|
| 2056 | + | ||
| 2057 | + | [[package]] |
|
| 1943 | 2058 | name = "unicode-ident" |
|
| 1944 | 2059 | version = "1.0.26" |
|
| 1945 | 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 52 unchanged lines |
||
| 1998 | 2113 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" |
|
| 1999 | 2114 | ||
| 2000 | 2115 | [[package]] |
|
| 2116 | + | name = "wait-timeout" |
|
| 2117 | + | version = "0.2.1" |
|
| 2118 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 2119 | + | checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" |
|
| 2120 | + | dependencies = [ |
|
| 2121 | + | "libc", |
|
| 2122 | + | ] |
|
| 2123 | + | ||
| 2124 | + | [[package]] |
|
| 2001 | 2125 | name = "walkdir" |
|
| 2002 | 2126 | version = "2.5.0" |
|
| 2003 | 2127 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 10 unchanged lines |
||
| 2014 | 2138 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" |
|
| 2015 | 2139 | ||
| 2016 | 2140 | [[package]] |
|
| 2141 | + | name = "wasip2" |
|
| 2142 | + | version = "1.0.4+wasi-0.2.12" |
|
| 2143 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 2144 | + | checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" |
|
| 2145 | + | dependencies = [ |
|
| 2146 | + | "wit-bindgen", |
|
| 2147 | + | ] |
|
| 2148 | + | ||
| 2149 | + | [[package]] |
|
| 2017 | 2150 | name = "wasm-bindgen" |
|
| 2018 | 2151 | version = "0.2.129" |
|
| 2019 | 2152 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 173 unchanged lines |
||
| 2193 | 2326 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" |
|
| 2194 | 2327 | ||
| 2195 | 2328 | [[package]] |
|
| 2329 | + | name = "wit-bindgen" |
|
| 2330 | + | version = "0.57.1" |
|
| 2331 | + | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 2332 | + | checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" |
|
| 2333 | + | ||
| 2334 | + | [[package]] |
|
| 2196 | 2335 | name = "writeable" |
|
| 2197 | 2336 | version = "0.6.4" |
|
| 2198 | 2337 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 23 unchanged lines |
||
| 2222 | 2361 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| 2223 | 2362 | checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" |
|
| 2224 | 2363 | dependencies = [ |
|
| 2225 | - | "bit-vec", |
|
| 2364 | + | "bit-vec 0.9.1", |
|
| 2226 | 2365 | "time", |
|
| 2227 | 2366 | ] |
|
| 2228 | 2367 | ||
| … | 142 unchanged lines |
modified crates/oxy-core/Cargo.toml +1 −0
| … | 20 unchanged lines |
||
| 21 | 21 | zstd = "0.13" |
|
| 22 | 22 | ||
| 23 | 23 | [dev-dependencies] |
|
| 24 | + | proptest = "1" |
|
| 24 | 25 | tempfile = "3" |