Box the large structure `AnyUnboundSocket`
So far it is quite common to put the `AnyUnboundSocket` in an enum
variant, e.g. the following code snippet.
```rust
enum Inner {
Unbound(AlwaysSome<Box<AnyUnboundSocket>>),
Bound(AlwaysSome<Arc<AnyBoundSocket>>),
// ...
}
```
However, this pattern is very memory inefficient because the size
difference between two enum variants is significant. The size of
`AnyUnboundSocket` is much larger than the size of
`Arc<AnyBoundSocket>`, where the latter is simply a pointer and a
reference counter.
In fact, we're about to trigger Clippy's large_enum_variant warning.
We're just below its threshold, so the warning doesn't appear.
The solution is simple: If we put `AnyBoundSocket` in `Arc`, we should
also put `AnyUnboundSocket` in `Box`. This way the sizes of different
enum variants will be similar.
This commit is contained in:
parent
02e10705af
commit
9dc5a4d28f
|
|
@ -98,9 +98,9 @@ impl IfaceCommon {
|
|||
pub(super) fn bind_socket(
|
||||
&self,
|
||||
iface: Arc<dyn Iface>,
|
||||
socket: AnyUnboundSocket,
|
||||
socket: Box<AnyUnboundSocket>,
|
||||
config: BindPortConfig,
|
||||
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, AnyUnboundSocket)> {
|
||||
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, Box<AnyUnboundSocket>)> {
|
||||
let port = if let Some(port) = config.port() {
|
||||
port
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ pub trait Iface: internal::IfaceInternal + Send + Sync {
|
|||
/// See discussion at https://github.com/smoltcp-rs/smoltcp/issues/779.
|
||||
fn bind_socket(
|
||||
&self,
|
||||
socket: AnyUnboundSocket,
|
||||
socket: Box<AnyUnboundSocket>,
|
||||
config: BindPortConfig,
|
||||
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, AnyUnboundSocket)> {
|
||||
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, Box<AnyUnboundSocket>)> {
|
||||
let common = self.common();
|
||||
let socket_type_inner = socket.socket_family();
|
||||
common.bind_socket(self.arc_self(), socket, config)
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ fn get_ephemeral_iface(remote_ip_addr: &IpAddress) -> Arc<dyn Iface> {
|
|||
}
|
||||
|
||||
pub(super) fn bind_socket(
|
||||
unbound_socket: AnyUnboundSocket,
|
||||
unbound_socket: Box<AnyUnboundSocket>,
|
||||
endpoint: IpEndpoint,
|
||||
can_reuse: bool,
|
||||
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, AnyUnboundSocket)> {
|
||||
) -> core::result::Result<Arc<AnyBoundSocket>, (Error, Box<AnyUnboundSocket>)> {
|
||||
let iface = match get_iface_to_bind(&endpoint.addr) {
|
||||
Some(iface) => iface,
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ pub struct DatagramSocket {
|
|||
}
|
||||
|
||||
enum Inner {
|
||||
Unbound(AlwaysSome<AnyUnboundSocket>),
|
||||
Unbound(AlwaysSome<Box<AnyUnboundSocket>>),
|
||||
Bound(Arc<BoundDatagram>),
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ impl Inner {
|
|||
|
||||
impl DatagramSocket {
|
||||
pub fn new(nonblocking: bool) -> Self {
|
||||
let udp_socket = AnyUnboundSocket::new_udp();
|
||||
let udp_socket = Box::new(AnyUnboundSocket::new_udp());
|
||||
Self {
|
||||
inner: RwLock::new(Inner::Unbound(AlwaysSome::new(udp_socket))),
|
||||
nonblocking: AtomicBool::new(nonblocking),
|
||||
|
|
@ -176,16 +176,17 @@ impl DatagramSocket {
|
|||
}
|
||||
|
||||
fn try_bind_empheral(&self, remote_endpoint: &IpEndpoint) -> Result<Arc<BoundDatagram>> {
|
||||
// Fast path
|
||||
if let Inner::Bound(bound) = &*self.inner.read() {
|
||||
return Ok(bound.clone());
|
||||
}
|
||||
|
||||
// Slow path
|
||||
let mut inner = self.inner.write();
|
||||
if let Inner::Bound(bound) = &*inner {
|
||||
Ok(bound.clone())
|
||||
} else {
|
||||
inner.bind_to_ephemeral_endpoint(remote_endpoint)
|
||||
return Ok(bound.clone());
|
||||
}
|
||||
inner.bind_to_ephemeral_endpoint(remote_endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pub struct InitStream {
|
|||
}
|
||||
|
||||
enum Inner {
|
||||
Unbound(AlwaysSome<AnyUnboundSocket>),
|
||||
Unbound(AlwaysSome<Box<AnyUnboundSocket>>),
|
||||
Bound(AlwaysSome<Arc<AnyBoundSocket>>),
|
||||
Connecting {
|
||||
bound_socket: Arc<AnyBoundSocket>,
|
||||
|
|
@ -114,7 +114,7 @@ impl Inner {
|
|||
|
||||
impl InitStream {
|
||||
pub fn new(nonblocking: bool) -> Self {
|
||||
let socket = AnyUnboundSocket::new_tcp();
|
||||
let socket = Box::new(AnyUnboundSocket::new_tcp());
|
||||
let inner = Inner::Unbound(AlwaysSome::new(socket));
|
||||
Self {
|
||||
is_nonblocking: AtomicBool::new(nonblocking),
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ impl BacklogSocket {
|
|||
Errno::EINVAL,
|
||||
"the socket is not bound",
|
||||
))?;
|
||||
let unbound_socket = AnyUnboundSocket::new_tcp();
|
||||
let unbound_socket = Box::new(AnyUnboundSocket::new_tcp());
|
||||
let bound_socket = {
|
||||
let iface = bound_socket.iface();
|
||||
let bind_port_config = BindPortConfig::new(local_endpoint.port, true)?;
|
||||
|
|
|
|||
Loading…
Reference in New Issue