wlan_common/
time.rs

1// Copyright 2019 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
5use std::ops;
6use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
7
8/// Representation of N IEEE 802.11 TimeUnits.
9/// A TimeUnit is defined as 1024 micro seconds.
10/// Note: Be careful with arithmetic operations on a TimeUnit. A TimeUnit is limited to 2 octets
11/// and can easily overflow. However, there is usually no need to ever work with TUs > 0xFFFF.
12#[repr(C)]
13#[derive(
14    IntoBytes,
15    KnownLayout,
16    FromBytes,
17    Immutable,
18    Copy,
19    Clone,
20    Debug,
21    Default,
22    PartialEq,
23    Eq,
24    PartialOrd,
25    Ord,
26    Hash,
27)]
28pub struct TimeUnit(pub u16);
29
30#[cfg(target_os = "fuchsia")]
31#[cfg(target_os = "fuchsia")]
32impl From<TimeUnit> for zx::MonotonicDuration {
33    fn from(tu: TimeUnit) -> zx::MonotonicDuration {
34        zx::MonotonicDuration::from_micros(tu.into_micros())
35    }
36}
37
38impl ops::Add<TimeUnit> for TimeUnit {
39    type Output = Self;
40    fn add(self, other_time_unit: TimeUnit) -> Self {
41        Self(self.0.saturating_add(other_time_unit.0))
42    }
43}
44
45impl<T> ops::Mul<T> for TimeUnit
46where
47    T: Into<u16>,
48{
49    type Output = Self;
50    fn mul(self, k: T) -> Self {
51        Self(self.0.saturating_mul(k.into()))
52    }
53}
54
55impl TimeUnit {
56    pub const DEFAULT_BEACON_INTERVAL: Self = Self(100);
57    pub const MAX: Self = Self(std::u16::MAX);
58
59    pub const fn into_micros(&self) -> i64 {
60        (self.0 as i64) * 1024
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[fuchsia::test]
69    fn one_time_unit_conversion_to_microseconds() {
70        assert_eq!(1024, TimeUnit(1).into_micros());
71    }
72
73    #[fuchsia::test]
74    fn time_unit_conversion_to_microseconds_is_linear() {
75        assert_eq!(0, TimeUnit(0).into_micros());
76        assert_eq!(1024, TimeUnit(1).into_micros());
77        assert_eq!(204800, TimeUnit(200).into_micros());
78    }
79
80    #[fuchsia::test]
81    fn one_time_unit_conversion_to_duration() {
82        assert_eq!(
83            zx::MonotonicDuration::from(TimeUnit(1)),
84            zx::MonotonicDuration::from_micros(1024)
85        );
86    }
87
88    #[fuchsia::test]
89    fn time_unit_conversion_to_duration_is_linear() {
90        assert_eq!(zx::MonotonicDuration::from(TimeUnit(0)), zx::MonotonicDuration::from_micros(0));
91        assert_eq!(
92            zx::MonotonicDuration::from(TimeUnit(1)),
93            zx::MonotonicDuration::from_micros(1024)
94        );
95        assert_eq!(
96            zx::MonotonicDuration::from(TimeUnit(200)),
97            zx::MonotonicDuration::from_micros(204800)
98        );
99    }
100
101    #[fuchsia::test]
102    fn time_unit_multiplication_with_integer() {
103        assert_eq!(TimeUnit(100) * 20_u8, TimeUnit(2000));
104    }
105
106    #[fuchsia::test]
107    fn time_unit_addition_with_other_time_unit() {
108        assert_eq!(TimeUnit(100) + TimeUnit(20), TimeUnit(120));
109    }
110
111    #[fuchsia::test]
112    fn time_unit_addition_saturation() {
113        assert_eq!(TimeUnit(1) + TimeUnit::MAX, TimeUnit::MAX);
114    }
115
116    #[fuchsia::test]
117    fn time_unit_multiplication_saturation() {
118        assert_eq!(TimeUnit::MAX * 2u16, TimeUnit::MAX);
119    }
120}