Skip to main content

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#[cfg(test)]
37mod tests {
38    use crate::round::round_div;
39
40    #[test]
41    fn test_round_div() {
42        assert_eq!(round_div(9, 4), Some(2));
43        assert_eq!(round_div(10, 4), Some(3));
44        assert_eq!(round_div(11, 4), Some(3));
45        assert_eq!(round_div(12, 4), Some(3));
46        assert_eq!(round_div(13, 4), Some(3));
47        assert_eq!(round_div(14, 4), Some(4));
48        assert_eq!(round_div(0, 1), Some(0));
49        assert_eq!(round_div(100, 0), None);
50        assert_eq!(round_div(u64::MAX, 2), None);
51    }
52}