Skip to content

Commit cf45e77

Browse files
committed
GAT-based Device trait.
The current `'a` lifetime in the `Device` trait is essentially a workaround for lack of GATs. I'm just experimenting how this would look like, it'll have to wait until GATs are stable to go in. The main benefit is structs implementing `Device` can now borrow stuff. This wasn't possible before because the `for<'d> T: Device<'d>` bounds would essentially imply `T: 'static`.
1 parent 0dfe66b commit cf45e77

14 files changed

+105
-85
lines changed

.github/workflows/test.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
on:
22
push:
3-
branches: [ staging, trying ]
3+
branches: [staging, trying]
44
pull_request:
55

66
name: Test
@@ -20,8 +20,8 @@ jobs:
2020
# Test on stable, MSRV 1.46, and nightly.
2121
# Failure is permitted on nightly.
2222
rust:
23-
- stable
24-
- 1.56.0
23+
#- stable
24+
#- 1.56.0
2525
- nightly
2626

2727
features:
@@ -67,8 +67,8 @@ jobs:
6767
# Test on stable, MSRV 1.46, and nightly.
6868
# Failure is permitted on nightly.
6969
rust:
70-
- stable
71-
- 1.56.0
70+
#- stable
71+
#- 1.56.0
7272
- nightly
7373

7474
features:

examples/dhcp_client.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,7 @@ fn main() {
9494
}
9595
}
9696

97-
fn set_ipv4_addr<DeviceT>(iface: &mut Interface<'_, DeviceT>, cidr: Ipv4Cidr)
98-
where
99-
DeviceT: for<'d> Device<'d>,
100-
{
97+
fn set_ipv4_addr<DeviceT: Device>(iface: &mut Interface<'_, DeviceT>, cidr: Ipv4Cidr) {
10198
iface.update_ip_addrs(|addrs| {
10299
let dest = addrs.iter_mut().next().unwrap();
103100
*dest = IpCidr::Ipv4(cidr);

examples/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ pub fn parse_middleware_options<D>(
159159
loopback: bool,
160160
) -> FaultInjector<Tracer<PcapWriter<D, Box<dyn io::Write>>>>
161161
where
162-
D: for<'a> Device<'a>,
162+
D: Device,
163163
{
164164
let drop_chance = matches
165165
.opt_str("drop-chance")

fuzz/utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ pub fn parse_middleware_options<D>(
9393
loopback: bool,
9494
) -> FaultInjector<Tracer<PcapWriter<D, Box<dyn Write>>>>
9595
where
96-
D: for<'a> Device<'a>,
96+
D: Device,
9797
{
9898
let drop_chance = matches
9999
.opt_str("drop-chance")

src/iface/interface.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{Error, Result};
1919
/// The network interface logically owns a number of other data structures; to avoid
2020
/// a dependency on heap allocation, it instead owns a `BorrowMut<[T]>`, which can be
2121
/// a `&mut [T]`, or `Vec<T>` if a heap is available.
22-
pub struct Interface<'a, DeviceT: for<'d> Device<'d>> {
22+
pub struct Interface<'a, DeviceT: Device> {
2323
device: DeviceT,
2424
sockets: SocketSet<'a>,
2525
inner: InterfaceInner<'a>,
@@ -53,7 +53,7 @@ struct InterfaceInner<'a> {
5353
}
5454

5555
/// A builder structure used for creating a network interface.
56-
pub struct InterfaceBuilder<'a, DeviceT: for<'d> Device<'d>> {
56+
pub struct InterfaceBuilder<'a, DeviceT: Device> {
5757
device: DeviceT,
5858
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
5959
hardware_addr: Option<HardwareAddress>,
@@ -73,10 +73,7 @@ pub struct InterfaceBuilder<'a, DeviceT: for<'d> Device<'d>> {
7373
ipv4_multicast_groups: ManagedMap<'a, Ipv4Address, ()>,
7474
}
7575

76-
impl<'a, DeviceT> InterfaceBuilder<'a, DeviceT>
77-
where
78-
DeviceT: for<'d> Device<'d>,
79-
{
76+
impl<'a, DeviceT: Device> InterfaceBuilder<'a, DeviceT> {
8077
/// Create a builder used for creating a network interface using the
8178
/// given device and address.
8279
#[cfg_attr(
@@ -465,10 +462,7 @@ enum IgmpReportState {
465462
},
466463
}
467464

468-
impl<'a, DeviceT> Interface<'a, DeviceT>
469-
where
470-
DeviceT: for<'d> Device<'d>,
471-
{
465+
impl<'a, DeviceT: Device> Interface<'a, DeviceT> {
472466
/// Add a socket to the interface, and return its handle.
473467
///
474468
/// # Panics

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
),
88
deny(unused)
99
)]
10+
#![feature(generic_associated_types)]
1011

1112
//! The _smoltcp_ library is built in a layered structure, with the layers corresponding
1213
//! to the levels of API abstraction. Only the highest layers would be used by a typical

src/phy/fault_injector.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,13 @@ impl State {
9494
/// adverse network conditions (such as random packet loss or corruption), or software
9595
/// or hardware limitations (such as a limited number or size of usable network buffers).
9696
#[derive(Debug)]
97-
pub struct FaultInjector<D: for<'a> Device<'a>> {
97+
pub struct FaultInjector<D: Device> {
9898
inner: D,
9999
state: RefCell<State>,
100100
config: Config,
101101
}
102102

103-
impl<D: for<'a> Device<'a>> FaultInjector<D> {
103+
impl<D: Device> FaultInjector<D> {
104104
/// Create a fault injector device, using the given random number generator seed.
105105
pub fn new(inner: D, seed: u32) -> FaultInjector<D> {
106106
let state = State {
@@ -195,12 +195,15 @@ impl<D: for<'a> Device<'a>> FaultInjector<D> {
195195
}
196196
}
197197

198-
impl<'a, D> Device<'a> for FaultInjector<D>
199-
where
200-
D: for<'b> Device<'b>,
201-
{
202-
type RxToken = RxToken<'a, <D as Device<'a>>::RxToken>;
203-
type TxToken = TxToken<'a, <D as Device<'a>>::TxToken>;
198+
impl<D: Device> Device for FaultInjector<D> {
199+
type RxToken<'a>
200+
where
201+
Self: 'a,
202+
= RxToken<'a, D::RxToken<'a>>;
203+
type TxToken<'a>
204+
where
205+
Self: 'a,
206+
= TxToken<'a, D::TxToken<'a>>;
204207

205208
fn capabilities(&self) -> DeviceCapabilities {
206209
let mut caps = self.inner.capabilities();
@@ -210,7 +213,7 @@ where
210213
caps
211214
}
212215

213-
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
216+
fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
214217
let &mut Self {
215218
ref mut inner,
216219
ref state,
@@ -233,7 +236,7 @@ where
233236
})
234237
}
235238

236-
fn transmit(&'a mut self) -> Option<Self::TxToken> {
239+
fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
237240
let &mut Self {
238241
ref mut inner,
239242
ref state,

src/phy/fuzz_injector.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ pub trait Fuzzer {
1919
#[allow(unused)]
2020
#[derive(Debug)]
2121
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22-
pub struct FuzzInjector<D: for<'a> Device<'a>, FTx: Fuzzer, FRx: Fuzzer> {
22+
pub struct FuzzInjector<D: Device, FTx: Fuzzer, FRx: Fuzzer> {
2323
inner: D,
2424
fuzz_tx: FTx,
2525
fuzz_rx: FRx,
2626
}
2727

2828
#[allow(unused)]
29-
impl<D: for<'a> Device<'a>, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector<D, FTx, FRx> {
29+
impl<D: Device, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector<D, FTx, FRx> {
3030
/// Create a fuzz injector device.
3131
pub fn new(inner: D, fuzz_tx: FTx, fuzz_rx: FRx) -> FuzzInjector<D, FTx, FRx> {
3232
FuzzInjector {
@@ -42,14 +42,19 @@ impl<D: for<'a> Device<'a>, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector<D, FTx, FRx>
4242
}
4343
}
4444

45-
impl<'a, D, FTx, FRx> Device<'a> for FuzzInjector<D, FTx, FRx>
45+
impl<D: Device, FTx, FRx> Device for FuzzInjector<D, FTx, FRx>
4646
where
47-
D: for<'b> Device<'b>,
48-
FTx: Fuzzer + 'a,
49-
FRx: Fuzzer + 'a,
47+
FTx: Fuzzer,
48+
FRx: Fuzzer,
5049
{
51-
type RxToken = RxToken<'a, <D as Device<'a>>::RxToken, FRx>;
52-
type TxToken = TxToken<'a, <D as Device<'a>>::TxToken, FTx>;
50+
type RxToken<'a>
51+
where
52+
Self: 'a,
53+
= RxToken<'a, D::RxToken<'a>, FRx>;
54+
type TxToken<'a>
55+
where
56+
Self: 'a,
57+
= TxToken<'a, D::TxToken<'a>, FTx>;
5358

5459
fn capabilities(&self) -> DeviceCapabilities {
5560
let mut caps = self.inner.capabilities();
@@ -59,7 +64,7 @@ where
5964
caps
6065
}
6166

62-
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
67+
fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
6368
let &mut Self {
6469
ref mut inner,
6570
ref fuzz_rx,
@@ -78,7 +83,7 @@ where
7883
})
7984
}
8085

81-
fn transmit(&'a mut self) -> Option<Self::TxToken> {
86+
fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
8287
let &mut Self {
8388
ref mut inner,
8489
fuzz_rx: _,

src/phy/loopback.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ impl Loopback {
2929
}
3030
}
3131

32-
impl<'a> Device<'a> for Loopback {
33-
type RxToken = RxToken;
34-
type TxToken = TxToken<'a>;
32+
impl Device for Loopback {
33+
type RxToken<'a> = RxToken;
34+
type TxToken<'a> = TxToken<'a>;
3535

3636
fn capabilities(&self) -> DeviceCapabilities {
3737
DeviceCapabilities {
@@ -41,7 +41,7 @@ impl<'a> Device<'a> for Loopback {
4141
}
4242
}
4343

44-
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
44+
fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
4545
self.queue.pop_front().map(move |buffer| {
4646
let rx = RxToken { buffer };
4747
let tx = TxToken {
@@ -51,7 +51,7 @@ impl<'a> Device<'a> for Loopback {
5151
})
5252
}
5353

54-
fn transmit(&'a mut self) -> Option<Self::TxToken> {
54+
fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
5555
Some(TxToken {
5656
queue: &mut self.queue,
5757
})

src/phy/mod.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ An implementation of the [Device](trait.Device.html) trait for a simple hardware
2020
Ethernet controller could look as follows:
2121
2222
```rust
23+
# #![feature(generic_associated_types)]
24+
2325
use smoltcp::Result;
2426
use smoltcp::phy::{self, DeviceCapabilities, Device, Medium};
2527
use smoltcp::time::Instant;
@@ -38,16 +40,16 @@ impl<'a> StmPhy {
3840
}
3941
}
4042
41-
impl<'a> phy::Device<'a> for StmPhy {
42-
type RxToken = StmPhyRxToken<'a>;
43-
type TxToken = StmPhyTxToken<'a>;
43+
impl phy::Device for StmPhy {
44+
type RxToken<'a> where Self: 'a = StmPhyRxToken<'a>;
45+
type TxToken<'a> where Self: 'a = StmPhyTxToken<'a>;
4446
45-
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
47+
fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
4648
Some((StmPhyRxToken(&mut self.rx_buffer[..]),
4749
StmPhyTxToken(&mut self.tx_buffer[..])))
4850
}
4951
50-
fn transmit(&'a mut self) -> Option<Self::TxToken> {
52+
fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
5153
Some(StmPhyTxToken(&mut self.tx_buffer[..]))
5254
}
5355
@@ -312,20 +314,24 @@ impl Default for Medium {
312314
/// The interface is based on _tokens_, which are types that allow to receive/transmit a
313315
/// single packet. The `receive` and `transmit` functions only construct such tokens, the
314316
/// real sending/receiving operation are performed when the tokens are consumed.
315-
pub trait Device<'a> {
316-
type RxToken: RxToken + 'a;
317-
type TxToken: TxToken + 'a;
317+
pub trait Device {
318+
type RxToken<'a>: RxToken
319+
where
320+
Self: 'a;
321+
type TxToken<'a>: TxToken
322+
where
323+
Self: 'a;
318324

319325
/// Construct a token pair consisting of one receive token and one transmit token.
320326
///
321327
/// The additional transmit token makes it possible to generate a reply packet based
322328
/// on the contents of the received packet. For example, this makes it possible to
323329
/// handle arbitrarily large ICMP echo ("ping") requests, where the all received bytes
324330
/// need to be sent back, without heap allocation.
325-
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)>;
331+
fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>;
326332

327333
/// Construct a transmit token.
328-
fn transmit(&'a mut self) -> Option<Self::TxToken>;
334+
fn transmit(&mut self) -> Option<Self::TxToken<'_>>;
329335

330336
/// Get a description of device capabilities.
331337
fn capabilities(&self) -> DeviceCapabilities;

src/phy/pcap_writer.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,15 @@ impl<T: Write> PcapSink for T {
118118
#[derive(Debug)]
119119
pub struct PcapWriter<D, S>
120120
where
121-
D: for<'a> Device<'a>,
121+
D: Device,
122122
S: PcapSink,
123123
{
124124
lower: D,
125125
sink: RefCell<S>,
126126
mode: PcapMode,
127127
}
128128

129-
impl<D: for<'a> Device<'a>, S: PcapSink> PcapWriter<D, S> {
129+
impl<D: Device, S: PcapSink> PcapWriter<D, S> {
130130
/// Creates a packet capture writer.
131131
pub fn new(lower: D, mut sink: S, mode: PcapMode) -> PcapWriter<D, S> {
132132
let medium = lower.capabilities().medium;
@@ -162,19 +162,24 @@ impl<D: for<'a> Device<'a>, S: PcapSink> PcapWriter<D, S> {
162162
}
163163
}
164164

165-
impl<'a, D, S> Device<'a> for PcapWriter<D, S>
165+
impl<D: Device, S> Device for PcapWriter<D, S>
166166
where
167-
D: for<'b> Device<'b>,
168-
S: PcapSink + 'a,
167+
S: PcapSink,
169168
{
170-
type RxToken = RxToken<'a, <D as Device<'a>>::RxToken, S>;
171-
type TxToken = TxToken<'a, <D as Device<'a>>::TxToken, S>;
169+
type RxToken<'a>
170+
where
171+
Self: 'a,
172+
= RxToken<'a, D::RxToken<'a>, S>;
173+
type TxToken<'a>
174+
where
175+
Self: 'a,
176+
= TxToken<'a, D::TxToken<'a>, S>;
172177

173178
fn capabilities(&self) -> DeviceCapabilities {
174179
self.lower.capabilities()
175180
}
176181

177-
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
182+
fn receive(&mut self) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
178183
let sink = &self.sink;
179184
let mode = self.mode;
180185
self.lower.receive().map(move |(rx_token, tx_token)| {
@@ -192,7 +197,7 @@ where
192197
})
193198
}
194199

195-
fn transmit(&'a mut self) -> Option<Self::TxToken> {
200+
fn transmit(&mut self) -> Option<Self::TxToken<'_>> {
196201
let sink = &self.sink;
197202
let mode = self.mode;
198203
self.lower

0 commit comments

Comments
 (0)