From 71cc55c0082980400fabcc1104d80280556056e0 Mon Sep 17 00:00:00 2001 From: Ed Barnard Date: Sat, 22 Oct 2022 15:56:56 +0100 Subject: [PATCH 1/2] Allow a type implementing `phy::Device` to contain borrowed data Previously, a limitation of Rust's type system required a device to implement `phy::Device<'a>` for all lifetimes, including `'static`, to be able to call methods on `iface::Interface`. This prevented types implementing `phy::Device<'a>` from containing any borrowed data. Now that Rust supports GATs (generic associated types), it is possible to lift this restriction and allow implementations of `phy::Device<'a>` which contain borrowed data. --- examples/utils.rs | 2 +- fuzz/utils.rs | 4 ++-- src/iface/interface.rs | 18 +++++++++--------- src/phy/fault_injector.rs | 21 +++++++++++++-------- src/phy/fuzz_injector.rs | 25 +++++++++++++++---------- src/phy/loopback.rs | 10 +++++----- src/phy/mod.rs | 27 ++++++++++++++++----------- src/phy/pcap_writer.rs | 23 ++++++++++++++--------- src/phy/raw_socket.rs | 10 +++++----- src/phy/tracer.rs | 21 +++++++++++++-------- src/phy/tuntap_interface.rs | 10 +++++----- 11 files changed, 98 insertions(+), 73 deletions(-) diff --git a/examples/utils.rs b/examples/utils.rs index 8473c7303..fc3193593 100644 --- a/examples/utils.rs +++ b/examples/utils.rs @@ -159,7 +159,7 @@ pub fn parse_middleware_options( loopback: bool, ) -> FaultInjector>>> where - D: for<'a> Device<'a>, + D: Device, { let drop_chance = matches .opt_str("drop-chance") diff --git a/fuzz/utils.rs b/fuzz/utils.rs index 89329d99d..3d625f102 100644 --- a/fuzz/utils.rs +++ b/fuzz/utils.rs @@ -87,13 +87,13 @@ pub fn add_middleware_options(opts: &mut Options, _free: &mut Vec<&str>) { ); } -pub fn parse_middleware_options( +pub fn parse_middleware_options<'a, D>( matches: &mut Matches, device: D, loopback: bool, ) -> FaultInjector>>> where - D: for<'a> Device<'a>, + D: Device<'a>, { let drop_chance = matches .opt_str("drop-chance") diff --git a/src/iface/interface.rs b/src/iface/interface.rs index 14fae7184..a31f5bb49 100644 --- a/src/iface/interface.rs +++ b/src/iface/interface.rs @@ -551,7 +551,7 @@ let iface = builder.finalize(&mut device); /// [neighbor_cache]: #method.neighbor_cache pub fn finalize(self, device: &mut D) -> Interface<'a> where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { let caps = device.capabilities(); @@ -893,7 +893,7 @@ impl<'a> Interface<'a> { timestamp: Instant, ) -> Result where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { self.inner.now = timestamp; @@ -935,7 +935,7 @@ impl<'a> Interface<'a> { timestamp: Instant, ) -> Result where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { self.inner.now = timestamp; @@ -1035,7 +1035,7 @@ impl<'a> Interface<'a> { sockets: &mut SocketSet<'_>, ) -> Result where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { self.inner.now = timestamp; @@ -1140,7 +1140,7 @@ impl<'a> Interface<'a> { fn socket_ingress(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { let mut processed_any = false; let Self { @@ -1196,7 +1196,7 @@ impl<'a> Interface<'a> { fn socket_egress(&mut self, device: &mut D, sockets: &mut SocketSet<'_>) -> bool where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { let Self { inner, @@ -1306,7 +1306,7 @@ impl<'a> Interface<'a> { #[cfg(feature = "proto-igmp")] fn igmp_egress(&mut self, device: &mut D) -> Result where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { match self.inner.igmp_report_state { IgmpReportState::ToSpecificQuery { @@ -1372,7 +1372,7 @@ impl<'a> Interface<'a> { #[cfg(feature = "proto-ipv4-fragmentation")] fn ipv4_egress(&mut self, device: &mut D) -> Result where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { // Reset the buffer when we transmitted everything. if self.out_packets.ipv4_out_packet.finished() { @@ -1410,7 +1410,7 @@ impl<'a> Interface<'a> { #[cfg(feature = "proto-sixlowpan-fragmentation")] fn sixlowpan_egress(&mut self, device: &mut D) -> Result where - D: for<'d> Device<'d> + ?Sized, + D: Device + ?Sized, { // Reset the buffer when we transmitted everything. if self.out_packets.sixlowpan_out_packet.finished() { diff --git a/src/phy/fault_injector.rs b/src/phy/fault_injector.rs index 6a83bf759..b852d060d 100644 --- a/src/phy/fault_injector.rs +++ b/src/phy/fault_injector.rs @@ -94,13 +94,13 @@ impl State { /// adverse network conditions (such as random packet loss or corruption), or software /// or hardware limitations (such as a limited number or size of usable network buffers). #[derive(Debug)] -pub struct FaultInjector Device<'a>> { +pub struct FaultInjector { inner: D, state: RefCell, config: Config, } -impl Device<'a>> FaultInjector { +impl FaultInjector { /// Create a fault injector device, using the given random number generator seed. pub fn new(inner: D, seed: u32) -> FaultInjector { let state = State { @@ -195,12 +195,17 @@ impl Device<'a>> FaultInjector { } } -impl<'a, D> Device<'a> for FaultInjector +impl Device for FaultInjector where - D: for<'b> Device<'b>, + D: Device, { - type RxToken = RxToken<'a, >::RxToken>; - type TxToken = TxToken<'a, >::TxToken>; + type RxToken<'a> = RxToken<'a, ::RxToken<'a>> + where + Self: 'a; + + type TxToken<'a> = TxToken<'a, ::TxToken<'a>> + where + Self: 'a; fn capabilities(&self) -> DeviceCapabilities { let mut caps = self.inner.capabilities(); @@ -210,7 +215,7 @@ where caps } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { let &mut Self { ref mut inner, ref state, @@ -233,7 +238,7 @@ where }) } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { let &mut Self { ref mut inner, ref state, diff --git a/src/phy/fuzz_injector.rs b/src/phy/fuzz_injector.rs index 4be1fc0e2..e4858040b 100644 --- a/src/phy/fuzz_injector.rs +++ b/src/phy/fuzz_injector.rs @@ -19,14 +19,14 @@ pub trait Fuzzer { #[allow(unused)] #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct FuzzInjector Device<'a>, FTx: Fuzzer, FRx: Fuzzer> { +pub struct FuzzInjector { inner: D, fuzz_tx: FTx, fuzz_rx: FRx, } #[allow(unused)] -impl Device<'a>, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector { +impl FuzzInjector { /// Create a fuzz injector device. pub fn new(inner: D, fuzz_tx: FTx, fuzz_rx: FRx) -> FuzzInjector { FuzzInjector { @@ -42,14 +42,19 @@ impl Device<'a>, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector } } -impl<'a, D, FTx, FRx> Device<'a> for FuzzInjector +impl Device for FuzzInjector where - D: for<'b> Device<'b>, - FTx: Fuzzer + 'a, - FRx: Fuzzer + 'a, + D: Device, + FTx: Fuzzer, + FRx: Fuzzer, { - type RxToken = RxToken<'a, >::RxToken, FRx>; - type TxToken = TxToken<'a, >::TxToken, FTx>; + type RxToken<'a> = RxToken<'a, ::RxToken<'a>, FRx> + where + Self: 'a; + + type TxToken<'a> = TxToken<'a, ::TxToken<'a>, FTx> + where + Self: 'a; fn capabilities(&self) -> DeviceCapabilities { let mut caps = self.inner.capabilities(); @@ -59,7 +64,7 @@ where caps } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { let &mut Self { ref mut inner, ref fuzz_rx, @@ -78,7 +83,7 @@ where }) } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { let &mut Self { ref mut inner, fuzz_rx: _, diff --git a/src/phy/loopback.rs b/src/phy/loopback.rs index 9b39aed33..76e284def 100644 --- a/src/phy/loopback.rs +++ b/src/phy/loopback.rs @@ -29,9 +29,9 @@ impl Loopback { } } -impl<'a> Device<'a> for Loopback { - type RxToken = RxToken; - type TxToken = TxToken<'a>; +impl Device for Loopback { + type RxToken<'a> = RxToken; + type TxToken<'a> = TxToken<'a>; fn capabilities(&self) -> DeviceCapabilities { DeviceCapabilities { @@ -41,7 +41,7 @@ impl<'a> Device<'a> for Loopback { } } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { self.queue.pop_front().map(move |buffer| { let rx = RxToken { buffer }; let tx = TxToken { @@ -51,7 +51,7 @@ impl<'a> Device<'a> for Loopback { }) } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { Some(TxToken { queue: &mut self.queue, }) diff --git a/src/phy/mod.rs b/src/phy/mod.rs index 3a7799dab..cd9bad8d6 100644 --- a/src/phy/mod.rs +++ b/src/phy/mod.rs @@ -29,7 +29,7 @@ struct StmPhy { tx_buffer: [u8; 1536], } -impl<'a> StmPhy { +impl StmPhy { fn new() -> StmPhy { StmPhy { rx_buffer: [0; 1536], @@ -38,16 +38,16 @@ impl<'a> StmPhy { } } -impl<'a> phy::Device<'a> for StmPhy { - type RxToken = StmPhyRxToken<'a>; - type TxToken = StmPhyTxToken<'a>; +impl phy::Device for StmPhy { + type RxToken<'a> = StmPhyRxToken<'a>; + type TxToken<'a> = StmPhyTxToken<'a>; - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { Some((StmPhyRxToken(&mut self.rx_buffer[..]), StmPhyTxToken(&mut self.tx_buffer[..]))) } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { Some(StmPhyTxToken(&mut self.tx_buffer[..])) } @@ -308,9 +308,14 @@ impl Default for Medium { /// The interface is based on _tokens_, which are types that allow to receive/transmit a /// single packet. The `receive` and `transmit` functions only construct such tokens, the /// real sending/receiving operation are performed when the tokens are consumed. -pub trait Device<'a> { - type RxToken: RxToken + 'a; - type TxToken: TxToken + 'a; +pub trait Device { + type RxToken<'a>: RxToken + where + Self: 'a; + + type TxToken<'a>: TxToken + where + Self: 'a; /// Construct a token pair consisting of one receive token and one transmit token. /// @@ -318,10 +323,10 @@ pub trait Device<'a> { /// on the contents of the received packet. For example, this makes it possible to /// handle arbitrarily large ICMP echo ("ping") requests, where the all received bytes /// need to be sent back, without heap allocation. - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)>; + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)>; /// Construct a transmit token. - fn transmit(&'a mut self) -> Option; + fn transmit<'a>(&'a mut self) -> Option>; /// Get a description of device capabilities. fn capabilities(&self) -> DeviceCapabilities; diff --git a/src/phy/pcap_writer.rs b/src/phy/pcap_writer.rs index 069e55503..9bacfb01a 100644 --- a/src/phy/pcap_writer.rs +++ b/src/phy/pcap_writer.rs @@ -118,7 +118,7 @@ impl PcapSink for T { #[derive(Debug)] pub struct PcapWriter where - D: for<'a> Device<'a>, + D: Device, S: PcapSink, { lower: D, @@ -126,7 +126,7 @@ where mode: PcapMode, } -impl Device<'a>, S: PcapSink> PcapWriter { +impl PcapWriter { /// Creates a packet capture writer. pub fn new(lower: D, mut sink: S, mode: PcapMode) -> PcapWriter { let medium = lower.capabilities().medium; @@ -162,19 +162,24 @@ impl Device<'a>, S: PcapSink> PcapWriter { } } -impl<'a, D, S> Device<'a> for PcapWriter +impl Device for PcapWriter where - D: for<'b> Device<'b>, - S: PcapSink + 'a, + D: Device, + S: PcapSink, { - type RxToken = RxToken<'a, >::RxToken, S>; - type TxToken = TxToken<'a, >::TxToken, S>; + type RxToken<'a> = RxToken<'a, ::RxToken<'a>, S> + where + Self: 'a; + + type TxToken<'a> = TxToken<'a, ::TxToken<'a>, S> + where + Self: 'a; fn capabilities(&self) -> DeviceCapabilities { self.lower.capabilities() } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { let sink = &self.sink; let mode = self.mode; self.lower.receive().map(move |(rx_token, tx_token)| { @@ -192,7 +197,7 @@ where }) } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { let sink = &self.sink; let mode = self.mode; self.lower diff --git a/src/phy/raw_socket.rs b/src/phy/raw_socket.rs index b760983a5..a5c5b7e97 100644 --- a/src/phy/raw_socket.rs +++ b/src/phy/raw_socket.rs @@ -54,9 +54,9 @@ impl RawSocket { } } -impl<'a> Device<'a> for RawSocket { - type RxToken = RxToken; - type TxToken = TxToken; +impl Device for RawSocket { + type RxToken<'a> = RxToken; + type TxToken<'a> = TxToken; fn capabilities(&self) -> DeviceCapabilities { DeviceCapabilities { @@ -66,7 +66,7 @@ impl<'a> Device<'a> for RawSocket { } } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { let mut lower = self.lower.borrow_mut(); let mut buffer = vec![0; self.mtu]; match lower.recv(&mut buffer[..]) { @@ -83,7 +83,7 @@ impl<'a> Device<'a> for RawSocket { } } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { Some(TxToken { lower: self.lower.clone(), }) diff --git a/src/phy/tracer.rs b/src/phy/tracer.rs index fdf5b1cfc..a28f025e4 100644 --- a/src/phy/tracer.rs +++ b/src/phy/tracer.rs @@ -12,12 +12,12 @@ use crate::{ /// A tracer is a device that pretty prints all packets traversing it /// using the provided writer function, and then passes them to another /// device. -pub struct Tracer Device<'a>> { +pub struct Tracer { inner: D, writer: fn(Instant, Packet), } -impl Device<'a>> Tracer { +impl Tracer { /// Create a tracer device. pub fn new(inner: D, writer: fn(timestamp: Instant, packet: Packet)) -> Tracer { Tracer { inner, writer } @@ -44,18 +44,23 @@ impl Device<'a>> Tracer { } } -impl<'a, D> Device<'a> for Tracer +impl Device for Tracer where - D: for<'b> Device<'b>, + D: Device, { - type RxToken = RxToken<>::RxToken>; - type TxToken = TxToken<>::TxToken>; + type RxToken<'a> = RxToken<::RxToken<'a>> + where + Self: 'a; + + type TxToken<'a> = TxToken<::TxToken<'a>> + where + Self: 'a; fn capabilities(&self) -> DeviceCapabilities { self.inner.capabilities() } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { let &mut Self { ref mut inner, writer, @@ -77,7 +82,7 @@ where }) } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { let &mut Self { ref mut inner, writer, diff --git a/src/phy/tuntap_interface.rs b/src/phy/tuntap_interface.rs index 6792a7be5..3f3466213 100644 --- a/src/phy/tuntap_interface.rs +++ b/src/phy/tuntap_interface.rs @@ -40,9 +40,9 @@ impl TunTapInterface { } } -impl<'a> Device<'a> for TunTapInterface { - type RxToken = RxToken; - type TxToken = TxToken; +impl Device for TunTapInterface { + type RxToken<'a> = RxToken; + type TxToken<'a> = TxToken; fn capabilities(&self) -> DeviceCapabilities { DeviceCapabilities { @@ -52,7 +52,7 @@ impl<'a> Device<'a> for TunTapInterface { } } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive<'a>(&'a mut self) -> Option<(Self::RxToken<'a>, Self::TxToken<'a>)> { let mut lower = self.lower.borrow_mut(); let mut buffer = vec![0; self.mtu]; match lower.recv(&mut buffer[..]) { @@ -69,7 +69,7 @@ impl<'a> Device<'a> for TunTapInterface { } } - fn transmit(&'a mut self) -> Option { + fn transmit<'a>(&'a mut self) -> Option> { Some(TxToken { lower: self.lower.clone(), }) From 8d2c32aa9520aa9bf135f87067d58f6be07a1947 Mon Sep 17 00:00:00 2001 From: Ed Barnard Date: Sat, 22 Oct 2022 15:57:00 +0100 Subject: [PATCH 2/2] [TMP] Run CI on beta --- .github/workflows/clippy.yml | 2 +- .github/workflows/test.yml | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 111b1ef99..f449c483b 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v2 if: github.event_name != 'pull_request_target' - run: sed -n 's,^rust-version = "\(.*\)"$,RUSTUP_TOOLCHAIN=\1,p' Cargo.toml >> $GITHUB_ENV - - run: rustup toolchain install $RUSTUP_TOOLCHAIN + - run: rustup toolchain install beta - run: rustup component add clippy - uses: actions-rs/clippy-check@v1 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 72b3fdbab..3ddba3788 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,8 +20,7 @@ jobs: # Test on stable, MSRV, and nightly. # Failure is permitted on nightly. rust: - - stable - - 1.60.0 + - beta - nightly features: @@ -64,8 +63,7 @@ jobs: # Test on stable, MSRV, and nightly. # Failure is permitted on nightly. rust: - - stable - - 1.60.0 + - beta - nightly features: