deepdiff-rs 0.5.1__tar.gz → 0.5.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/Cargo.lock +3 -3
  2. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/Cargo.toml +1 -1
  3. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/PKG-INFO +1 -1
  4. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/array.rs +7 -7
  5. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/dispatch.rs +4 -4
  6. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/object.rs +3 -3
  7. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/scalar.rs +1 -1
  8. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/tests.rs +12 -11
  9. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/distance.rs +10 -10
  10. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/fxhash.rs +4 -4
  11. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/hash.rs +4 -4
  12. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/memo.rs +1 -1
  13. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/mod.rs +7 -7
  14. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/pairing.rs +1 -1
  15. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/lcs.rs +1 -1
  16. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/report.rs +1 -1
  17. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/README.md +0 -0
  18. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/Cargo.toml +0 -0
  19. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/examples/stack_frame_cost.rs +0 -0
  20. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/datetime.rs +0 -0
  21. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/datetime_tests.rs +0 -0
  22. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/mod.rs +0 -0
  23. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/options.rs +0 -0
  24. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/diff/set.rs +0 -0
  25. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/error.rs +0 -0
  26. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/ignore_order/tests.rs +0 -0
  27. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/lcs_tests.rs +0 -0
  28. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/lib.rs +0 -0
  29. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/path.rs +0 -0
  30. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/report_tests.rs +0 -0
  31. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/test_support.rs +0 -0
  32. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/value.rs +0 -0
  33. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/src/value_tests.rs +0 -0
  34. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/tests/golden.rs +0 -0
  35. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/tests/ignore_order_memory.rs +0 -0
  36. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/tests/memory_footprint.rs +0 -0
  37. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/tests/proptest_diff.rs +0 -0
  38. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-core/tests/proptest_ignore_order.rs +0 -0
  39. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/Cargo.toml +0 -0
  40. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/benchmarks/bench_bindings.py +0 -0
  41. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/src/convert.rs +0 -0
  42. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/src/deepdiff.rs +0 -0
  43. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/src/errors.rs +0 -0
  44. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/src/fast_path.rs +0 -0
  45. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/src/guard.rs +0 -0
  46. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/src/lib.rs +0 -0
  47. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_bindings_memory.py +0 -0
  48. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_conversions.py +0 -0
  49. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_datetimes.py +0 -0
  50. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_depth_guard.py +0 -0
  51. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_differential_fuzz.py +0 -0
  52. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_golden_parity.py +0 -0
  53. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_sets.py +0 -0
  54. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_signed_zero.py +0 -0
  55. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_smoke.py +0 -0
  56. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_suite_hygiene.py +0 -0
  57. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/crates/onix-py/tests/test_tuples.py +0 -0
  58. {deepdiff_rs-0.5.1 → deepdiff_rs-0.5.3}/pyproject.toml +0 -0
@@ -127,7 +127,7 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
127
127
 
128
128
  [[package]]
129
129
  name = "onix-cli"
130
- version = "0.5.1"
130
+ version = "0.5.3"
131
131
  dependencies = [
132
132
  "onix-core",
133
133
  "serde_json",
@@ -135,7 +135,7 @@ dependencies = [
135
135
 
136
136
  [[package]]
137
137
  name = "onix-core"
138
- version = "0.5.1"
138
+ version = "0.5.3"
139
139
  dependencies = [
140
140
  "proptest",
141
141
  "serde",
@@ -145,7 +145,7 @@ dependencies = [
145
145
 
146
146
  [[package]]
147
147
  name = "onix-py"
148
- version = "0.5.1"
148
+ version = "0.5.3"
149
149
  dependencies = [
150
150
  "onix-core",
151
151
  "pyo3",
@@ -3,7 +3,7 @@ resolver = "3"
3
3
  members = ["crates/onix-core", "crates/onix-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.5.1"
6
+ version = "0.5.3"
7
7
  edition = "2024"
8
8
  license = "MIT"
9
9
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepdiff-rs
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -133,7 +133,7 @@ struct LcsPair<'a> {
133
133
  /// function, and must record *nothing* — which is also what keeps
134
134
  /// [`lcs_or_positional_array_diff`]'s finding-count comparison matching
135
135
  /// `DeepDiff`'s. That branch is also where the pair picks up the
136
- /// UTC-normalized rendering [`datetime_diff`] documents.
136
+ /// UTC-normalized rendering [`datetime_diff`](super::datetime_diff) documents.
137
137
  ///
138
138
  /// Checks [`check_traversal_depth`] at `depth + 1` (this pair's own path
139
139
  /// depth) before recording anything — the same bound
@@ -312,7 +312,7 @@ fn lcs_array_diff(
312
312
  /// own internal dispatch one level deeper with the index appended to the
313
313
  /// path (so a changed, type-changed, or further-nested-container
314
314
  /// difference at that index surfaces with its own deep path, exactly like
315
- /// [`object_diff`]'s shared-key recursion). Once the shorter list is
315
+ /// [`object_diff`](super::object_diff)'s shared-key recursion). Once the shorter list is
316
316
  /// exhausted, the longer list's surplus tail becomes
317
317
  /// `iterable_item_removed` findings (if `a` is longer) or
318
318
  /// `iterable_item_added` findings (if `b` is longer), one per surplus index,
@@ -325,15 +325,15 @@ fn lcs_array_diff(
325
325
  /// against [`lcs_array_diff`]'s result otherwise — see [`array_diff`]'s
326
326
  /// doc.
327
327
  ///
328
- /// Like [`object_diff`], this always recurses into same-index pairs rather
329
- /// than re-checking [`values_equal`] first — see that function's doc for why
330
- /// the single top-level equality check in [`diff_with_max_depth`] is enough.
328
+ /// Like [`object_diff`](super::object_diff), this always recurses into same-index pairs rather
329
+ /// than re-checking [`values_equal`](super::values_equal) first — see that function's doc for why
330
+ /// the single top-level equality check in [`diff_with_max_depth`](super::diff_with_max_depth) is enough.
331
331
  ///
332
332
  /// Every surplus-tail clone is checked with [`check_value_depth`] first,
333
- /// exactly like [`object_diff`]'s added/removed leaf clones: a surplus
333
+ /// exactly like [`object_diff`](super::object_diff)'s added/removed leaf clones: a surplus
334
334
  /// element can itself be an arbitrarily deep value, so the same combined
335
335
  /// path-depth-plus-value-depth budget applies here too (see
336
- /// [`diff_with_max_depth`]'s doc for the full contract).
336
+ /// [`diff_with_max_depth`](super::diff_with_max_depth)'s doc for the full contract).
337
337
  ///
338
338
  /// `path` is the single buffer shared across the whole traversal (see
339
339
  /// [`diff_at`]'s doc): each iteration below runs its work through
@@ -18,7 +18,7 @@ use super::{
18
18
  type_change_report,
19
19
  };
20
20
 
21
- /// The recursive core of [`diff_with_max_depth()`]: identical dispatch, but
21
+ /// The recursive core of [`diff_with_max_depth()`](super::diff_with_max_depth): identical dispatch, but
22
22
  /// carrying the path and depth accumulated so far, so that nested findings
23
23
  /// get their full deep path and the recursion-depth bound can be enforced.
24
24
  ///
@@ -153,7 +153,7 @@ pub(crate) fn deeper_than(value: &Value, limit: usize) -> bool {
153
153
  /// closes: a value could be accepted at up to `max_depth` deep *in addition
154
154
  /// to* however deep the traversal already was, for a combined worst case of
155
155
  /// roughly `2 * max_depth` native frames at the `.clone()` call — see
156
- /// [`diff_with_max_depth`]'s doc for the full contract this restores.
156
+ /// [`diff_with_max_depth`](super::diff_with_max_depth)'s doc for the full contract this restores.
157
157
  pub(crate) fn check_value_depth(
158
158
  path: &[PathSegment],
159
159
  value: &Value,
@@ -217,10 +217,10 @@ pub(crate) fn check_map_depth(
217
217
  /// `max_depth`, `Ok(())` otherwise.
218
218
  ///
219
219
  /// This is [`diff_at`]'s own top check, factored out so
220
- /// [`insert_lcs_pair_finding`] can enforce the *exact same* bound for an
220
+ /// `insert_lcs_pair_finding` can enforce the *exact same* bound for an
221
221
  /// LCS `'replace'`-opcode pairwise comparison as `diff_at` would have
222
222
  /// enforced had the pair been reached by ordinary recursion instead (which
223
- /// is what [`positional_array_diff`]'s equivalent same-index pairs go
223
+ /// is what `positional_array_diff`'s equivalent same-index pairs go
224
224
  /// through) — see [`array_diff`]'s module-level "List diffing" doc section.
225
225
  /// Deliberately distinct from [`check_value_depth`]: that function bounds a
226
226
  /// *value's own nesting* combined with the remaining budget, and is a
@@ -22,8 +22,8 @@ use super::{DiffOptions, check_map_depth, check_value_depth, diff_at, scoped};
22
22
  /// finding (via `array_diff`), all surface with their own deep path.
23
23
  ///
24
24
  /// This always recurses, even for a key whose value is unchanged — it does
25
- /// not re-check [`values_equal`] per key. That single top-level check in
26
- /// [`diff_with_max_depth`] is enough for its documented guarantee (fully
25
+ /// not re-check [`values_equal`](super::values_equal) per key. That single top-level check in
26
+ /// [`diff_with_max_depth`](super::diff_with_max_depth) is enough for its documented guarantee (fully
27
27
  /// equal *whole* inputs never hit the bound); re-running it per key would
28
28
  /// only rescue one specific edge case (an equal subtree nested arbitrarily
29
29
  /// deep under an unrelated shallow change) at the cost of an extra full
@@ -49,7 +49,7 @@ use super::{DiffOptions, check_map_depth, check_value_depth, diff_at, scoped};
49
49
  /// [`Report::merge`] documents why the per-key `report.merge(...)` calls
50
50
  /// below never collide on a *structural* path (each key here is visited
51
51
  /// once, so no traversal ever revisits the same node) — `Report` is keyed
52
- /// by that structural path, not by [`render_path`]'s rendered string, which
52
+ /// by that structural path, not by [`render_path`](crate::path::render_path)'s rendered string, which
53
53
  /// is *not* injective on adversarial keys (see [`crate::path::quote_key`]'s
54
54
  /// doc and `Report`'s module doc for how two structurally distinct paths
55
55
  /// can render identically, and how that collision is handled at
@@ -173,7 +173,7 @@ pub(crate) fn numeric_diff(
173
173
  scalar_diff(path, numbers_equal(old, new), a, b, depth, max_depth)
174
174
  }
175
175
  /// The single definition of numeric equality shared by [`numeric_diff`] and
176
- /// [`values_equal`], so there is exactly one place these rules live.
176
+ /// [`values_equal`](super::values_equal), so there is exactly one place these rules live.
177
177
  ///
178
178
  /// An int and a float are never equal (mirroring `DeepDiff` always reporting
179
179
  /// that pairing as a `type_changes`, never a numeric comparison). Within the
@@ -749,9 +749,9 @@ fn map_deeper_than_recurses_with_incrementing_not_constant_depth() {
749
749
 
750
750
  #[test]
751
751
  fn deeper_than_handles_a_deeply_nested_value_without_crashing() {
752
- // Security-gate regression: `deeper_than` itself must be immune to
753
- // the very depth it is measuring — RECURSION_OVERFLOW_DEPTH (see its
754
- // doc) reuses this file's own established native-recursion-overflow
752
+ // Guards `deeper_than` itself against being vulnerable to the very
753
+ // depth it is measuring — RECURSION_OVERFLOW_DEPTH (see its doc)
754
+ // reuses this file's own established native-recursion-overflow
755
755
  // threshold. Built iteratively (a flat loop, not recursion); the
756
756
  // whole test runs on `run_on_a_large_stack` so it is genuinely
757
757
  // dropped afterwards instead of leaked.
@@ -761,7 +761,7 @@ fn deeper_than_handles_a_deeply_nested_value_without_crashing() {
761
761
  });
762
762
  }
763
763
 
764
- // --- Security-gate regression: a shallow finding carrying a deep VALUE
764
+ // --- A shallow finding carrying a deep VALUE
765
765
  // (dictionary_item_added/removed/type_changes/values_changed) must
766
766
  // error cleanly via check_value_depth, never clone the deep value. ---
767
767
 
@@ -917,9 +917,9 @@ fn scalar_diff_rejects_a_value_whose_own_nesting_exceeds_max_depth_on_the_new_si
917
917
  );
918
918
  }
919
919
 
920
- // --- Compounding-depth regression (security-gate round 3): a value's
921
- // own nesting and the path depth it is found at share ONE combined
922
- // max_depth budget, not one each. ---
920
+ // --- Compounding-depth regression: a value reached through a shallow
921
+ // finding must not be allowed its own full max_depth on top of the path
922
+ // depth already consumed to reach it. ---
923
923
 
924
924
  #[test]
925
925
  fn value_depth_full_budget_at_a_shallow_finding_is_accepted() {
@@ -1114,9 +1114,10 @@ fn sibling_after_a_deeply_nested_key_gets_its_own_shallow_path_not_the_deep_ones
1114
1114
  }
1115
1115
 
1116
1116
  #[test]
1117
- fn security_poc_shallow_finding_with_a_value_past_the_guard_errors_cleanly() {
1118
- // The exact security-gate PoC shape: diff({}, {"x": <deep array>})
1119
- // at DEFAULT_MAX_DEPTH. `check_value_depth`/`deeper_than` reject a
1117
+ fn shallow_finding_with_a_value_past_the_guard_errors_cleanly() {
1118
+ // Exercises the shallow-finding-with-a-too-deep-value shape:
1119
+ // diff({}, {"x": <deep array>}) at DEFAULT_MAX_DEPTH.
1120
+ // `check_value_depth`/`deeper_than` reject a
1120
1121
  // too-deep value by walking at most `max_depth + 1` levels of it
1121
1122
  // before short-circuiting (see `check_value_depth`'s doc), so
1122
1123
  // PAST_DEFAULT_MAX_DEPTH exercises identical behavior to the
@@ -1201,7 +1202,7 @@ fn compounding_depth_regression_max_depth_20_000_traversal_plus_deep_added_value
1201
1202
 
1202
1203
  #[test]
1203
1204
  fn threshold_collapse_rejects_a_deep_side_on_a_constrained_stack_instead_of_crashing() {
1204
- // Security-gate regression for the `threshold_to_diff_deeper` collapse:
1205
+ // Guards the `threshold_to_diff_deeper` collapse:
1205
1206
  // the collapse clones the whole `a`/`b` dict into a finding,
1206
1207
  // so cloning before checking depth would hand an attacker-controlled,
1207
1208
  // `RECURSION_OVERFLOW_DEPTH`-deep value straight to `serde_json::Value`'s
@@ -14,8 +14,8 @@ use super::IgnoreOrderMemo;
14
14
  use super::fxhash::HashSet;
15
15
 
16
16
  /// A total-ordering wrapper for the non-negative, always-finite distances
17
- /// [`rough_distance`] computes, so they can key a [`BTreeMap`] (ascending
18
- /// iteration, for [`compute_pairs`]'s greedy loop) and group candidates by
17
+ /// [`rough_distance`] computes, so they can key a [`BTreeMap`](std::collections::BTreeMap) (ascending
18
+ /// iteration, for [`compute_pairs`](super::pairing::compute_pairs)'s greedy loop) and group candidates by
19
19
  /// **exact** float equality — matching `DeepDiff`'s own behavior of keying
20
20
  /// a plain Python `dict` by the raw `float` distance value.
21
21
  #[derive(Debug, Clone, Copy)]
@@ -155,7 +155,7 @@ fn family_distance(removed: &Value, added: &Value, cutoff: f64) -> Option<f64> {
155
155
  /// `DeepDiff`'s `_get_numbers_distance` (distance.py), including the
156
156
  /// "self-cancellation" quirk (`max_` appears in both the
157
157
  /// formula and the rejection threshold, so same-sign numeric pairs are
158
- /// almost never rejected by [`CUTOFF_DISTANCE_FOR_PAIRS`]) and the
158
+ /// almost never rejected by [`CUTOFF_DISTANCE_FOR_PAIRS`](super::pairing::CUTOFF_DISTANCE_FOR_PAIRS)) and the
159
159
  /// opposite-sign zero-sum edge case (`divisor == 0.0` returns `cutoff`
160
160
  /// itself, i.e. always-reject, rather than dividing by zero).
161
161
  #[allow(
@@ -254,9 +254,9 @@ pub(crate) fn is_length_excluded_key(key: &str) -> bool {
254
254
  }
255
255
 
256
256
  /// A `Report`-free mirror of the recursive diff dispatch, counting exactly
257
- /// what [`Report::distance_leaf_length`] would sum from the equivalent real
257
+ /// what [`Report::distance_leaf_length`](crate::report::Report::distance_leaf_length) would sum from the equivalent real
258
258
  /// diff — used by [`rough_distance`]'s structural fallback so a candidate
259
- /// pair's `diff_length` never pays for a [`Report`]'s `PathSegment`
259
+ /// pair's `diff_length` never pays for a [`Report`](crate::report::Report)'s `PathSegment`
260
260
  /// allocations, `Value` clones, or `BTreeMap` inserts. This matters: a
261
261
  /// naive "just call `diff_at` and count its `Report`" implementation would
262
262
  /// pay exactly the per-candidate object-construction cost that is the
@@ -648,10 +648,10 @@ fn coerce_to_python_str(value: &Value) -> Option<String> {
648
648
  /// dict-vs-dict pair through the real `array_diff`/`object_diff` engine:
649
649
  /// when that trial's pairing accepts a dict-vs-dict pair nested inside it,
650
650
  /// the *actual Report entry it builds* now already reflects the collapse,
651
- /// so [`Report::distance_leaf_length`] never inherits an inflated,
651
+ /// so [`Report::distance_leaf_length`](crate::report::Report::distance_leaf_length) never inherits an inflated,
652
652
  /// uncollapsed leaf count from it (found by differential fuzzing: a
653
653
  /// nested-array-of-dicts candidate pair whose true distance is 0.1364 used
654
- /// to be measured at 0.3182 — crossing [`CUTOFF_DISTANCE_FOR_PAIRS`] and
654
+ /// to be measured at 0.3182 — crossing [`CUTOFF_DISTANCE_FOR_PAIRS`](super::pairing::CUTOFF_DISTANCE_FOR_PAIRS) and
655
655
  /// producing a completely different pairing decision).
656
656
  pub(crate) const THRESHOLD_TO_DIFF_DEEPER: f64 = 0.33;
657
657
 
@@ -783,7 +783,7 @@ pub(crate) fn count_array_diff_leaves(
783
783
  /// `diff_length` comes from [`count_diff_leaves`] — a `Report`-free mirror
784
784
  /// of a trial recursive diff between `removed` and `added` (see that
785
785
  /// function's own doc for why it deliberately does *not* build a
786
- /// [`Report`], unlike `DeepDiff`'s own brand-new nested `DeepDiff` object
786
+ /// [`Report`](crate::report::Report), unlike `DeepDiff`'s own brand-new nested `DeepDiff` object
787
787
  /// built purely to measure this).
788
788
  ///
789
789
  /// `depth` is the depth of the *list* doing the pairing (so `removed`/
@@ -797,14 +797,14 @@ pub(crate) fn count_array_diff_leaves(
797
797
  ///
798
798
  /// **The one place this can still fail is [`count_array_diff_leaves`]'s own
799
799
  /// nested trial diff, and it is believed unreachable today, kept anyway as
800
- /// defense-in-depth.** [`ignore_order_array_diff`]'s own up-front
800
+ /// defense-in-depth.** [`ignore_order_array_diff`](super::ignore_order_array_diff)'s own up-front
801
801
  /// [`crate::diff::check_value_depth`] pass already validates `removed`/`added`
802
802
  /// individually against this exact same reduced budget
803
803
  /// (`max_depth` minus the items' own depth) before pairing ever runs; a
804
804
  /// short inductive argument (every subtree's remaining-budget-at-its-relative-depth
805
805
  /// transfers exactly from a depth-checked root to a trial restarted at
806
806
  /// depth `0` with that same budget as its own `max_depth`) shows the trial
807
- /// can never need more depth than that. Unlike [`insert_lcs_pair_finding`]'s
807
+ /// can never need more depth than that. Unlike `insert_lcs_pair_finding`'s
808
808
  /// equivalent "structurally unreachable" guard (a *static type fact* — a
809
809
  /// JSON scalar's nesting is always `0`, true forever), the invariant here
810
810
  /// is a *cross-function arithmetic* one, spread across several functions —
@@ -1,6 +1,6 @@
1
1
  //! `FxHash`: a small, fast, non-cryptographic hasher used for this module's
2
2
  //! `HashMap`/`HashSet`s ([`HashedList::info`](super::hash::HashedList),
3
- //! [`AddedCandidates::buckets`](super::pairing::AddedCandidates), the
3
+ //! `AddedCandidates::buckets`, the
4
4
  //! pairing/`used` sets in [`compute_pairs`](super::pairing::compute_pairs),
5
5
  //! and the [`IgnoreOrderMemo`](super::memo::IgnoreOrderMemo) cache) —
6
6
  //! chosen for speed at the cost of hash-flooding resistance. Some of these
@@ -12,7 +12,7 @@
12
12
  use std::hash::BuildHasherDefault;
13
13
 
14
14
  /// A [`std::collections::HashMap`] keyed by this module's own types
15
- /// ([`ItemKey`], [`Distance`]), using [`FxHasher`] instead of the standard
15
+ /// ([`ItemKey`](super::hash::ItemKey), [`Distance`](super::distance::Distance)), using [`FxHasher`] instead of the standard
16
16
  /// library's default (`SipHash`) — see that type's doc for the trade-off.
17
17
  pub(crate) type HashMap<K, V> = std::collections::HashMap<K, V, BuildHasherDefault<FxHasher>>;
18
18
  /// The [`HashMap`] equivalent for [`std::collections::HashSet`].
@@ -44,11 +44,11 @@ pub(crate) type HashSet<T> = std::collections::HashSet<T, BuildHasherDefault<FxH
44
44
  /// `FxHash` table there would be a crafted-collision `DoS` on the ordinary
45
45
  /// path; a `BTreeMap` has no hash to attack (`O(log n)` worst case, always). See
46
46
  /// that module's "Set-member digests" section. Every remaining `FxHash` table
47
- /// in this module — `HashedList`, [`AddedCandidates`](super::pairing::AddedCandidates),
47
+ /// in this module — `HashedList`, `AddedCandidates`,
48
48
  /// the pairing/`used` sets, and the distance memo — is reached **only** under
49
49
  /// `ignore_order=true`, the pairing hot path already bounded by the `O(N²)`
50
50
  /// caveat below; those keep `FxHash`, and their float-carrying keys
51
- /// ([`ItemKey`](super::hash::ItemKey), [`ScalarKey`](super::hash::ScalarKey),
51
+ /// ([`ItemKey`](super::hash::ItemKey), [`ScalarKey`](crate::lcs::ScalarKey),
52
52
  /// and the distance memo's [`DistKey`](super::hash::DistKey)) mix their bits
53
53
  /// first ([`mix_float_bits`](crate::lcs::mix_float_bits)) — `DistKey`'s
54
54
  /// encoding routes every float through `number_key`, hence `ItemKey::Float`,
@@ -169,7 +169,7 @@ pub(crate) enum ItemKey {
169
169
  /// value (never collides with `Int`).
170
170
  Bool(bool),
171
171
  /// A JSON value `serde_json` parsed as an integer (no decimal point or
172
- /// exponent) — see [`crate::diff`]'s `python_type_name` for the same
172
+ /// exponent) — see [`mod@crate::diff`]'s `python_type_name` for the same
173
173
  /// int/float split used throughout this crate. Always exact: a
174
174
  /// `serde_json::Number`'s non-float representation is always an `i64`
175
175
  /// or `u64`, both of which fit losslessly in `i128`.
@@ -400,7 +400,7 @@ pub(crate) enum MemberContent {
400
400
  /// `RepId`s are equal.
401
401
  ///
402
402
  /// Shared by [`crate::diff::set_diff`] and
403
- /// [`crate::ignore_order::count_set_diff_leaves`] so the two can never drift
403
+ /// `count_set_diff_leaves` so the two can never drift
404
404
  /// on what "the same member" means.
405
405
  pub(crate) fn set_difference<'a>(
406
406
  a: &'a [Value],
@@ -660,7 +660,7 @@ fn number_key(n: &crate::value::Number) -> ItemKey {
660
660
  ///
661
661
  /// Recurses natively — safe only because
662
662
  /// every caller in this module first proves `value`'s nesting is within the
663
- /// crate's shared depth budget via [`check_value_depth`] (see this module's
663
+ /// crate's shared depth budget via [`check_value_depth`](crate::diff::check_value_depth) (see this module's
664
664
  /// "Depth safety" doc section).
665
665
  pub(crate) fn item_key(value: &Value, memo: &IgnoreOrderMemo) -> ItemKey {
666
666
  keyed(value, memo, false).0
@@ -790,7 +790,7 @@ pub(crate) struct HashedList<'a> {
790
790
  /// — this is `SetOrdered(full_t{1,2}_hashtable.keys())`'s own iteration
791
791
  /// order (a Python dict's insertion order). Each key sits behind an [`Rc`]
792
792
  /// shared with [`Self::info`] and the distance-memo cache keys (see
793
- /// [`super::memo::DistanceKey`]).
793
+ /// `DistanceKey`).
794
794
  pub(crate) distinct_order: Vec<Rc<ItemKey>>,
795
795
  info: HashMap<Rc<ItemKey>, (usize, &'a Value)>,
796
796
  }
@@ -139,7 +139,7 @@ use super::hash::{
139
139
  /// [`super::hash::DistKey`] for why each side is a value's exact structural
140
140
  /// identity (not its order/repetition-insensitive `ItemKey`). Memory per
141
141
  /// entry is a refcount bump: each side's value is interned once per candidate
142
- /// and the `A * R` entries one pairing records just share those [`Rc`]s. The
142
+ /// and the `A * R` entries one pairing records just share those [`Rc`](std::rc::Rc)s. The
143
143
  /// *lookup* cost is not constant, though — every probe hashes both keys (a
144
144
  /// full walk of each value) and, on a bucket match, compares them structurally
145
145
  /// — so per-pair work is proportional to record size (see [`super::hash::DistKey`]).
@@ -33,7 +33,7 @@
33
33
  //!
34
34
  //! For one list level (`a` = `t1`/old, `b` = `t2`/new):
35
35
  //!
36
- //! 1. **Hash every item** ([`item_key`]) into a canonical equivalence key —
36
+ //! 1. **Hash every item** ([`item_key`](hash::item_key)) into a canonical equivalence key —
37
37
  //! see that function's doc for the exact `DeepHash`-matching rules
38
38
  //! (type-tagged numbers, order/count-insensitive nested lists, etc.).
39
39
  //! Reduce each list to its *distinct* keys in first-occurrence order
@@ -70,7 +70,7 @@
70
70
  //! added-hash loop consumed every paired partner) is a plain
71
71
  //! `iterable_item_removed` at its own index.
72
72
  //!
73
- //! After the whole recursive traversal finishes, [`crate::diff`]'s existing
73
+ //! After the whole recursive traversal finishes, [`mod@crate::diff`]'s existing
74
74
  //! whole-tree [`crate::report::Report::merge_mutual_add_removes`] pass
75
75
  //! still runs exactly once, unchanged — it is what turns many of this
76
76
  //! module's own raw adds/removes into `values_changed` on typical small,
@@ -79,21 +79,21 @@
79
79
  //!
80
80
  //! # Depth safety (this crate's own invariant, not `DeepDiff`'s)
81
81
  //!
82
- //! [`item_key`] and [`rough_length`] both recurse **natively** (no explicit
82
+ //! [`item_key`](hash::item_key) and [`rough_length`](distance::rough_length) both recurse **natively** (no explicit
83
83
  //! work-stack) — unlike the rest of this crate's traversal, which is bounded
84
84
  //! via [`crate::diff::check_traversal_depth`]/[`crate::diff::check_value_depth`].
85
85
  //! [`ignore_order_array_diff`] closes this gap up front: every item of both
86
86
  //! `a` and `b` is validated with [`crate::diff::check_value_depth`] (the same
87
87
  //! combined path-depth-plus-value-depth budget documented on
88
88
  //! [`crate::diff::diff_with_max_depth`]) *before* any hashing happens, so by
89
- //! the time [`item_key`]/[`rough_length`] run, their native recursion is
89
+ //! the time [`item_key`](hash::item_key)/[`rough_length`](distance::rough_length) run, their native recursion is
90
90
  //! already proven to be no deeper than a bound this crate already trusts a
91
91
  //! plain `.clone()` to recurse through safely elsewhere. The structural
92
- //! distance fallback's own trial comparison ([`count_diff_leaves`]) is a
92
+ //! distance fallback's own trial comparison ([`count_diff_leaves`](distance::count_diff_leaves)) is a
93
93
  //! `Report`-free mirror of a diff for scalars and dicts (no further native
94
94
  //! recursion risk beyond what's already covered above), except for a
95
95
  //! genuinely nested array, which still runs a real, small trial
96
- //! [`crate::diff::array_diff`] call — see [`rough_distance`]'s doc for its
96
+ //! [`crate::diff::array_diff`] call — see [`rough_distance`](distance::rough_distance)'s doc for its
97
97
  //! own remaining-budget bound.
98
98
  //!
99
99
  //! # Two `DeepDiff` behaviors the pairing depends on
@@ -107,7 +107,7 @@
107
107
  //! `float(0) == 0.0`, `int(True) == 1`, `bool(0) == False`) — the general
108
108
  //! rule real `DeepDiff` applies
109
109
  //! (`model.py::TreeResult._from_tree_type_changes`, `DELTA_VIEW` branch).
110
- //! See [`coerce_for_type_change`] for the exact matrix.
110
+ //! See `coerce_for_type_change` for the exact matrix.
111
111
  //! [`type_change_leaf_length`] and `Report::distance_leaf_length` both
112
112
  //! route through it, so this rule lives in exactly one place.
113
113
  //! 2. **`new_path` composition across nesting levels.** A paired item whose
@@ -83,7 +83,7 @@ impl AddedCandidates {
83
83
  /// Returns added-hash → removed-hash (only that one direction: `DeepDiff`'s
84
84
  /// own `pairs` dict is built symmetrically so `get_other_pair` can look it
85
85
  /// up from either side, but this port only ever looks up from the added
86
- /// side — see [`ignore_order_array_diff`] — so the reverse direction is
86
+ /// side — see [`ignore_order_array_diff`](super::ignore_order_array_diff) — so the reverse direction is
87
87
  /// never constructed).
88
88
  pub(crate) fn compute_pairs(
89
89
  hashes_added: &[Rc<ItemKey>],
@@ -44,7 +44,7 @@ use crate::value::Value;
44
44
 
45
45
  /// A bucket key for grouping list elements that compare equal the way
46
46
  /// Python's `==` (and therefore `difflib`'s matcher, and dict/set hashing)
47
- /// does — **not** the way [`crate::diff`]'s own scalar comparison does.
47
+ /// does — **not** the way [`mod@crate::diff`]'s own scalar comparison does.
48
48
  ///
49
49
  /// This is the "hashable" finding: Python treats `1 == 1.0 == True` (and
50
50
  /// `0 == 0.0 == False`) as equal regardless of type, so `difflib` can match
@@ -588,7 +588,7 @@ impl Report {
588
588
  }
589
589
 
590
590
  /// `DeepDiff`'s `_get_item_length` (distance.py) applied to a whole
591
- /// trial-diff report — [`crate::ignore_order::rough_distance`]'s
591
+ /// trial-diff report — `rough_distance`'s
592
592
  /// structural-fallback numerator (`diff_length`).
593
593
  ///
594
594
  /// Mirrors exactly which sub-value `_get_item_length` would see for
File without changes
File without changes