use alloc::borrow::Cow;
use core::borrow::Borrow;
use core::fmt::Debug;
use core::hash::Hash;
pub(crate) mod address;
pub(crate) mod link;
pub trait DeviceIdentifier: Clone + Debug + Eq + Hash + PartialEq + Send + Sync + 'static {
fn is_loopback(&self) -> bool;
}
pub trait StrongDeviceIdentifier: DeviceIdentifier + PartialEq<Self::Weak> {
type Weak: WeakDeviceIdentifier<Strong = Self>;
fn downgrade(&self) -> Self::Weak;
}
pub trait WeakDeviceIdentifier: DeviceIdentifier + PartialEq<Self::Strong> {
type Strong: StrongDeviceIdentifier<Weak = Self>;
fn upgrade(&self) -> Option<Self::Strong>;
}
pub trait Device: 'static {}
pub enum AnyDevice {}
impl Device for AnyDevice {}
pub trait DeviceIdContext<D: Device> {
type DeviceId: StrongDeviceIdentifier<Weak = Self::WeakDeviceId> + 'static;
type WeakDeviceId: WeakDeviceIdentifier<Strong = Self::DeviceId> + 'static;
}
pub trait DeviceIdAnyCompatContext<D: Device>:
DeviceIdContext<D>
+ DeviceIdContext<
AnyDevice,
DeviceId: From<<Self as DeviceIdContext<D>>::DeviceId>,
WeakDeviceId: From<<Self as DeviceIdContext<D>>::WeakDeviceId>,
>
{
}
impl<CC, D> DeviceIdAnyCompatContext<D> for CC
where
D: Device,
CC: DeviceIdContext<D>
+ DeviceIdContext<
AnyDevice,
DeviceId: From<<CC as DeviceIdContext<D>>::DeviceId>,
WeakDeviceId: From<<CC as DeviceIdContext<D>>::WeakDeviceId>,
>,
{
}
#[derive(Copy, Clone)]
#[allow(missing_docs)]
pub enum EitherDeviceId<S, W> {
Strong(S),
Weak(W),
}
impl<S: PartialEq, W: PartialEq + PartialEq<S>> PartialEq for EitherDeviceId<S, W> {
fn eq(&self, other: &EitherDeviceId<S, W>) -> bool {
match (self, other) {
(EitherDeviceId::Strong(this), EitherDeviceId::Strong(other)) => this == other,
(EitherDeviceId::Strong(this), EitherDeviceId::Weak(other)) => other == this,
(EitherDeviceId::Weak(this), EitherDeviceId::Strong(other)) => this == other,
(EitherDeviceId::Weak(this), EitherDeviceId::Weak(other)) => this == other,
}
}
}
impl<S: StrongDeviceIdentifier, W: WeakDeviceIdentifier<Strong = S>> EitherDeviceId<&'_ S, &'_ W> {
pub fn as_strong_ref<'a>(&'a self) -> Option<Cow<'a, S>> {
match self {
EitherDeviceId::Strong(s) => Some(Cow::Borrowed(s)),
EitherDeviceId::Weak(w) => w.upgrade().map(Cow::Owned),
}
}
}
impl<S, W> EitherDeviceId<S, W> {
pub fn as_ref<'a, S2, W2>(&'a self) -> EitherDeviceId<&'a S2, &'a W2>
where
S: Borrow<S2>,
W: Borrow<W2>,
{
match self {
EitherDeviceId::Strong(s) => EitherDeviceId::Strong(s.borrow()),
EitherDeviceId::Weak(w) => EitherDeviceId::Weak(w.borrow()),
}
}
}
impl<S: StrongDeviceIdentifier<Weak = W>, W: WeakDeviceIdentifier<Strong = S>>
EitherDeviceId<S, W>
{
pub fn as_strong<'a>(&'a self) -> Option<Cow<'a, S>> {
match self {
EitherDeviceId::Strong(s) => Some(Cow::Borrowed(s)),
EitherDeviceId::Weak(w) => w.upgrade().map(Cow::Owned),
}
}
pub fn as_weak<'a>(&'a self) -> Cow<'a, W> {
match self {
EitherDeviceId::Strong(s) => Cow::Owned(s.downgrade()),
EitherDeviceId::Weak(w) => Cow::Borrowed(w),
}
}
}
pub trait DeviceWithName {
fn name_matches(&self, name: &str) -> bool;
}
#[cfg(any(test, feature = "testutils"))]
pub(crate) mod testutil {
use alloc::sync::Arc;
use core::sync::atomic::AtomicBool;
use super::*;
use crate::testutil::FakeCoreCtx;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct FakeWeakDeviceId<D>(pub D);
impl<D: PartialEq> PartialEq<D> for FakeWeakDeviceId<D> {
fn eq(&self, other: &D) -> bool {
let Self(this) = self;
this == other
}
}
impl<D: FakeStrongDeviceId> WeakDeviceIdentifier for FakeWeakDeviceId<D> {
type Strong = D;
fn upgrade(&self) -> Option<D> {
let Self(inner) = self;
inner.is_alive().then(|| inner.clone())
}
}
impl<D: DeviceIdentifier> DeviceIdentifier for FakeWeakDeviceId<D> {
fn is_loopback(&self) -> bool {
let Self(inner) = self;
inner.is_loopback()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct FakeDeviceId;
impl FakeDeviceId {
pub const FAKE_NAME: &'static str = "FakeDeviceId";
}
impl StrongDeviceIdentifier for FakeDeviceId {
type Weak = FakeWeakDeviceId<Self>;
fn downgrade(&self) -> Self::Weak {
FakeWeakDeviceId(self.clone())
}
}
impl DeviceIdentifier for FakeDeviceId {
fn is_loopback(&self) -> bool {
false
}
}
impl DeviceWithName for FakeDeviceId {
fn name_matches(&self, name: &str) -> bool {
name == Self::FAKE_NAME
}
}
impl FakeStrongDeviceId for FakeDeviceId {
fn is_alive(&self) -> bool {
true
}
}
impl PartialEq<FakeWeakDeviceId<FakeDeviceId>> for FakeDeviceId {
fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeDeviceId>) -> bool {
self == other
}
}
#[derive(Clone, Debug, Default)]
pub struct FakeReferencyDeviceId {
removed: Arc<AtomicBool>,
}
impl core::hash::Hash for FakeReferencyDeviceId {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
let Self { removed } = self;
core::ptr::hash(alloc::sync::Arc::as_ptr(removed), state)
}
}
impl core::cmp::Eq for FakeReferencyDeviceId {}
impl core::cmp::PartialEq for FakeReferencyDeviceId {
fn eq(&self, Self { removed: other }: &Self) -> bool {
let Self { removed } = self;
alloc::sync::Arc::ptr_eq(removed, other)
}
}
impl core::cmp::Ord for FakeReferencyDeviceId {
fn cmp(&self, Self { removed: other }: &Self) -> core::cmp::Ordering {
let Self { removed } = self;
alloc::sync::Arc::as_ptr(removed).cmp(&alloc::sync::Arc::as_ptr(other))
}
}
impl core::cmp::PartialOrd for FakeReferencyDeviceId {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl FakeReferencyDeviceId {
pub fn mark_removed(&self) {
self.removed.store(true, core::sync::atomic::Ordering::Relaxed);
}
const FAKE_NAME: &'static str = "FakeReferencyDeviceId";
}
impl StrongDeviceIdentifier for FakeReferencyDeviceId {
type Weak = FakeWeakDeviceId<Self>;
fn downgrade(&self) -> Self::Weak {
FakeWeakDeviceId(self.clone())
}
}
impl DeviceIdentifier for FakeReferencyDeviceId {
fn is_loopback(&self) -> bool {
false
}
}
impl DeviceWithName for FakeReferencyDeviceId {
fn name_matches(&self, name: &str) -> bool {
name == Self::FAKE_NAME
}
}
impl FakeStrongDeviceId for FakeReferencyDeviceId {
fn is_alive(&self) -> bool {
!self.removed.load(core::sync::atomic::Ordering::Relaxed)
}
}
impl PartialEq<FakeWeakDeviceId<FakeReferencyDeviceId>> for FakeReferencyDeviceId {
fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeReferencyDeviceId>) -> bool {
self == other
}
}
pub trait FakeStrongDeviceId:
StrongDeviceIdentifier<Weak = FakeWeakDeviceId<Self>> + 'static + Ord
{
fn is_alive(&self) -> bool;
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
#[allow(missing_docs)]
pub enum MultipleDevicesId {
A,
B,
C,
}
impl MultipleDevicesId {
pub fn all() -> [Self; 3] {
[Self::A, Self::B, Self::C]
}
fn fake_name(&self) -> &'static str {
match self {
MultipleDevicesId::A => "A",
MultipleDevicesId::B => "B",
MultipleDevicesId::C => "C",
}
}
}
impl DeviceIdentifier for MultipleDevicesId {
fn is_loopback(&self) -> bool {
false
}
}
impl DeviceWithName for MultipleDevicesId {
fn name_matches(&self, name: &str) -> bool {
self.fake_name() == name
}
}
impl StrongDeviceIdentifier for MultipleDevicesId {
type Weak = FakeWeakDeviceId<Self>;
fn downgrade(&self) -> Self::Weak {
FakeWeakDeviceId(self.clone())
}
}
impl FakeStrongDeviceId for MultipleDevicesId {
fn is_alive(&self) -> bool {
true
}
}
impl<S, Meta, D: StrongDeviceIdentifier> DeviceIdContext<AnyDevice> for FakeCoreCtx<S, Meta, D> {
type DeviceId = D;
type WeakDeviceId = D::Weak;
}
impl<S, Meta, D: StrongDeviceIdentifier> DeviceIdContext<AnyDevice>
for &mut FakeCoreCtx<S, Meta, D>
{
type DeviceId = D;
type WeakDeviceId = D::Weak;
}
impl PartialEq<FakeWeakDeviceId<MultipleDevicesId>> for MultipleDevicesId {
fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<MultipleDevicesId>) -> bool {
self == other
}
}
}