• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / gpt-disk-rs / 14182859342

31 Mar 2025 10:40PM CUT coverage: 94.803%. Remained the same
14182859342

Pull #277

github

web-flow
Merge 9a5384971 into 32b4a7e87
Pull Request #277: uguid: Unconditionally use the Error trait

1441 of 1520 relevant lines covered (94.8%)

13.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.76
/gpt_disk_types/src/block.rs
1
// Copyright 2022 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6
// option. This file may not be copied, modified, or distributed
7
// except according to those terms.
8

9
use crate::U64Le;
10
use core::fmt::{self, Display, Formatter};
11
use core::num::{NonZeroU32, TryFromIntError};
12
use core::ops::RangeInclusive;
13

14
#[cfg(feature = "bytemuck")]
15
use bytemuck::{Pod, Zeroable};
16

17
/// Logical block address.
18
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
19
#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
×
20
#[repr(transparent)]
21
pub struct Lba(pub u64);
22

23
impl Lba {
24
    /// Convert to a plain [`u64`].
25
    #[must_use]
26
    pub fn to_u64(self) -> u64 {
25✔
27
        self.0
25✔
28
    }
25✔
29
}
30

31
impl PartialEq<u64> for Lba {
32
    fn eq(&self, other: &u64) -> bool {
2✔
33
        self.0 == *other
2✔
34
    }
2✔
35
}
36

37
impl Display for Lba {
38
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
7✔
39
        self.0.fmt(f)
7✔
40
    }
7✔
41
}
42

43
impl TryFrom<Lba> for usize {
44
    type Error = TryFromIntError;
45

46
    fn try_from(lba: Lba) -> Result<Self, Self::Error> {
35✔
47
        lba.0.try_into()
35✔
48
    }
35✔
49
}
50

51
impl From<LbaLe> for Lba {
52
    fn from(lba: LbaLe) -> Self {
12✔
53
        Self(lba.to_u64())
12✔
54
    }
12✔
55
}
56

57
/// Logical block address stored as a [`U64Le`].
58
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
59
#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
×
60
#[repr(transparent)]
61
pub struct LbaLe(pub U64Le);
62

63
impl LbaLe {
64
    /// Create a logical block address from a [`u64`].
65
    #[must_use]
66
    pub const fn from_u64(v: u64) -> Self {
96✔
67
        Self(U64Le::from_u64(v))
96✔
68
    }
96✔
69

70
    /// Get the logical block address as a [`u64`].
71
    #[must_use]
72
    pub const fn to_u64(self) -> u64 {
30✔
73
        self.0.to_u64()
30✔
74
    }
30✔
75
}
76

77
impl Display for LbaLe {
78
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
18✔
79
        self.to_u64().fmt(f)
18✔
80
    }
18✔
81
}
82

83
impl From<Lba> for LbaLe {
84
    fn from(lba: Lba) -> Self {
1✔
85
        Self::from_u64(lba.0)
1✔
86
    }
1✔
87
}
88

89
/// Inclusive range of logical block addresses.
90
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
91
#[cfg_attr(feature = "bytemuck", derive(Pod, Zeroable))]
×
92
#[repr(C)]
93
pub struct LbaRangeInclusive {
94
    start: Lba,
95
    end: Lba,
96
}
97

98
impl LbaRangeInclusive {
99
    /// Create an LBA range. The end address must be greater than or
100
    /// equal to the start address.
101
    #[must_use]
102
    pub const fn new(start: Lba, end: Lba) -> Option<LbaRangeInclusive> {
3✔
103
        if end.0 >= start.0 {
3✔
104
            Some(LbaRangeInclusive { start, end })
2✔
105
        } else {
106
            None
1✔
107
        }
108
    }
3✔
109

110
    /// Starting LBA (inclusive).
111
    #[must_use]
112
    pub const fn start(self) -> Lba {
1✔
113
        self.start
1✔
114
    }
1✔
115

116
    /// Ending LBA (inclusive).
117
    #[must_use]
118
    pub const fn end(self) -> Lba {
1✔
119
        self.end
1✔
120
    }
1✔
121

122
    /// Create an LBA range from the corresponding byte range for the
123
    /// given block size.
124
    ///
125
    /// The byte range must correspond precisely to block bounds, with
126
    /// the start byte at the beginning of a block and the end byte at
127
    /// the end of a block
128
    ///
129
    /// # Examples
130
    ///
131
    /// ```
132
    /// use gpt_disk_types::{BlockSize, LbaRangeInclusive};
133
    ///
134
    /// let bs = BlockSize::BS_512;
135
    /// let r = LbaRangeInclusive::from_byte_range(512..=1535, bs).unwrap();
136
    /// assert_eq!(r.start().0, 1);
137
    /// assert_eq!(r.end().0, 2);
138
    #[must_use]
139
    pub fn from_byte_range(
3✔
140
        byte_range: RangeInclusive<u64>,
3✔
141
        block_size: BlockSize,
3✔
142
    ) -> Option<Self> {
3✔
143
        let start_byte = byte_range.start();
3✔
144
        let end_byte_plus_1 = byte_range.end().checked_add(1)?;
3✔
145
        let block_size = block_size.to_u64();
3✔
146

3✔
147
        if (start_byte % block_size) != 0 {
3✔
148
            return None;
1✔
149
        }
2✔
150
        if (end_byte_plus_1 % block_size) != 0 {
2✔
151
            return None;
1✔
152
        }
1✔
153

154
        let end_lba = (end_byte_plus_1 / block_size).checked_sub(1)?;
1✔
155

156
        LbaRangeInclusive::new(Lba(start_byte / block_size), Lba(end_lba))
1✔
157
    }
3✔
158

159
    /// Convert the LBA range to the corresponding byte range for the
160
    /// given block size.
161
    ///
162
    /// # Examples
163
    ///
164
    /// ```
165
    /// use gpt_disk_types::{BlockSize, Lba, LbaRangeInclusive};
166
    ///
167
    /// let r = LbaRangeInclusive::new(Lba(1), Lba(2)).unwrap();
168
    /// let bs = BlockSize::BS_512;
169
    /// assert_eq!(r.to_byte_range(bs).unwrap(), 512..=1535);
170
    /// ```
171
    #[must_use]
172
    pub fn to_byte_range(
1✔
173
        self,
1✔
174
        block_size: BlockSize,
1✔
175
    ) -> Option<RangeInclusive<u64>> {
1✔
176
        let block_size = block_size.to_u64();
1✔
177
        let start_byte = self.start.0.checked_mul(block_size)?;
1✔
178
        let end_byte = self
1✔
179
            .end
1✔
180
            .0
1✔
181
            .checked_mul(block_size)?
1✔
182
            .checked_add(block_size - 1)?;
1✔
183
        Some(start_byte..=end_byte)
1✔
184
    }
1✔
185

186
    /// Get the number of bytes in the LBA range for the given block
187
    /// size.
188
    ///
189
    /// # Examples
190
    ///
191
    /// ```
192
    /// use gpt_disk_types::{BlockSize, Lba, LbaRangeInclusive};
193
    ///
194
    /// let r = LbaRangeInclusive::new(Lba(1), Lba(2)).unwrap();
195
    /// let bs = BlockSize::BS_512;
196
    /// assert_eq!(r.num_bytes(bs).unwrap(), 1024);
197
    /// ```
198
    #[must_use]
199
    pub fn num_bytes(self, block_size: BlockSize) -> Option<u64> {
×
200
        let r = self.to_byte_range(block_size)?;
×
201
        r.end().checked_sub(*r.start())?.checked_add(1)
×
202
    }
×
203

204
    /// Get the number of blocks in the LBA range.
205
    ///
206
    /// # Examples
207
    ///
208
    /// ```
209
    /// use gpt_disk_types::{Lba, LbaRangeInclusive};
210
    ///
211
    /// let r = LbaRangeInclusive::new(Lba(1), Lba(2)).unwrap();
212
    /// assert_eq!(r.num_blocks(), 2);
213
    /// ```
214
    #[must_use]
215
    pub fn num_blocks(self) -> u64 {
×
216
        // Add one here since the range is inclusive.
×
217
        self.end().to_u64() - self.start.to_u64() + 1
×
218
    }
×
219
}
220

221
impl Display for LbaRangeInclusive {
222
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2✔
223
        write!(f, "{}..={}", self.start, self.end)
2✔
224
    }
2✔
225
}
226

227
/// Size of a block in bytes.
228
///
229
/// This type enforces some restrictions on the block size: it must be
230
/// at least 512 bytes and fit within a [`u32`].
231
///
232
/// # Minimum size
233
///
234
/// The [`MasterBootRecord`] size is 512 bytes and must fit within a
235
/// block, so the block size must be at least that large.
236
///
237
/// [`MasterBootRecord`]: crate::MasterBootRecord
238
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
239
#[repr(transparent)]
240
pub struct BlockSize(NonZeroU32);
241

242
impl BlockSize {
243
    /// 512-byte block size.
244
    pub const BS_512: Self = Self(if let Some(nz) = NonZeroU32::new(512) {
245
        nz
246
    } else {
247
        unreachable!()
248
    });
249

250
    /// 4096-byte block size.
251
    pub const BS_4096: Self = Self(if let Some(nz) = NonZeroU32::new(4096) {
252
        nz
253
    } else {
254
        unreachable!()
255
    });
256

257
    /// Create a `BlockSize`.
258
    #[must_use]
259
    pub const fn new(num_bytes: u32) -> Option<Self> {
7✔
260
        if let Some(nz) = NonZeroU32::new(num_bytes) {
7✔
261
            if num_bytes >= 512 {
5✔
262
                Some(Self(nz))
4✔
263
            } else {
264
                None
1✔
265
            }
266
        } else {
267
            None
2✔
268
        }
269
    }
7✔
270

271
    /// Create a `BlockSize`.
272
    #[must_use]
273
    pub fn from_usize(num_bytes: usize) -> Option<Self> {
2✔
274
        Self::new(u32::try_from(num_bytes).ok()?)
2✔
275
    }
2✔
276

277
    /// Get the size in bytes as a [`u32`].
278
    #[must_use]
279
    pub const fn to_u32(self) -> u32 {
1✔
280
        self.0.get()
1✔
281
    }
1✔
282

283
    /// Get the size in bytes as a [`u64`].
284
    #[allow(clippy::as_conversions)]
285
    #[must_use]
286
    pub const fn to_u64(self) -> u64 {
145✔
287
        self.0.get() as u64
145✔
288
    }
145✔
289

290
    /// Get the size in bytes as a [`usize`].
291
    #[must_use]
292
    pub fn to_usize(self) -> Option<usize> {
70✔
293
        self.0.get().try_into().ok()
70✔
294
    }
70✔
295

296
    /// Check if `value` is an even multiple of the block size.
297
    ///
298
    /// # Panics
299
    ///
300
    /// Panics if `value` does not fit in a [`u64`].
301
    #[must_use]
302
    pub fn is_multiple_of_block_size<T>(&self, value: T) -> bool
68✔
303
    where
68✔
304
        T: TryInto<u64>,
68✔
305
    {
68✔
306
        if let Ok(value) = value.try_into() {
68✔
307
            let block_size = self.to_u64();
67✔
308
            (value % block_size) == 0
67✔
309
        } else {
310
            panic!("value does not fit in a u64");
1✔
311
        }
312
    }
67✔
313

314
    /// Assert that the `buffer` size is an even multiple of the block size.
315
    ///
316
    /// # Panics
317
    ///
318
    /// Panics if `buffer.len()` is not an even multiple of the block size.
319
    #[track_caller]
320
    pub fn assert_valid_block_buffer(&self, buffer: &[u8]) {
62✔
321
        assert!(self.is_multiple_of_block_size(buffer.len()));
62✔
322
    }
61✔
323
}
324

325
impl Default for BlockSize {
326
    fn default() -> Self {
3✔
327
        BlockSize::BS_512
3✔
328
    }
3✔
329
}
330

331
impl Display for BlockSize {
332
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1✔
333
        write!(f, "{}", self.0)
1✔
334
    }
1✔
335
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc