1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Checked conversions from file-derived 64-bit values to platform integers.
//!
//! HDF5 stores offsets, lengths, sizes, and element counts as 64-bit values
//! (the on-disk "size of offsets" / "size of lengths" are commonly 8 bytes).
//! The reader, however, indexes an in-memory byte buffer with `usize`. On a
//! 64-bit host these conversions are infallible, but on a 32-bit (or WASM32)
//! host `usize` is 32 bits, so a `u64 as usize` cast *silently truncates* any
//! value above 4 GiB, reading from the wrong location or sizing an allocation
//! incorrectly.
//!
//! The helpers here replace those casts with fallible conversions that return
//! [`FormatError`] instead of truncating. They all return [`FormatError`], so
//! they compose with `?` in both the format layer (which returns
//! `Result<_, FormatError>`) and the high-level layer (whose `Error` has a
//! `From<FormatError>` impl).
//!
//! ## When to use these
//!
//! Use [`TryToUsize::to_usize`] / [`slice_range`] / [`u32_from`] for any value
//! that is **file-derived and not structurally bounded**: the result of
//! `read_offset`/`read_length`, a `DataLayout` address or size, a chunk offset
//! or size, a heap or collection size, `num_elements`, an element count, or any
//! arithmetic on those that becomes a slice index or allocation size.
//!
//! A narrowing `as` cast is acceptable only when the source is **provably
//! bounded on every supported target** (e.g. a `u8` "size of offsets" field that
//! is 2/4/8, a version/flags byte, a `u16` message size capped at 64 KiB, a
//! match arm keyed on the on-disk field width it casts to, or a small loop
//! counter). A `u8`/`u16` widening to `usize` never narrows and needs no guard.
//!
//! When you keep such a cast, annotate it at the site with
//! `#[expect(clippy::cast_possible_truncation /* or cast_possible_wrap */,
//! reason = "…")]`, where the `reason` states the bound that makes it safe. The
//! 32-bit CI gate (the `cast-deny-32bit` job) denies both lints, so every
//! narrowing cast must be either converted through the helpers above or
//! explicitly accounted for this way; a leftover `#[expect]` whose cast was
//! later removed fails the gate too, keeping the annotations honest.
use Range;
use Range;
use crateFormatError;
/// Fallible narrowing of a file-derived integer to the platform `usize`.
///
/// On targets where the source type already fits `usize` (e.g. `u64` on a
/// 64-bit host) this collapses to an infallible widening that the optimizer
/// removes; the error arm is cold. On a narrower target it returns
/// [`FormatError::ValueTooLargeForPlatform`] rather than truncating.
/// Fallibly narrow a file-derived `u64` to `u32`.
///
/// Used where the in-memory representation of a (de)compressed chunk size or
/// similar quantity is a `u32` regardless of platform pointer width. Returns
/// [`FormatError::ValueTooLargeForPlatform`] (with `target: "u32"`) instead of
/// truncating.
/// Compute `offset .. offset + len` as a `usize` range, checking both the
/// 64-bit addition and the narrowing of each bound to `usize`.
///
/// Use this anywhere a file-derived `(offset, length)` pair becomes a slice
/// index. It guards two distinct hazards a bare `offset as usize + len as usize`
/// misses: the `u64` addition wrapping ([`FormatError::OffsetOverflow`]) and
/// either operand exceeding `usize` on a 32-bit target
/// ([`FormatError::ValueTooLargeForPlatform`]). The returned `range.end` is the
/// already-checked `usize` end bound, so a subsequent bounds check against the
/// buffer length stays truthful.
/// True when `addr` is the all-`0xFF` "undefined address" sentinel for a file
/// whose size-of-offsets is `offset_size` (2, 4, or 8 bytes). HDF5 stores an
/// unallocated block or chunk pointer this way; readers and the free-space
/// reclaim walk skip such entries. Any other `offset_size` returns `false`.
pub