-
Notifications
You must be signed in to change notification settings - Fork 428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible to dynamic dispatch on Device
trait?
#957
Comments
Is doing something like the following forcing you to write a lot of duplicate code? struct NetInterface<D> {
device: D,
iface: Interface,
sockets: SocketSet<'static>,
} |
I have a similar problem — I'm working on a virtual ethernet switch that operates over a variable number of unknown struct VSwitch<'a, const MAX_DEVICES: usize> {
devices: heapless::Vec<MAX_DEVICES, &'a mut dyn smoltcp::phy::Device>,
} This isn't possible with the current I'm considering a wrapper/"trampoline" trait that impls // These need to wrap the {Rx,Tx}Token traits, which I *think* (hope) can be done
// with a closure -- might be impossible.
struct MyCrateTxToken;
struct MyCrateRxToken;
trait DeviceTrampoline {
fn receive(&mut self, timestamp: Instant) -> Option<(MyCrateRxToken, MyCrateTxToken)>;
fn transmit(&mut self, timestamp: Instant) -> Option<MyCrateTxToken>;
fn capabilities(&self) -> DeviceCapabilities;
}
impl<T> DeviceTrampoline for T
where T: phy::Device {
/* delegate */
}
// Now (I think) I can have:
struct VSwitch<'a, const MAX_DEVICES: usize> {
devices: heapless::Vec<MAX_DEVICES, &'a mut dyn DeviceTrampoline>,
} This feels unfortunate in that I think dynamic dispatch for |
I wrote a proof-of-concept crate that enables this -- My observation in looking at this problem is that the token traits are the obstacle to making trait TxToken {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R {
// ...
}
}
fn use_token(tok: impl TxToken) {
let result = tok.consume(move |buf| {
// ... process frame
buf.len() // some computation over the buffer
});
} The type parameter is easily eliminated if you accept allocation for the sake of argument -- the same functionality can be expressed like this: trait TxToken {
// I want "dyn FnOnce" by value here, but that needs unsized_fn_params.
// FnMut isn't suitable because it unduly restricts the function implementation
// (e.g. we need FnOnce for tx-from-rx semantics in Device::receive)
fn consume(self, f: Box<dyn FnOnce(&mut [u8])>)
// ...
}
}
// Ditto re: unsized_fn_params here
fn use_token(tok: Box<dyn TxToken>) {
let mut result = None;
{
let result = &mut result;
tok.consume(move |buf| {
// ... process frame
*mut result = Some(buf.len()); // some computation over the buffer
});
}
let result = result.unwrap();
} The point being that you can write My crate uses |
I am trying to put different
Device
implementations into something likeBox<dyn Device>
. Moreover, I want to have something looks likeWithout which, I have to write a lot of duplicate codes to support multiple physical network interfaces. However the trait doesn't meet object safe requirements. I wonder if this can be done with some tricks.
The text was updated successfully, but these errors were encountered: