1use std::cmp::Ordering;
5use std::convert::TryFrom;
6use std::ops::{Add, Sub};
7
8pub trait BusAddress:
10 Add<<Self as BusAddress>::V, Output = Self>
11 + Copy
12 + Eq
13 + Ord
14 + Sub<Output = <Self as BusAddress>::V>
15{
16 type V: Add<Output = Self::V>
18 + Copy
19 + From<u8>
20 + PartialEq
21 + Ord
22 + Sub<Output = Self::V>
23 + TryFrom<usize>;
24
25 fn value(&self) -> Self::V;
27
28 fn checked_add(&self, value: Self::V) -> Option<Self>;
31}
32
33pub type MmioAddressOffset = u64;
35
36#[derive(Clone, Copy, Debug)]
38pub struct MmioAddress(pub MmioAddressOffset);
39
40pub type PioAddressOffset = u16;
42
43#[derive(Clone, Copy, Debug)]
45pub struct PioAddress(pub PioAddressOffset);
46
47impl PartialEq for MmioAddress {
50 fn eq(&self, other: &Self) -> bool {
51 self.0 == other.0
52 }
53}
54
55impl Eq for MmioAddress {}
56
57impl PartialOrd for MmioAddress {
58 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
59 self.0.partial_cmp(&other.0)
60 }
61}
62
63impl Ord for MmioAddress {
64 fn cmp(&self, other: &Self) -> Ordering {
65 self.0.cmp(&other.0)
66 }
67}
68
69impl Add<MmioAddressOffset> for MmioAddress {
70 type Output = Self;
71
72 fn add(self, rhs: MmioAddressOffset) -> Self::Output {
73 MmioAddress(self.0 + rhs)
74 }
75}
76
77impl Sub for MmioAddress {
78 type Output = MmioAddressOffset;
79
80 fn sub(self, rhs: Self) -> Self::Output {
81 self.0 - rhs.0
82 }
83}
84
85impl BusAddress for MmioAddress {
86 type V = MmioAddressOffset;
87
88 fn value(&self) -> Self::V {
89 self.0
90 }
91
92 fn checked_add(&self, value: Self::V) -> Option<Self> {
93 self.0.checked_add(value).map(MmioAddress)
94 }
95}
96
97impl PartialEq for PioAddress {
100 fn eq(&self, other: &Self) -> bool {
101 self.0 == other.0
102 }
103}
104
105impl Eq for PioAddress {}
106
107impl PartialOrd for PioAddress {
108 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
109 self.0.partial_cmp(&other.0)
110 }
111}
112
113impl Ord for PioAddress {
114 fn cmp(&self, other: &Self) -> Ordering {
115 self.0.cmp(&other.0)
116 }
117}
118
119impl Add<PioAddressOffset> for PioAddress {
120 type Output = Self;
121
122 fn add(self, rhs: PioAddressOffset) -> Self::Output {
123 PioAddress(self.0 + rhs)
124 }
125}
126
127impl Sub for PioAddress {
128 type Output = PioAddressOffset;
129
130 fn sub(self, rhs: Self) -> Self::Output {
131 self.0 - rhs.0
132 }
133}
134
135impl BusAddress for PioAddress {
136 type V = PioAddressOffset;
137
138 fn value(&self) -> Self::V {
139 self.0
140 }
141
142 fn checked_add(&self, value: Self::V) -> Option<Self> {
143 self.0.checked_add(value).map(PioAddress)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 use std::fmt::Debug;
152
153 fn check_bus_address_ops<A>(addr_zero: A, max_value: A::V)
156 where
157 A: BusAddress + Debug,
158 A::V: Debug,
159 {
160 let value = A::V::from(5);
161 let addr = addr_zero + value;
162
163 assert!(addr_zero < addr);
164 assert_eq!(addr - addr_zero, value);
165
166 assert_eq!(addr.value(), value);
167 assert_eq!(addr_zero.checked_add(value).unwrap(), addr);
168
169 let addr_max = addr_zero.checked_add(max_value).unwrap();
170 assert!(addr_max.checked_add(A::V::from(1)).is_none());
171 }
172
173 #[test]
174 fn test_address_ops() {
175 check_bus_address_ops(MmioAddress(0), std::u64::MAX);
176 check_bus_address_ops(PioAddress(0), std::u16::MAX);
177 }
178}