Implement a SocketRef smart pointer to detect state changes.

This commit is contained in:
Egor Karavaev 2017-09-10 23:18:12 +03:00 committed by whitequark
parent 100b57aa66
commit 096ce02ac4
8 changed files with 146 additions and 88 deletions

View File

@ -12,8 +12,7 @@ use std::os::unix::io::AsRawFd;
use smoltcp::phy::wait as phy_wait; use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr}; use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface}; use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
use smoltcp::socket::{AsSocket, SocketSet}; use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
fn main() { fn main() {
utils::setup_logging(""); utils::setup_logging("");
@ -50,14 +49,14 @@ fn main() {
let tcp_handle = sockets.add(tcp_socket); let tcp_handle = sockets.add(tcp_socket);
{ {
let socket: &mut TcpSocket = sockets.get_mut(tcp_handle).as_socket(); let mut socket = sockets.get::<TcpSocket>(tcp_handle);
socket.connect((address, port), 49500).unwrap(); socket.connect((address, port), 49500).unwrap();
} }
let mut tcp_active = false; let mut tcp_active = false;
loop { loop {
{ {
let socket: &mut TcpSocket = sockets.get_mut(tcp_handle).as_socket(); let mut socket = sockets.get::<TcpSocket>(tcp_handle);
if socket.is_active() && !tcp_active { if socket.is_active() && !tcp_active {
debug!("connected"); debug!("connected");
} else if !socket.is_active() && tcp_active { } else if !socket.is_active() && tcp_active {

View File

@ -19,8 +19,7 @@ use core::str;
use smoltcp::phy::Loopback; use smoltcp::phy::Loopback;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface}; use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
use smoltcp::socket::{AsSocket, SocketSet}; use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
mod mock { mod mock {
@ -124,7 +123,7 @@ fn main() {
let mut done = false; let mut done = false;
while !done && clock.elapsed() < 10_000 { while !done && clock.elapsed() < 10_000 {
{ {
let socket: &mut TcpSocket = socket_set.get_mut(server_handle).as_socket(); let mut socket = socket_set.get::<TcpSocket>(server_handle);
if !socket.is_active() && !socket.is_listening() { if !socket.is_active() && !socket.is_listening() {
if !did_listen { if !did_listen {
debug!("listening"); debug!("listening");
@ -141,7 +140,7 @@ fn main() {
} }
{ {
let socket: &mut TcpSocket = socket_set.get_mut(client_handle).as_socket(); let mut socket = socket_set.get::<TcpSocket>(client_handle);
if !socket.is_open() { if !socket.is_open() {
if !did_connect { if !did_connect {
debug!("connecting"); debug!("connecting");

View File

@ -16,8 +16,7 @@ use smoltcp::wire::{EthernetAddress, IpVersion, IpProtocol, IpAddress, IpCidr,
Ipv4Address, Ipv4Packet, Ipv4Repr, Ipv4Address, Ipv4Packet, Ipv4Repr,
Icmpv4Repr, Icmpv4Packet}; Icmpv4Repr, Icmpv4Packet};
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface}; use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
use smoltcp::socket::{AsSocket, SocketSet}; use smoltcp::socket::{SocketSet, RawSocket, RawSocketBuffer, RawPacketBuffer};
use smoltcp::socket::{RawSocket, RawSocketBuffer, RawPacketBuffer};
use std::collections::HashMap; use std::collections::HashMap;
use byteorder::{ByteOrder, NetworkEndian}; use byteorder::{ByteOrder, NetworkEndian};
@ -75,7 +74,7 @@ fn main() {
loop { loop {
{ {
let socket: &mut RawSocket = sockets.get_mut(raw_handle).as_socket(); let mut socket = sockets.get::<RawSocket>(raw_handle);
let timestamp = Instant::now().duration_since(startup_time); let timestamp = Instant::now().duration_since(startup_time);
let timestamp_us = (timestamp.as_secs() * 1000000) + let timestamp_us = (timestamp.as_secs() * 1000000) +

View File

@ -13,7 +13,7 @@ use std::os::unix::io::AsRawFd;
use smoltcp::phy::wait as phy_wait; use smoltcp::phy::wait as phy_wait;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr};
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface}; use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
use smoltcp::socket::{AsSocket, SocketSet}; use smoltcp::socket::SocketSet;
use smoltcp::socket::{UdpSocket, UdpSocketBuffer, UdpPacketBuffer}; use smoltcp::socket::{UdpSocket, UdpSocketBuffer, UdpPacketBuffer};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer}; use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
@ -70,7 +70,7 @@ fn main() {
loop { loop {
// udp:6969: respond "hello" // udp:6969: respond "hello"
{ {
let socket: &mut UdpSocket = sockets.get_mut(udp_handle).as_socket(); let mut socket = sockets.get::<UdpSocket>(udp_handle);
if !socket.is_open() { if !socket.is_open() {
socket.bind(6969).unwrap() socket.bind(6969).unwrap()
} }
@ -93,7 +93,7 @@ fn main() {
// tcp:6969: respond "hello" // tcp:6969: respond "hello"
{ {
let socket: &mut TcpSocket = sockets.get_mut(tcp1_handle).as_socket(); let mut socket = sockets.get::<TcpSocket>(tcp1_handle);
if !socket.is_open() { if !socket.is_open() {
socket.listen(6969).unwrap(); socket.listen(6969).unwrap();
} }
@ -108,7 +108,7 @@ fn main() {
// tcp:6970: echo with reverse // tcp:6970: echo with reverse
{ {
let socket: &mut TcpSocket = sockets.get_mut(tcp2_handle).as_socket(); let mut socket = sockets.get::<TcpSocket>(tcp2_handle);
if !socket.is_open() { if !socket.is_open() {
socket.listen(6970).unwrap() socket.listen(6970).unwrap()
} }
@ -145,7 +145,7 @@ fn main() {
// tcp:6971: sinkhole // tcp:6971: sinkhole
{ {
let socket: &mut TcpSocket = sockets.get_mut(tcp3_handle).as_socket(); let mut socket = sockets.get::<TcpSocket>(tcp3_handle);
if !socket.is_open() { if !socket.is_open() {
socket.listen(6971).unwrap(); socket.listen(6971).unwrap();
socket.set_keep_alive(Some(1000)); socket.set_keep_alive(Some(1000));
@ -165,7 +165,7 @@ fn main() {
// tcp:6972: fountain // tcp:6972: fountain
{ {
let socket: &mut TcpSocket = sockets.get_mut(tcp4_handle).as_socket(); let mut socket = sockets.get::<TcpSocket>(tcp4_handle);
if !socket.is_open() { if !socket.is_open() {
socket.listen(6972).unwrap() socket.listen(6972).unwrap()
} }

View File

@ -13,7 +13,7 @@ use wire::{Ipv4Packet, Ipv4Repr};
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable}; use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
#[cfg(feature = "socket-udp")] use wire::{UdpPacket, UdpRepr}; #[cfg(feature = "socket-udp")] use wire::{UdpPacket, UdpRepr};
#[cfg(feature = "socket-tcp")] use wire::{TcpPacket, TcpRepr, TcpControl}; #[cfg(feature = "socket-tcp")] use wire::{TcpPacket, TcpRepr, TcpControl};
use socket::{Socket, SocketSet, AsSocket}; use socket::{Socket, SocketSet, AnySocket};
#[cfg(feature = "socket-raw")] use socket::RawSocket; #[cfg(feature = "socket-raw")] use socket::RawSocket;
#[cfg(feature = "socket-udp")] use socket::UdpSocket; #[cfg(feature = "socket-udp")] use socket::UdpSocket;
#[cfg(feature = "socket-tcp")] use socket::TcpSocket; #[cfg(feature = "socket-tcp")] use socket::TcpSocket;
@ -195,29 +195,29 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let mut caps = self.device.capabilities(); let mut caps = self.device.capabilities();
caps.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len(); caps.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len();
for socket in sockets.iter_mut() { for mut socket in sockets.iter_mut() {
let mut device_result = Ok(()); let mut device_result = Ok(());
let socket_result = let socket_result =
match socket { match *socket {
#[cfg(feature = "socket-raw")] #[cfg(feature = "socket-raw")]
&mut Socket::Raw(ref mut socket) => Socket::Raw(ref mut socket) =>
socket.dispatch(|response| { socket.dispatch(|response| {
device_result = self.dispatch(timestamp, Packet::Raw(response)); device_result = self.dispatch(timestamp, Packet::Raw(response));
device_result device_result
}, &caps.checksum), }, &caps.checksum),
#[cfg(feature = "socket-udp")] #[cfg(feature = "socket-udp")]
&mut Socket::Udp(ref mut socket) => Socket::Udp(ref mut socket) =>
socket.dispatch(|response| { socket.dispatch(|response| {
device_result = self.dispatch(timestamp, Packet::Udp(response)); device_result = self.dispatch(timestamp, Packet::Udp(response));
device_result device_result
}), }),
#[cfg(feature = "socket-tcp")] #[cfg(feature = "socket-tcp")]
&mut Socket::Tcp(ref mut socket) => Socket::Tcp(ref mut socket) =>
socket.dispatch(timestamp, &caps, |response| { socket.dispatch(timestamp, &caps, |response| {
device_result = self.dispatch(timestamp, Packet::Tcp(response)); device_result = self.dispatch(timestamp, Packet::Tcp(response));
device_result device_result
}), }),
&mut Socket::__Nonexhaustive(_) => unreachable!() Socket::__Nonexhaustive(_) => unreachable!()
}; };
match (device_result, socket_result) { match (device_result, socket_result) {
(Err(Error::Unaddressable), _) => break, // no one to transmit to (Err(Error::Unaddressable), _) => break, // no one to transmit to
@ -323,8 +323,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
// Pass every IP packet to all raw sockets we have registered. // Pass every IP packet to all raw sockets we have registered.
#[cfg(feature = "socket-raw")] #[cfg(feature = "socket-raw")]
for raw_socket in sockets.iter_mut().filter_map( for mut raw_socket in sockets.iter_mut().filter_map(RawSocket::downcast) {
<Socket as AsSocket<RawSocket>>::try_as_socket) {
if !raw_socket.accepts(&ip_repr) { continue } if !raw_socket.accepts(&ip_repr) { continue }
match raw_socket.process(&ip_repr, ip_payload, &checksum_caps) { match raw_socket.process(&ip_repr, ip_payload, &checksum_caps) {
@ -415,8 +414,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let checksum_caps = self.device.capabilities().checksum; let checksum_caps = self.device.capabilities().checksum;
let udp_repr = UdpRepr::parse(&udp_packet, &src_addr, &dst_addr, &checksum_caps)?; let udp_repr = UdpRepr::parse(&udp_packet, &src_addr, &dst_addr, &checksum_caps)?;
for udp_socket in sockets.iter_mut().filter_map( for mut udp_socket in sockets.iter_mut().filter_map(UdpSocket::downcast) {
<Socket as AsSocket<UdpSocket>>::try_as_socket) {
if !udp_socket.accepts(&ip_repr, &udp_repr) { continue } if !udp_socket.accepts(&ip_repr, &udp_repr) { continue }
match udp_socket.process(&ip_repr, &udp_repr) { match udp_socket.process(&ip_repr, &udp_repr) {
@ -458,8 +456,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
let checksum_caps = self.device.capabilities().checksum; let checksum_caps = self.device.capabilities().checksum;
let tcp_repr = TcpRepr::parse(&tcp_packet, &src_addr, &dst_addr, &checksum_caps)?; let tcp_repr = TcpRepr::parse(&tcp_packet, &src_addr, &dst_addr, &checksum_caps)?;
for tcp_socket in sockets.iter_mut().filter_map( for mut tcp_socket in sockets.iter_mut().filter_map(TcpSocket::downcast) {
<Socket as AsSocket<TcpSocket>>::try_as_socket) {
if !tcp_socket.accepts(&ip_repr, &tcp_repr) { continue } if !tcp_socket.accepts(&ip_repr, &tcp_repr) { continue }
match tcp_socket.process(timestamp, &ip_repr, &tcp_repr) { match tcp_socket.process(timestamp, &ip_repr, &tcp_repr) {

View File

@ -17,6 +17,7 @@ use wire::IpRepr;
#[cfg(feature = "socket-udp")] mod udp; #[cfg(feature = "socket-udp")] mod udp;
#[cfg(feature = "socket-tcp")] mod tcp; #[cfg(feature = "socket-tcp")] mod tcp;
mod set; mod set;
mod ref_;
#[cfg(feature = "socket-raw")] #[cfg(feature = "socket-raw")]
pub use self::raw::{PacketBuffer as RawPacketBuffer, pub use self::raw::{PacketBuffer as RawPacketBuffer,
@ -36,19 +37,19 @@ pub use self::tcp::{SocketBuffer as TcpSocketBuffer,
pub use self::set::{Set as SocketSet, Item as SocketSetItem, Handle as SocketHandle}; pub use self::set::{Set as SocketSet, Item as SocketSetItem, Handle as SocketHandle};
pub use self::set::{Iter as SocketSetIter, IterMut as SocketSetIterMut}; pub use self::set::{Iter as SocketSetIter, IterMut as SocketSetIterMut};
pub use self::ref_::Ref as SocketRef;
pub(crate) use self::ref_::Session as SocketSession;
/// A network socket. /// A network socket.
/// ///
/// This enumeration abstracts the various types of sockets based on the IP protocol. /// This enumeration abstracts the various types of sockets based on the IP protocol.
/// To downcast a `Socket` value down to a concrete socket, use /// To downcast a `Socket` value to a concrete socket, use the [AnySocket] trait,
/// the [AsSocket](trait.AsSocket.html) trait, and call e.g. `socket.as_socket::<UdpSocket<_>>()`. /// e.g. to get `UdpSocket`, call `UdpSocket::downcast(socket)`.
/// ///
/// The `process` and `dispatch` functions are fundamentally asymmetric and thus differ in /// It is usually more convenient to use [SocketSet::get] instead.
/// their use of the [trait PacketRepr](trait.PacketRepr.html). When `process` is called, ///
/// the packet length is already known and no allocation is required; on the other hand, /// [AnySocket]: trait.AnySocket.html
/// `process` would have to downcast a `&PacketRepr` to e.g. an `&UdpRepr` through `Any`, /// [SocketSet::get]: struct.SocketSet.html#method.get
/// which is rather inelegant. Conversely, when `dispatch` is called, the packet length is
/// not yet known and the packet storage has to be allocated; but the `&PacketRepr` is sufficient
/// since the lower layers treat the packet as an opaque octet sequence.
#[derive(Debug)] #[derive(Debug)]
pub enum Socket<'a, 'b: 'a> { pub enum Socket<'a, 'b: 'a> {
#[cfg(feature = "socket-raw")] #[cfg(feature = "socket-raw")]
@ -90,40 +91,37 @@ impl<'a, 'b> Socket<'a, 'b> {
} }
} }
/// A conversion trait for network sockets. impl<'a, 'b> SocketSession for Socket<'a, 'b> {
/// fn finish(&mut self) {
/// This trait is used to concisely downcast [Socket](trait.Socket.html) values to their dispatch_socket!(self, |socket [mut]| socket.finish())
/// concrete types. }
pub trait AsSocket<T> {
fn as_socket(&mut self) -> &mut T;
fn try_as_socket(&mut self) -> Option<&mut T>;
} }
macro_rules! as_socket { /// A conversion trait for network sockets.
($socket:ty, $variant:ident) => { pub trait AnySocket<'a, 'b>: SocketSession + Sized {
impl<'a, 'b> AsSocket<$socket> for Socket<'a, 'b> { fn downcast<'c>(socket_ref: SocketRef<'c, Socket<'a, 'b>>) ->
fn as_socket(&mut self) -> &mut $socket { Option<SocketRef<'c, Self>>;
match self { }
&mut Socket::$variant(ref mut socket) => socket,
_ => panic!(concat!(".as_socket::<",
stringify!($socket),
"> called on wrong socket type"))
}
}
fn try_as_socket(&mut self) -> Option<&mut $socket> { macro_rules! from_socket {
match self { ($socket:ty, $variant:ident) => {
&mut Socket::$variant(ref mut socket) => Some(socket), impl<'a, 'b> AnySocket<'a, 'b> for $socket {
_ => None, fn downcast<'c>(ref_: SocketRef<'c, Socket<'a, 'b>>) ->
} Option<SocketRef<'c, Self>> {
SocketRef::map(ref_, |socket| {
match *socket {
Socket::$variant(ref mut socket) => Some(socket),
_ => None,
}
})
} }
} }
} }
} }
#[cfg(feature = "socket-raw")] #[cfg(feature = "socket-raw")]
as_socket!(RawSocket<'a, 'b>, Raw); from_socket!(RawSocket<'a, 'b>, Raw);
#[cfg(feature = "socket-udp")] #[cfg(feature = "socket-udp")]
as_socket!(UdpSocket<'a, 'b>, Udp); from_socket!(UdpSocket<'a, 'b>, Udp);
#[cfg(feature = "socket-tcp")] #[cfg(feature = "socket-tcp")]
as_socket!(TcpSocket<'a>, Tcp); from_socket!(TcpSocket<'a>, Tcp);

73
src/socket/ref_.rs Normal file
View File

@ -0,0 +1,73 @@
use core::ops::{Deref, DerefMut};
#[cfg(feature = "socket-raw")]
use socket::RawSocket;
#[cfg(feature = "socket-udp")]
use socket::UdpSocket;
#[cfg(feature = "socket-tcp")]
use socket::TcpSocket;
/// A trait for tracking a socket usage session.
///
/// Allows implementation of custom drop logic that runs only if the socket was changed
/// in specific ways. For example, drop logic for UDP would check if the local endpoint
/// has changed, and if yes, notify the socket set.
#[doc(hidden)]
pub trait Session {
fn finish(&mut self) {}
}
#[cfg(feature = "socket-raw")]
impl<'a, 'b> Session for RawSocket<'a, 'b> {}
#[cfg(feature = "socket-udp")]
impl<'a, 'b> Session for UdpSocket<'a, 'b> {}
#[cfg(feature = "socket-tcp")]
impl<'a> Session for TcpSocket<'a> {}
/// A smart pointer to a socket.
///
/// Allows the network stack to efficiently determine if the socket state was changed in any way.
pub struct Ref<'a, T: Session + 'a> {
socket: &'a mut T,
consumed: bool,
}
impl<'a, T: Session> Ref<'a, T> {
pub(crate) fn new(socket: &'a mut T) -> Self {
Ref { socket, consumed: false }
}
}
impl<'a, T: Session + 'a> Ref<'a, T> {
pub(crate) fn map<U, F>(mut ref_: Self, f: F) -> Option<Ref<'a, U>>
where U: Session + 'a, F: FnOnce(&'a mut T) -> Option<&'a mut U> {
if let Some(socket) = f(ref_.socket) {
ref_.consumed = true;
Some(Ref::new(socket))
} else {
None
}
}
}
impl<'a, T: Session> Deref for Ref<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.socket
}
}
impl<'a, T: Session> DerefMut for Ref<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.socket
}
}
impl<'a, T: Session> Drop for Ref<'a, T> {
fn drop(&mut self) {
if !self.consumed {
Session::finish(self.socket);
}
}
}

View File

@ -1,7 +1,7 @@
use core::{fmt, slice}; use core::{fmt, slice};
use managed::ManagedSlice; use managed::ManagedSlice;
use super::Socket; use super::{Socket, SocketRef, AnySocket};
#[cfg(feature = "socket-tcp")] use super::TcpState; #[cfg(feature = "socket-tcp")] use super::TcpState;
/// An item of a socket set. /// An item of a socket set.
@ -28,7 +28,7 @@ impl fmt::Display for Handle {
} }
} }
/// An extensible set of sockets, with stable numeric identifiers. /// An extensible set of sockets.
/// ///
/// The lifetimes `'b` and `'c` are used when storing a `Socket<'b, 'c>`. /// The lifetimes `'b` and `'c` are used when storing a `Socket<'b, 'c>`.
#[derive(Debug)] #[derive(Debug)]
@ -79,26 +79,19 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Set<'a, 'b, 'c> {
} }
} }
/// Get a socket from the set by its handle.
///
/// # Panics
/// This function may panic if the handle does not belong to this socket set.
pub fn get(&self, handle: Handle) -> &Socket<'b, 'c> {
&self.sockets[handle.0]
.as_ref()
.expect("handle does not refer to a valid socket")
.socket
}
/// Get a socket from the set by its handle, as mutable. /// Get a socket from the set by its handle, as mutable.
/// ///
/// # Panics /// # Panics
/// This function may panic if the handle does not belong to this socket set. /// This function may panic if the handle does not belong to this socket set
pub fn get_mut(&mut self, handle: Handle) -> &mut Socket<'b, 'c> { /// or the socket has the wrong type.
&mut self.sockets[handle.0] pub fn get<T: AnySocket<'b, 'c>>(&mut self, handle: Handle) -> SocketRef<T> {
.as_mut() match self.sockets[handle.0].as_mut() {
.expect("handle does not refer to a valid socket") Some(item) => {
.socket T::downcast(SocketRef::new(&mut item.socket))
.expect("handle refers to a socket of a wrong type")
}
None => panic!("handle does not refer to a valid socket")
}
} }
/// Remove a socket from the set, without changing its state. /// Remove a socket from the set, without changing its state.
@ -175,7 +168,7 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Set<'a, 'b, 'c> {
Iter { lower: self.sockets.iter() } Iter { lower: self.sockets.iter() }
} }
/// Iterate every socket in this set, as mutable. /// Iterate every socket in this set, as SocketRef.
pub fn iter_mut<'d>(&'d mut self) -> IterMut<'d, 'b, 'c> { pub fn iter_mut<'d>(&'d mut self) -> IterMut<'d, 'b, 'c> {
IterMut { lower: self.sockets.iter_mut() } IterMut { lower: self.sockets.iter_mut() }
} }
@ -207,16 +200,16 @@ impl<'a, 'b: 'a, 'c: 'a + 'b> Iterator for Iter<'a, 'b, 'c> {
/// This struct is created by the [iter_mut](struct.SocketSet.html#method.iter_mut) /// This struct is created by the [iter_mut](struct.SocketSet.html#method.iter_mut)
/// on [socket sets](struct.SocketSet.html). /// on [socket sets](struct.SocketSet.html).
pub struct IterMut<'a, 'b: 'a, 'c: 'a + 'b> { pub struct IterMut<'a, 'b: 'a, 'c: 'a + 'b> {
lower: slice::IterMut<'a, Option<Item<'b, 'c>>> lower: slice::IterMut<'a, Option<Item<'b, 'c>>>,
} }
impl<'a, 'b: 'a, 'c: 'a + 'b> Iterator for IterMut<'a, 'b, 'c> { impl<'a, 'b: 'a, 'c: 'a + 'b> Iterator for IterMut<'a, 'b, 'c> {
type Item = &'a mut Socket<'b, 'c>; type Item = SocketRef<'a, Socket<'b, 'c>>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(item_opt) = self.lower.next() { while let Some(item_opt) = self.lower.next() {
if let Some(item) = item_opt.as_mut() { if let Some(item) = item_opt.as_mut() {
return Some(&mut item.socket) return Some(SocketRef::new(&mut item.socket))
} }
} }
None None