blob: 07f5bdfc57fe3efa0e400eb54def0e3e23449abc [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! A collection of uninstantiable types.
//!
//! These uninstantiable types can be used to satisfy trait bounds in
//! uninstantiable situations. For example,
//! [`crate::socket::datagram::DatagramBoundStateContext::DualStackContext`]
//! is set to the [`UninstantiableWrapper`] when implemented for Ipv4, because
//! IPv4 sockets do not support dualstack operations.
use core::{convert::Infallible as Never, marker::PhantomData};
use explicit::UnreachableExt as _;
use net_types::{ip::Ip, SpecifiedAddr};
use packet::{BufferMut, Serializer};
use crate::{
context::{CoreTimerContext, CounterContext, TimerBindingsTypes},
convert::BidirectionalConverter,
device::{self, Device, DeviceIdContext},
ip::{
socket::{
DefaultSendOptions, DeviceIpSocketHandler, IpSock, IpSocketHandler, Mms, MmsError,
SendOptions,
},
EitherDeviceId, HopLimits, IpExt, IpLayerIpExt, IpSockCreationError, IpSockSendError,
TransportIpContext,
},
socket::{
address::SocketIpAddr,
datagram::{
self, DatagramBoundStateContext, DatagramSocketMapSpec, DatagramSocketSpec,
DualStackDatagramBoundStateContext, NonDualStackDatagramBoundStateContext,
},
MaybeDualStack,
},
transport::tcp::{
socket::{self as tcp_socket, TcpBindingsTypes},
TcpCounters,
},
};
/// An uninstantiable type.
#[derive(Clone, Copy)]
pub struct Uninstantiable(Never);
impl AsRef<Never> for Uninstantiable {
fn as_ref(&self) -> &Never {
&self.0
}
}
impl<I, O> BidirectionalConverter<I, O> for Uninstantiable {
fn convert_back(&self, _: O) -> I {
self.uninstantiable_unreachable()
}
fn convert(&self, _: I) -> O {
self.uninstantiable_unreachable()
}
}
/// An uninstantiable type that wraps an instantiable type, `A`.
///
/// This type can be used to more easily implement traits where `A` already
/// implements the trait.
// TODO(https://github.com/rust-lang/rust/issues/118212): Simplify the trait
// implementations once Rust supports function delegation.
pub struct UninstantiableWrapper<A>(Never, PhantomData<A>);
impl<A> AsRef<Never> for UninstantiableWrapper<A> {
fn as_ref(&self) -> &Never {
let Self(never, _marker) = self;
&never
}
}
impl<D: Device, C: DeviceIdContext<D>> DeviceIdContext<D> for UninstantiableWrapper<C> {
type DeviceId = C::DeviceId;
type WeakDeviceId = C::WeakDeviceId;
}
impl<T, BT, C> CoreTimerContext<T, BT> for UninstantiableWrapper<C>
where
BT: TimerBindingsTypes,
C: CoreTimerContext<T, BT>,
{
fn convert_timer(dispatch_id: T) -> BT::DispatchId {
C::convert_timer(dispatch_id)
}
}
impl<I: datagram::IpExt, S: DatagramSocketSpec, P: DatagramBoundStateContext<I, C, S>, C>
DatagramBoundStateContext<I, C, S> for UninstantiableWrapper<P>
{
type IpSocketsCtx<'a> = P::IpSocketsCtx<'a>;
type DualStackContext = P::DualStackContext;
type NonDualStackContext = P::NonDualStackContext;
fn dual_stack_context(
&mut self,
) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
self.uninstantiable_unreachable()
}
fn with_bound_sockets<
O,
F: FnOnce(
&mut Self::IpSocketsCtx<'_>,
&datagram::BoundSockets<
I,
Self::WeakDeviceId,
<S as DatagramSocketSpec>::AddrSpec,
<S as DatagramSocketSpec>::SocketMapSpec<I, Self::WeakDeviceId>,
>,
) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
fn with_bound_sockets_mut<
O,
F: FnOnce(
&mut Self::IpSocketsCtx<'_>,
&mut datagram::BoundSockets<
I,
Self::WeakDeviceId,
<S as DatagramSocketSpec>::AddrSpec,
<S as DatagramSocketSpec>::SocketMapSpec<I, Self::WeakDeviceId>,
>,
) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
}
impl<I: datagram::IpExt, S: DatagramSocketSpec, P: DatagramBoundStateContext<I, C, S>, C>
NonDualStackDatagramBoundStateContext<I, C, S> for UninstantiableWrapper<P>
{
type Converter = Uninstantiable;
fn converter(&self) -> Self::Converter {
self.uninstantiable_unreachable()
}
}
impl<I: datagram::IpExt, S: DatagramSocketSpec, P: DatagramBoundStateContext<I, C, S>, C>
DualStackDatagramBoundStateContext<I, C, S> for UninstantiableWrapper<P>
where
for<'a> P::IpSocketsCtx<'a>: TransportIpContext<I::OtherVersion, C>,
{
type IpSocketsCtx<'a> = P::IpSocketsCtx<'a>;
fn dual_stack_enabled(
&self,
_state: &impl AsRef<datagram::IpOptions<I, Self::WeakDeviceId, S>>,
) -> bool {
self.uninstantiable_unreachable()
}
type OtherSendOptions = DefaultSendOptions;
fn to_other_send_options<'a>(
&self,
_state: &'a datagram::IpOptions<I, Self::WeakDeviceId, S>,
) -> &'a Self::OtherSendOptions {
self.uninstantiable_unreachable()
}
type Converter = Uninstantiable;
fn converter(&self) -> Self::Converter {
self.uninstantiable_unreachable()
}
fn to_other_bound_socket_id(
&self,
_id: &S::SocketId<I, Self::WeakDeviceId>,
) -> <S::SocketMapSpec<I::OtherVersion, Self::WeakDeviceId> as DatagramSocketMapSpec<
I::OtherVersion,
Self::WeakDeviceId,
S::AddrSpec,
>>::BoundSocketId {
self.uninstantiable_unreachable()
}
fn with_both_bound_sockets_mut<
O,
F: FnOnce(
&mut Self::IpSocketsCtx<'_>,
&mut datagram::BoundSockets<
I,
Self::WeakDeviceId,
S::AddrSpec,
S::SocketMapSpec<I, Self::WeakDeviceId>,
>,
&mut datagram::BoundSockets<
I::OtherVersion,
Self::WeakDeviceId,
S::AddrSpec,
S::SocketMapSpec<I::OtherVersion, Self::WeakDeviceId>,
>,
) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
fn with_other_bound_sockets_mut<
O,
F: FnOnce(
&mut Self::IpSocketsCtx<'_>,
&mut datagram::BoundSockets<
I::OtherVersion,
Self::WeakDeviceId,
S::AddrSpec,
S::SocketMapSpec<<I>::OtherVersion, Self::WeakDeviceId>,
>,
) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
}
impl<
I: tcp_socket::DualStackIpExt,
D: device::WeakId,
BT: TcpBindingsTypes,
P: tcp_socket::TcpDemuxContext<I, D, BT>,
> tcp_socket::TcpDemuxContext<I, D, BT> for UninstantiableWrapper<P>
{
type IpTransportCtx<'a> = P::IpTransportCtx<'a>;
fn with_demux<O, F: FnOnce(&tcp_socket::DemuxState<I, D, BT>) -> O>(&mut self, _cb: F) -> O {
self.uninstantiable_unreachable()
}
fn with_demux_mut<O, F: FnOnce(&mut tcp_socket::DemuxState<I, D, BT>) -> O>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
fn with_demux_mut_and_ip_transport_ctx<
O,
F: FnOnce(&mut tcp_socket::DemuxState<I, D, BT>, &mut Self::IpTransportCtx<'_>) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
}
impl<I: IpLayerIpExt, C, P: DeviceIpSocketHandler<I, C>> DeviceIpSocketHandler<I, C>
for UninstantiableWrapper<P>
{
fn get_mms(
&mut self,
_ctx: &mut C,
_ip_sock: &IpSock<I, Self::WeakDeviceId>,
) -> Result<Mms, MmsError> {
self.uninstantiable_unreachable()
}
}
impl<I: IpExt, C, P: TransportIpContext<I, C>> TransportIpContext<I, C>
for UninstantiableWrapper<P>
{
type DevicesWithAddrIter<'s> = P::DevicesWithAddrIter<'s> where P: 's;
fn get_devices_with_assigned_addr(
&mut self,
_addr: SpecifiedAddr<I::Addr>,
) -> Self::DevicesWithAddrIter<'_> {
self.uninstantiable_unreachable()
}
fn get_default_hop_limits(&mut self, _device: Option<&Self::DeviceId>) -> HopLimits {
self.uninstantiable_unreachable()
}
fn confirm_reachable_with_destination(
&mut self,
_ctx: &mut C,
_dst: SpecifiedAddr<I::Addr>,
_device: Option<&Self::DeviceId>,
) {
self.uninstantiable_unreachable()
}
}
impl<I: IpExt, C, P: IpSocketHandler<I, C>> IpSocketHandler<I, C> for UninstantiableWrapper<P> {
fn new_ip_socket(
&mut self,
_ctx: &mut C,
_device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
_local_ip: Option<SocketIpAddr<I::Addr>>,
_remote_ip: SocketIpAddr<I::Addr>,
_proto: I::Proto,
) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
self.uninstantiable_unreachable()
}
fn send_ip_packet<S, O>(
&mut self,
_ctx: &mut C,
_socket: &IpSock<I, Self::WeakDeviceId>,
_body: S,
_mtu: Option<u32>,
_options: &O,
) -> Result<(), (S, IpSockSendError)>
where
S: Serializer,
S::Buffer: BufferMut,
O: SendOptions<I, Self::WeakDeviceId>,
{
self.uninstantiable_unreachable()
}
}
impl<P> tcp_socket::AsThisStack<P> for UninstantiableWrapper<P> {
fn as_this_stack(&mut self) -> &mut P {
self.uninstantiable_unreachable()
}
}
impl<I: tcp_socket::DualStackIpExt> tcp_socket::DualStackDemuxIdConverter<I> for Uninstantiable {
fn convert<D: device::WeakId, BT: tcp_socket::TcpBindingsTypes>(
&self,
_id: tcp_socket::TcpSocketId<I, D, BT>,
) -> <I::OtherVersion as tcp_socket::DualStackIpExt>::DemuxSocketId<D, BT> {
self.uninstantiable_unreachable()
}
}
impl<
I: tcp_socket::DualStackIpExt,
D: device::WeakId,
BT: TcpBindingsTypes,
P: tcp_socket::TcpDualStackContext<I::OtherVersion, D, BT>,
> tcp_socket::TcpDualStackContext<I, D, BT> for UninstantiableWrapper<P>
where
for<'a> P::DualStackIpTransportCtx<'a>: CounterContext<TcpCounters<I>>,
{
type Converter = Uninstantiable;
type DualStackIpTransportCtx<'a> = P::DualStackIpTransportCtx<'a>;
fn other_demux_id_converter(&self) -> Self::Converter {
self.uninstantiable_unreachable()
}
fn dual_stack_enabled(&self, _ip_options: &I::DualStackIpOptions) -> bool {
self.uninstantiable_unreachable()
}
fn set_dual_stack_enabled(&self, _ip_options: &mut I::DualStackIpOptions, _value: bool) {
self.uninstantiable_unreachable()
}
fn with_both_demux_mut<
O,
F: FnOnce(
&mut tcp_socket::DemuxState<I, D, BT>,
&mut tcp_socket::DemuxState<I::OtherVersion, D, BT>,
) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
fn with_both_demux_mut_and_ip_transport_ctx<
O,
F: FnOnce(
&mut tcp_socket::DemuxState<I, D, BT>,
&mut tcp_socket::DemuxState<I::OtherVersion, D, BT>,
&mut Self::DualStackIpTransportCtx<'_>,
) -> O,
>(
&mut self,
_cb: F,
) -> O {
self.uninstantiable_unreachable()
}
}
impl<I: Ip, P> CounterContext<TcpCounters<I>> for UninstantiableWrapper<P> {
fn with_counters<O, F: FnOnce(&TcpCounters<I>) -> O>(&self, _cb: F) -> O {
self.uninstantiable_unreachable()
}
}