1use crate::error::Error;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct Wire(usize);
15
16impl Wire {
17 #[must_use]
19 pub fn new(index: usize) -> Self {
20 Self(index)
21 }
22
23 #[must_use]
25 pub fn index(self) -> usize {
26 self.0
27 }
28}
29
30impl core::fmt::Display for Wire {
31 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32 write!(f, "w{}", self.0)
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41pub struct WireCount(usize);
42
43impl WireCount {
44 #[must_use]
46 pub fn new(n: usize) -> Self {
47 Self(n)
48 }
49
50 #[must_use]
52 pub fn count(self) -> usize {
53 self.0
54 }
55
56 #[must_use]
58 pub fn zero() -> Self {
59 Self(0)
60 }
61
62 #[must_use]
64 pub fn tensor(self, other: Self) -> Self {
65 Self(self.0 + other.0)
66 }
67}
68
69impl std::ops::Add for WireCount {
70 type Output = Self;
71 fn add(self, rhs: Self) -> Self {
72 self.tensor(rhs)
73 }
74}
75
76impl core::fmt::Display for WireCount {
77 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
78 write!(f, "{}", self.0)
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub struct WireRange {
87 start: Wire,
88 count: WireCount,
89}
90
91impl WireRange {
92 #[must_use]
94 pub fn new(start: Wire, count: WireCount) -> Self {
95 Self { start, count }
96 }
97
98 #[must_use]
100 pub fn start(&self) -> Wire {
101 self.start
102 }
103
104 #[must_use]
106 pub fn count(&self) -> WireCount {
107 self.count
108 }
109
110 pub fn wire_at(&self, offset: usize) -> Result<Wire, Error> {
116 if offset < self.count.0 {
117 Ok(Wire::new(self.start.0 + offset))
118 } else {
119 Err(Error::WireOutOfBounds {
120 wire_index: self.start.0 + offset,
121 allocated: self.start.0 + self.count.0,
122 })
123 }
124 }
125}
126
127#[derive(Debug, Clone, Copy)]
132pub struct WireAllocator {
133 next: usize,
134}
135
136impl WireAllocator {
137 #[must_use]
139 pub fn new() -> Self {
140 Self { next: 0 }
141 }
142
143 #[must_use]
145 pub fn allocate(self, count: WireCount) -> (WireRange, Self) {
146 let range = WireRange::new(Wire::new(self.next), count);
147 let next_alloc = Self {
148 next: self.next + count.count(),
149 };
150 (range, next_alloc)
151 }
152
153 #[must_use]
155 pub fn total_allocated(self) -> usize {
156 self.next
157 }
158}
159
160impl Default for WireAllocator {
161 fn default() -> Self {
162 Self::new()
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn allocate_produces_non_overlapping_ranges() {
172 let alloc = WireAllocator::new();
173 let (r1, alloc) = alloc.allocate(WireCount::new(3));
174 let (r2, _alloc) = alloc.allocate(WireCount::new(2));
175 assert_eq!(r1.start(), Wire::new(0));
176 assert_eq!(r1.count(), WireCount::new(3));
177 assert_eq!(r2.start(), Wire::new(3));
178 assert_eq!(r2.count(), WireCount::new(2));
179 }
180
181 #[test]
182 fn wire_at_in_bounds() -> Result<(), Error> {
183 let range = WireRange::new(Wire::new(5), WireCount::new(3));
184 assert_eq!(range.wire_at(0)?, Wire::new(5));
185 assert_eq!(range.wire_at(1)?, Wire::new(6));
186 assert_eq!(range.wire_at(2)?, Wire::new(7));
187 Ok(())
188 }
189
190 #[test]
191 fn wire_at_out_of_bounds() {
192 let range = WireRange::new(Wire::new(0), WireCount::new(2));
193 assert!(range.wire_at(2).is_err());
194 }
195
196 #[test]
197 fn wire_count_tensor_is_addition() {
198 let a = WireCount::new(3);
199 let b = WireCount::new(4);
200 assert_eq!(a.tensor(b), WireCount::new(7));
201 assert_eq!(a + b, WireCount::new(7));
202 }
203}