Route get supports querying the route tables #23
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Closes #22
This MR adds support for querying the route tables for the best route to a given destination, which as of now only supports dumping all route tables.
Design
The idea behind the design is pretty simple and inspired by what route::add and neighbour::get do: the user gets a
RouteRequest<()>
from the handle, which they must specialize into either aRouteRequest<Ipv4Addr>
orRouteRequest<Ipv6Addr>
by callingv4()
orv6()
before being able to callexecute()
. Once specialized, the user can optionally add a destination address, but only of the same address family as the generic parameter (you can't put a ipv6 destination inRouteRequest<Ipv4Addr>
). Doing this will turn the request into a lookup request instead of dump request.Unfortunately, this design introduces a change to the API for the user, and will require a version bump.
It also adds a new
examples/get_route_to.rs
example to showcase this use case.execute()
opaque return typeWhile writing this PR, I faced a lot of troubles related to opaque types. Like all other requests in this crate,
RouteRequest::execute()
used to return a opaqueimpl TryStream<Ok = RouteMessage, Error = Error>
. This becomes a problem if the user tries to handle ipv4 and ipv6 in a single code path, like so:Because
RouteRequest
is now generic, the return type ofRouteRequest<Ipv4Addr>
andRouteRequest<Ipv6Addr>
are no longer the same concrete type, even though they have the exact same opaque type signature. Because of this, the two match arms differ in type, androutes
cannot have a valid type.The only way I found around this problem is dynamic dispatch, which means asking the user to turn the concrete opaque type returned by
execute()
into aBox<dyn TryStream<...>>
in both match arms. But for that the user has to write the full type signature of the trait, including the associated typeSteam::Item
which is erased in the returned opaque type, and this unprovable constraint makes rustc refuse to compile.I solved this by changing the opaque type returned by
execute()
into a simpler opaqueimpl Stream<Item = Result<...>>
, which automatically implementsTryStream
anyway, so this is transparent for the user.The final solution is
which I'm not super happy about, because it asks the user to write a complicated dyn type.
Another solution would have been to make
RouteRequest
an exception, and haveexecute()
return aBox<Stream<Item = ...>
.