Skip to content
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

util: UdpFramed takes Borrow<UdpSocket> #3451

Merged
merged 3 commits into from
Apr 14, 2021

Conversation

leshow
Copy link
Contributor

@leshow leshow commented Jan 20, 2021

Motivation

This changes UdpFramed from holding a UdpSocket to a Borrow<UdpSocket>.

Often, you will have an Arc<UdpSocket> which you want to share among many tasks but also still be able to use the helper functions from tokio-util. Unfortunately, UdpFramed only takes a UdpSocket.

The disadvantage of this approach is that into_inner and get_mut must be removed, does that seem like an acceptable trade-off for the added flexibility?

edit: into_inner doesn't actually have to be removed, my mistake, only get_mut
edit: get_mut now implemented specifically for UdpFramed<C, UdpSocket>

Possible Solution?

Make UdpFramed take a T: Borrow<UdpSocket> so it can take UdpSocket types generically.

I'm happy to take any feedback or alternate approach that is suggested. But let me take your temperature first on if you think you'd like this change or not?

@Darksonn Darksonn added A-tokio-util Area: The tokio-util crate M-codec Module: tokio-util/codec labels Jan 28, 2021
Comment on lines 37 to 41
pub struct UdpFramed<C> {
socket: UdpSocket,
pub struct UdpFramed<T, C> {
socket: T,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change, and would require a new tokio-util series.

Copy link
Contributor Author

@leshow leshow Jan 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, although I don't see any other way to enable this:

    let a = Arc::new(UdpSocket::bind("127.0.0.1:0").await?);
    let b = Arc::clone(&a);

    let mut recv = UdpFramed::new(a, ByteCodec);
    let mut send = UdpFramed::new(b, ByteCodec);
// possibly move recv/send to different tasks

I think it's a fairly common scenario that you'll have a UdpSocket in an Arc in order to share between different tasks? You may want to have one task doing the sending and one doing the recv'ing for example.

Would it help if it was a new type instead of changing UdpFramed?

edit: Just to make my case a little further. I the old api of taking just UdpSocket made more sense when tokio required &mut self to send/recv. Now that it's &self, I think this API makes more sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be possible to add it with a default as in UdpFramed<C, T = UdpSocket>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll experiment with that and report back. Probably best to switch the type param order as you have there also.

Copy link
Contributor Author

@leshow leshow Mar 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seemed to work. I was also able to add back get_mut by writing an impl block specifically for UdpFramed<C, T> where T: BorrowMut<UdpSocket> since BorrowMut is a parent trait to Borrow it will have access to all the other methods also.

@leshow leshow force-pushed the tokio_util_borrow branch 2 times, most recently from 82ce761 to 57ef66d Compare January 31, 2021 23:21
@leshow leshow force-pushed the tokio_util_borrow branch 2 times, most recently from 327064d to 669cece Compare March 27, 2021 20:31
@Darksonn
Copy link
Contributor

You will probably need to merge or rebase on master to get the fixes for any warnings introduced to Rust after this PR was created.

@leshow
Copy link
Contributor Author

leshow commented Mar 28, 2021

Should be all up to date now.

impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
impl<C, T> Stream for UdpFramed<C, T>
where
T: Borrow<UdpSocket> + Unpin,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need the Unpin bound.

Suggested change
T: Borrow<UdpSocket> + Unpin,
T: Borrow<UdpSocket>,

You can even add an unconditional impl<C, T> Unpin for UdpFramed<C, T> {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That last impl is what I was missing, without it the self.get_mut() line in Stream complains about Unpin. Thanks!

@@ -79,7 +86,7 @@ impl<C: Decoder + Unpin> Stream for UdpFramed<C> {
let buf = &mut *(pin.rd.chunk_mut() as *mut _ as *mut [MaybeUninit<u8>]);
let mut read = ReadBuf::uninit(buf);
let ptr = read.filled().as_ptr();
let res = ready!(Pin::new(&mut pin.socket).poll_recv_from(cx, &mut read));
let res = ready!(Pin::new(&mut pin.socket.borrow()).poll_recv_from(cx, &mut read));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let res = ready!(Pin::new(&mut pin.socket.borrow()).poll_recv_from(cx, &mut read));
let res = ready!(pin.socket.borrow().poll_recv_from(cx, &mut read));

Comment on lines 105 to 106
T: Borrow<UdpSocket> + Unpin,
C: Encoder<I> + Unpin,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, you don't need Unpin here.

Suggested change
T: Borrow<UdpSocket> + Unpin,
C: Encoder<I> + Unpin,
T: Borrow<UdpSocket>,
C: Encoder<I>,

Copy link
Contributor Author

@leshow leshow Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added these and the above changes manually, I just want to call out that the previous bound was C: Encoder<I> + Unpin so we are removing an existing Unpin bound also, same with C: Decoder + Unpin

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, well, there should not have been any Unpin bounds in this file in the first place.

Comment on lines 194 to 197
/// with.
pub fn get_mut(&mut self) -> &mut UdpSocket {
&mut self.socket
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove get_mut, it becomes a breaking change. Maybe return &mut T here, then change get_ref to return &T for consistency.

Edit: I just noticed the get_mut impl further down. Not sure what I like best tbh.

Copy link
Contributor Author

@leshow leshow Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with either, I used .borrow() and .borrow_mut() because I thought it may be a breaking change if it returned &T and a user updated, all of a sudden you have to call .borrow() additionally on that to get a &UdpSocket?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, any existing users would have T = UdpSocket, so if we return &T, that's an &UdpSocket, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default param was a recent addition that changes things, good point. Okay, I've updated it to return the type params.

@leshow leshow force-pushed the tokio_util_borrow branch 2 times, most recently from 0cf146b to d5b492c Compare April 13, 2021 14:48
@Darksonn Darksonn merged commit 9eeec03 into tokio-rs:master Apr 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio-util Area: The tokio-util crate M-codec Module: tokio-util/codec
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants