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
181pub trait DeviceWithName {
183 fn name_matches(&self, name: &str) -> bool;
185}
186
187#[cfg(any(test, feature = "testutils"))]
188pub(crate) mod testutil {
189 use alloc::sync::Arc;
190 use core::sync::atomic::AtomicBool;
191
192 use super::*;
193
194 use crate::testutil::FakeCoreCtx;
195
196 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
198 pub struct FakeWeakDeviceId<D>(pub D);
199
200 impl<D: PartialEq> PartialEq<D> for FakeWeakDeviceId<D> {
201 fn eq(&self, other: &D) -> bool {
202 let Self(this) = self;
203 this == other
204 }
205 }
206
207 impl<D: FakeStrongDeviceId> WeakDeviceIdentifier for FakeWeakDeviceId<D> {
208 type Strong = D;
209
210 fn upgrade(&self) -> Option<D> {
211 let Self(inner) = self;
212 inner.is_alive().then(|| inner.clone())
213 }
214 }
215
216 impl<D: DeviceIdentifier> DeviceIdentifier for FakeWeakDeviceId<D> {
217 fn is_loopback(&self) -> bool {
218 let Self(inner) = self;
219 inner.is_loopback()
220 }
221 }
222
223 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
225 pub struct FakeDeviceId;
226
227 impl FakeDeviceId {
228 pub const FAKE_NAME: &'static str = "FakeDeviceId";
230 }
231
232 impl StrongDeviceIdentifier for FakeDeviceId {
233 type Weak = FakeWeakDeviceId<Self>;
234
235 fn downgrade(&self) -> Self::Weak {
236 FakeWeakDeviceId(self.clone())
237 }
238 }
239
240 impl DeviceIdentifier for FakeDeviceId {
241 fn is_loopback(&self) -> bool {
242 false
243 }
244 }
245
246 impl DeviceWithName for FakeDeviceId {
247 fn name_matches(&self, name: &str) -> bool {
248 name == Self::FAKE_NAME
249 }
250 }
251
252 impl FakeStrongDeviceId for FakeDeviceId {
253 fn is_alive(&self) -> bool {
254 true
255 }
256 }
257
258 impl PartialEq<FakeWeakDeviceId<FakeDeviceId>> for FakeDeviceId {
259 fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeDeviceId>) -> bool {
260 self == other
261 }
262 }
263
264 #[derive(Clone, Debug, Default)]
269 pub struct FakeReferencyDeviceId {
270 removed: Arc<AtomicBool>,
271 }
272
273 impl core::hash::Hash for FakeReferencyDeviceId {
274 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
275 let Self { removed } = self;
276 core::ptr::hash(alloc::sync::Arc::as_ptr(removed), state)
277 }
278 }
279
280 impl core::cmp::Eq for FakeReferencyDeviceId {}
281
282 impl core::cmp::PartialEq for FakeReferencyDeviceId {
283 fn eq(&self, Self { removed: other }: &Self) -> bool {
284 let Self { removed } = self;
285 alloc::sync::Arc::ptr_eq(removed, other)
286 }
287 }
288
289 impl core::cmp::Ord for FakeReferencyDeviceId {
290 fn cmp(&self, Self { removed: other }: &Self) -> core::cmp::Ordering {
291 let Self { removed } = self;
292 alloc::sync::Arc::as_ptr(removed).cmp(&alloc::sync::Arc::as_ptr(other))
293 }
294 }
295
296 impl core::cmp::PartialOrd for FakeReferencyDeviceId {
297 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
298 Some(self.cmp(other))
299 }
300 }
301
302 impl FakeReferencyDeviceId {
303 pub fn mark_removed(&self) {
306 self.removed.store(true, core::sync::atomic::Ordering::Relaxed);
307 }
308
309 const FAKE_NAME: &'static str = "FakeReferencyDeviceId";
310 }
311
312 impl StrongDeviceIdentifier for FakeReferencyDeviceId {
313 type Weak = FakeWeakDeviceId<Self>;
314
315 fn downgrade(&self) -> Self::Weak {
316 FakeWeakDeviceId(self.clone())
317 }
318 }
319
320 impl DeviceIdentifier for FakeReferencyDeviceId {
321 fn is_loopback(&self) -> bool {
322 false
323 }
324 }
325
326 impl DeviceWithName for FakeReferencyDeviceId {
327 fn name_matches(&self, name: &str) -> bool {
328 name == Self::FAKE_NAME
329 }
330 }
331
332 impl FakeStrongDeviceId for FakeReferencyDeviceId {
333 fn is_alive(&self) -> bool {
334 !self.removed.load(core::sync::atomic::Ordering::Relaxed)
335 }
336 }
337
338 impl PartialEq<FakeWeakDeviceId<FakeReferencyDeviceId>> for FakeReferencyDeviceId {
339 fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeReferencyDeviceId>) -> bool {
340 self == other
341 }
342 }
343
344 pub trait FakeStrongDeviceId:
346 StrongDeviceIdentifier<Weak = FakeWeakDeviceId<Self>> + 'static + Ord
347 {
348 fn is_alive(&self) -> bool;
353 }
354
355 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
358 #[allow(missing_docs)]
359 pub enum MultipleDevicesId {
360 A,
361 B,
362 C,
363 }
364
365 impl MultipleDevicesId {
366 pub fn all() -> [Self; 3] {
368 [Self::A, Self::B, Self::C]
369 }
370
371 fn fake_name(&self) -> &'static str {
372 match self {
373 MultipleDevicesId::A => "A",
374 MultipleDevicesId::B => "B",
375 MultipleDevicesId::C => "C",
376 }
377 }
378 }
379
380 impl DeviceIdentifier for MultipleDevicesId {
381 fn is_loopback(&self) -> bool {
382 false
383 }
384 }
385
386 impl DeviceWithName for MultipleDevicesId {
387 fn name_matches(&self, name: &str) -> bool {
388 self.fake_name() == name
389 }
390 }
391
392 impl StrongDeviceIdentifier for MultipleDevicesId {
393 type Weak = FakeWeakDeviceId<Self>;
394
395 fn downgrade(&self) -> Self::Weak {
396 FakeWeakDeviceId(self.clone())
397 }
398 }
399
400 impl FakeStrongDeviceId for MultipleDevicesId {
401 fn is_alive(&self) -> bool {
402 true
403 }
404 }
405
406 impl<S, Meta, D: StrongDeviceIdentifier> DeviceIdContext<AnyDevice> for FakeCoreCtx<S, Meta, D> {
407 type DeviceId = D;
408 type WeakDeviceId = D::Weak;
409 }
410
411 impl<S, Meta, D: StrongDeviceIdentifier> DeviceIdContext<AnyDevice>
412 for &mut FakeCoreCtx<S, Meta, D>
413 {
414 type DeviceId = D;
415 type WeakDeviceId = D::Weak;
416 }
417
418 impl PartialEq<FakeWeakDeviceId<MultipleDevicesId>> for MultipleDevicesId {
419 fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<MultipleDevicesId>) -> bool {
420 self == other
421 }
422 }
423}