fxfs/
round.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// Round `offset` up to next multiple of `block_size`.
6/// This function will fail if rounding up leads to an integer overflow.
7///
8/// (Note that unstable rust is currently adding the same function
9/// `{integer}::checked_next_multiple_of()` behind the "int_roundings" feature.)
10pub fn round_up<T: Into<U>, U: Copy + num_traits::PrimInt>(offset: U, block_size: T) -> Option<U> {
11    let block_size = block_size.into();
12    #[allow(clippy::eq_op)]
13    let one = block_size / block_size;
14    Some(round_down(offset.checked_add(&(block_size - one))?, block_size))
15}
16
17/// Round `offset` down to the previous multiple of `block_size`.
18pub fn round_down<
19    T: Into<U>,
20    U: Copy + std::ops::Rem<U, Output = U> + std::ops::Sub<U, Output = U>,
21>(
22    offset: U,
23    block_size: T,
24) -> U {
25    let block_size = block_size.into();
26    offset - offset % block_size
27}
28
29/// Computes the rounded division of `numerator` / `denominator`.
30///
31/// Returns None for an arithmetic error (overflow, or divide-by-zero).
32pub fn round_div(numerator: u64, denominator: u64) -> Option<u64> {
33    numerator.checked_add(denominator / 2)?.checked_div(denominator)
34}
35
36/// Returns how many items of a given size are needed to contain a value.
37///
38/// TODO(https://github.com/rust-lang/rust/issues/88581): Replace with `{integer}::div_ceil()` when
39/// `int_roundings` is available.
40pub fn how_many<T: Into<u64>>(value: u64, item_size: T) -> u64 {
41    let item_size = item_size.into();
42    let items = value / item_size;
43    let remainder = value % item_size;
44    if remainder != 0 {
45        items + 1
46    } else {
47        items
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use crate::round::{how_many, round_div};
54
55    #[test]
56    fn test_how_many() {
57        assert_eq!(how_many(0, 3u64), 0);
58        assert_eq!(how_many(1, 3u64), 1);
59        assert_eq!(how_many(2, 3u64), 1);
60        assert_eq!(how_many(3, 3u64), 1);
61        assert_eq!(how_many(4, 3u64), 2);
62        assert_eq!(how_many(5, 3u64), 2);
63        assert_eq!(how_many(6, 3u64), 2);
64
65        assert_eq!(how_many(17u64, 3u8), 6u64);
66
67        assert_eq!(how_many(u64::MAX, 4096u32), u64::MAX / 4096 + 1);
68    }
69
70    #[test]
71    fn test_round_div() {
72        assert_eq!(round_div(9, 4), Some(2));
73        assert_eq!(round_div(10, 4), Some(3));
74        assert_eq!(round_div(11, 4), Some(3));
75        assert_eq!(round_div(12, 4), Some(3));
76        assert_eq!(round_div(13, 4), Some(3));
77        assert_eq!(round_div(14, 4), Some(4));
78        assert_eq!(round_div(0, 1), Some(0));
79        assert_eq!(round_div(100, 0), None);
80        assert_eq!(round_div(u64::MAX, 2), None);
81    }
82}