1use alloc::borrow::Cow;
19use core::borrow::Borrow;
20use core::fmt::Debug;
21use core::hash::Hash;
22
23pub(crate) mod address;
24pub(crate) mod link;
25
26pub trait DeviceIdentifier: Clone + Debug + Eq + Hash + PartialEq + Send + Sync + 'static {
28 fn is_loopback(&self) -> bool;
30}
31
32pub trait StrongDeviceIdentifier: DeviceIdentifier + PartialEq<Self::Weak> {
37 type Weak: WeakDeviceIdentifier<Strong = Self>;
39
40 fn downgrade(&self) -> Self::Weak;
42}
43
44pub trait WeakDeviceIdentifier: DeviceIdentifier + PartialEq<Self::Strong> {
48 type Strong: StrongDeviceIdentifier<Weak = Self>;
50
51 fn upgrade(&self) -> Option<Self::Strong>;
55}
56
57pub trait Device: 'static {}
62
63pub enum AnyDevice {}
68
69impl Device for AnyDevice {}
70
71pub trait DeviceIdContext<D: Device> {
74 type DeviceId: StrongDeviceIdentifier<Weak = Self::WeakDeviceId> + 'static;
76
77 type WeakDeviceId: WeakDeviceIdentifier<Strong = Self::DeviceId> + 'static;
79}
80
81pub trait DeviceIdAnyCompatContext<D: Device>:
91 DeviceIdContext<D>
92 + DeviceIdContext<
93 AnyDevice,
94 DeviceId: From<<Self as DeviceIdContext<D>>::DeviceId>,
95 WeakDeviceId: From<<Self as DeviceIdContext<D>>::WeakDeviceId>,
96 >
97{
98}
99
100impl<CC, D> DeviceIdAnyCompatContext<D> for CC
101where
102 D: Device,
103 CC: DeviceIdContext<D>
104 + DeviceIdContext<
105 AnyDevice,
106 DeviceId: From<<CC as DeviceIdContext<D>>::DeviceId>,
107 WeakDeviceId: From<<CC as DeviceIdContext<D>>::WeakDeviceId>,
108 >,
109{
110}
111
112#[derive(Copy, Clone)]
114#[allow(missing_docs)]
115pub enum EitherDeviceId<S, W> {
116 Strong(S),
117 Weak(W),
118}
119
120impl<S: PartialEq, W: PartialEq + PartialEq<S>> PartialEq for EitherDeviceId<S, W> {
121 fn eq(&self, other: &EitherDeviceId<S, W>) -> bool {
122 match (self, other) {
123 (EitherDeviceId::Strong(this), EitherDeviceId::Strong(other)) => this == other,
124 (EitherDeviceId::Strong(this), EitherDeviceId::Weak(other)) => other == this,
125 (EitherDeviceId::Weak(this), EitherDeviceId::Strong(other)) => this == other,
126 (EitherDeviceId::Weak(this), EitherDeviceId::Weak(other)) => this == other,
127 }
128 }
129}
130
131impl<S: StrongDeviceIdentifier, W: WeakDeviceIdentifier<Strong = S>> EitherDeviceId<&'_ S, &'_ W> {
132 pub fn as_strong_ref<'a>(&'a self) -> Option<Cow<'a, S>> {
136 match self {
137 EitherDeviceId::Strong(s) => Some(Cow::Borrowed(s)),
138 EitherDeviceId::Weak(w) => w.upgrade().map(Cow::Owned),
139 }
140 }
141}
142
143impl<S, W> EitherDeviceId<S, W> {
144 pub fn as_ref<'a, S2, W2>(&'a self) -> EitherDeviceId<&'a S2, &'a W2>
146 where
147 S: Borrow<S2>,
148 W: Borrow<W2>,
149 {
150 match self {
151 EitherDeviceId::Strong(s) => EitherDeviceId::Strong(s.borrow()),
152 EitherDeviceId::Weak(w) => EitherDeviceId::Weak(w.borrow()),
153 }
154 }
155}
156
157impl<S: StrongDeviceIdentifier<Weak = W>, W: WeakDeviceIdentifier<Strong = S>>
158 EitherDeviceId<S, W>
159{
160 pub fn as_strong<'a>(&'a self) -> Option<Cow<'a, S>> {
164 match self {
165 EitherDeviceId::Strong(s) => Some(Cow::Borrowed(s)),
166 EitherDeviceId::Weak(w) => w.upgrade().map(Cow::Owned),
167 }
168 }
169
170 pub fn as_weak<'a>(&'a self) -> Cow<'a, W> {
174 match self {
175 EitherDeviceId::Strong(s) => Cow::Owned(s.downgrade()),
176 EitherDeviceId::Weak(w) => Cow::Borrowed(w),
177 }
178 }
179}
180
181#[cfg(any(test, feature = "testutils"))]
182pub(crate) mod testutil {
183 use alloc::sync::Arc;
184 use core::sync::atomic::AtomicBool;
185
186 use super::*;
187
188 use crate::InterfaceProperties;
189 use crate::testutil::FakeCoreCtx;
190
191 #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
192 #[allow(missing_docs)]
193 pub enum FakeDeviceClass {
194 Ethernet,
195 Wlan,
196 }
197
198 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
200 pub struct FakeWeakDeviceId<D>(pub D);
201
202 impl<D: PartialEq> PartialEq<D> for FakeWeakDeviceId<D> {
203 fn eq(&self, other: &D) -> bool {
204 let Self(this) = self;
205 this == other
206 }
207 }
208
209 impl<D: FakeStrongDeviceId> WeakDeviceIdentifier for FakeWeakDeviceId<D> {
210 type Strong = D;
211
212 fn upgrade(&self) -> Option<D> {
213 let Self(inner) = self;
214 inner.is_alive().then(|| inner.clone())
215 }
216 }
217
218 impl<D: DeviceIdentifier> DeviceIdentifier for FakeWeakDeviceId<D> {
219 fn is_loopback(&self) -> bool {
220 let Self(inner) = self;
221 inner.is_loopback()
222 }
223 }
224
225 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
227 pub struct FakeDeviceId;
228
229 impl FakeDeviceId {
230 pub const FAKE_NAME: &'static str = "FakeDeviceId";
232 }
233
234 impl StrongDeviceIdentifier for FakeDeviceId {
235 type Weak = FakeWeakDeviceId<Self>;
236
237 fn downgrade(&self) -> Self::Weak {
238 FakeWeakDeviceId(self.clone())
239 }
240 }
241
242 impl DeviceIdentifier for FakeDeviceId {
243 fn is_loopback(&self) -> bool {
244 false
245 }
246 }
247
248 impl FakeStrongDeviceId for FakeDeviceId {
249 fn is_alive(&self) -> bool {
250 true
251 }
252 }
253
254 impl PartialEq<FakeWeakDeviceId<FakeDeviceId>> for FakeDeviceId {
255 fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeDeviceId>) -> bool {
256 self == other
257 }
258 }
259
260 impl InterfaceProperties<()> for FakeDeviceId {
261 fn id_matches(&self, _: &core::num::NonZeroU64) -> bool {
262 unimplemented!()
263 }
264
265 fn name_matches(&self, name: &str) -> bool {
266 name == Self::FAKE_NAME
267 }
268
269 fn device_class_matches(&self, _: &()) -> bool {
270 unimplemented!()
271 }
272 }
273
274 #[derive(Clone, Debug, Default)]
279 pub struct FakeReferencyDeviceId {
280 removed: Arc<AtomicBool>,
281 }
282
283 impl core::hash::Hash for FakeReferencyDeviceId {
284 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
285 let Self { removed } = self;
286 core::ptr::hash(alloc::sync::Arc::as_ptr(removed), state)
287 }
288 }
289
290 impl core::cmp::Eq for FakeReferencyDeviceId {}
291
292 impl core::cmp::PartialEq for FakeReferencyDeviceId {
293 fn eq(&self, Self { removed: other }: &Self) -> bool {
294 let Self { removed } = self;
295 alloc::sync::Arc::ptr_eq(removed, other)
296 }
297 }
298
299 impl core::cmp::Ord for FakeReferencyDeviceId {
300 fn cmp(&self, Self { removed: other }: &Self) -> core::cmp::Ordering {
301 let Self { removed } = self;
302 alloc::sync::Arc::as_ptr(removed).cmp(&alloc::sync::Arc::as_ptr(other))
303 }
304 }
305
306 impl core::cmp::PartialOrd for FakeReferencyDeviceId {
307 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
308 Some(self.cmp(other))
309 }
310 }
311
312 impl FakeReferencyDeviceId {
313 pub fn mark_removed(&self) {
316 self.removed.store(true, core::sync::atomic::Ordering::Relaxed);
317 }
318
319 const FAKE_NAME: &'static str = "FakeReferencyDeviceId";
320 }
321
322 impl StrongDeviceIdentifier for FakeReferencyDeviceId {
323 type Weak = FakeWeakDeviceId<Self>;
324
325 fn downgrade(&self) -> Self::Weak {
326 FakeWeakDeviceId(self.clone())
327 }
328 }
329
330 impl DeviceIdentifier for FakeReferencyDeviceId {
331 fn is_loopback(&self) -> bool {
332 false
333 }
334 }
335
336 impl FakeStrongDeviceId for FakeReferencyDeviceId {
337 fn is_alive(&self) -> bool {
338 !self.removed.load(core::sync::atomic::Ordering::Relaxed)
339 }
340 }
341
342 impl PartialEq<FakeWeakDeviceId<FakeReferencyDeviceId>> for FakeReferencyDeviceId {
343 fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeReferencyDeviceId>) -> bool {
344 self == other
345 }
346 }
347
348 impl InterfaceProperties<()> for FakeReferencyDeviceId {
349 fn id_matches(&self, _: &core::num::NonZeroU64) -> bool {
350 unimplemented!()
351 }
352
353 fn name_matches(&self, name: &str) -> bool {
354 name == Self::FAKE_NAME
355 }
356
357 fn device_class_matches(&self, _: &()) -> bool {
358 unimplemented!()
359 }
360 }
361
362 pub trait FakeStrongDeviceId:
364 StrongDeviceIdentifier<Weak = FakeWeakDeviceId<Self>> + 'static + Ord
365 {
366 fn is_alive(&self) -> bool;
371 }
372
373 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
376 #[allow(missing_docs)]
377 pub enum MultipleDevicesId {
378 A,
379 B,
380 C,
381 }
382
383 impl MultipleDevicesId {
384 pub fn all() -> [Self; 3] {
386 [Self::A, Self::B, Self::C]
387 }
388
389 fn fake_name(&self) -> &'static str {
390 match self {
391 MultipleDevicesId::A => "A",
392 MultipleDevicesId::B => "B",
393 MultipleDevicesId::C => "C",
394 }
395 }
396 }
397
398 impl DeviceIdentifier for MultipleDevicesId {
399 fn is_loopback(&self) -> bool {
400 false
401 }
402 }
403
404 impl StrongDeviceIdentifier for MultipleDevicesId {
405 type Weak = FakeWeakDeviceId<Self>;
406
407 fn downgrade(&self) -> Self::Weak {
408 FakeWeakDeviceId(self.clone())
409 }
410 }
411
412 impl FakeStrongDeviceId for MultipleDevicesId {
413 fn is_alive(&self) -> bool {
414 true
415 }
416 }
417
418 impl InterfaceProperties<()> for MultipleDevicesId {
419 fn id_matches(&self, _: &core::num::NonZeroU64) -> bool {
420 unimplemented!()
421 }
422
423 fn name_matches(&self, name: &str) -> bool {
424 self.fake_name() == name
425 }
426
427 fn device_class_matches(&self, _: &()) -> bool {
428 unimplemented!()
429 }
430 }
431
432 #[derive(Default)]
434 pub struct MultipleDevicesIdState<T> {
435 a: T,
436 b: T,
437 c: T,
438 }
439
440 impl<T> MultipleDevicesIdState<T> {
441 pub fn state(&self, device: &MultipleDevicesId) -> &T {
443 match device {
444 MultipleDevicesId::A => &self.a,
445 MultipleDevicesId::B => &self.b,
446 MultipleDevicesId::C => &self.c,
447 }
448 }
449 }
450
451 impl<S, Meta, D: StrongDeviceIdentifier> DeviceIdContext<AnyDevice> for FakeCoreCtx<S, Meta, D> {
452 type DeviceId = D;
453 type WeakDeviceId = D::Weak;
454 }
455
456 impl<S, Meta, D: StrongDeviceIdentifier> DeviceIdContext<AnyDevice>
457 for &mut FakeCoreCtx<S, Meta, D>
458 {
459 type DeviceId = D;
460 type WeakDeviceId = D::Weak;
461 }
462
463 impl PartialEq<FakeWeakDeviceId<MultipleDevicesId>> for MultipleDevicesId {
464 fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<MultipleDevicesId>) -> bool {
465 self == other
466 }
467 }
468}