Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 61a42d4bf2b0
Choose a base ref
...
head repository: smoltcp-rs/smoltcp
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: efdde337b912
Choose a head ref
  • 1 commit
  • 1 file changed
  • 1 contributor

Commits on Jul 23, 2019

  1. Restore Session::finish call in socket ref

    Using move semantics allows an Option to keep track of the
    initialization state while satisfying the borrow checker. This replaces
    the functionality that the 'consumed' flag had before. It also retains
    the smaller object size since the Option of a reference can use the
    representation of the null pointer, which is an invalid reference, as a
    niche for the None variant.
    
    Closes: #301
    Approved by: whitequark
    HeroicKatora authored and Homu committed Jul 23, 2019
    Copy the full SHA
    efdde33 View commit details
Showing with 19 additions and 18 deletions.
  1. +19 −18 src/socket/ref_.rs
37 changes: 19 additions & 18 deletions src/socket/ref_.rs
Original file line number Diff line number Diff line change
@@ -32,7 +32,12 @@ impl<'a> Session for TcpSocket<'a> {}
///
/// Allows the network stack to efficiently determine if the socket state was changed in any way.
pub struct Ref<'a, T: Session + 'a> {
socket: &'a mut T
/// Reference to the socket.
///
/// This is almost always `Some` except when dropped in `into_inner` which removes the socket
/// reference. This properly tracks the initialization state without any additional bytes as
/// the `None` variant occupies the `0` pattern which is invalid for the reference.
socket: Option<&'a mut T>,
}

impl<'a, T: Session + 'a> Ref<'a, T> {
@@ -42,7 +47,7 @@ impl<'a, T: Session + 'a> Ref<'a, T> {
///
/// [into_inner]: #method.into_inner
pub fn new(socket: &'a mut T) -> Self {
Ref { socket }
Ref { socket: Some(socket) }
}

/// Unwrap a smart pointer to a socket.
@@ -55,34 +60,30 @@ impl<'a, T: Session + 'a> Ref<'a, T> {
/// be sure to call [new] afterwards.
///
/// [new]: #method.new
pub fn into_inner(ref_: Self) -> &'a mut T {
ref_.socket
pub fn into_inner(mut ref_: Self) -> &'a mut T {
ref_.socket.take().unwrap()
}
}

impl<'a, T: Session> Deref for Ref<'a, T> {
type Target = T;

fn deref(&self) -> &Self::Target {
self.socket
// Deref is only used while the socket is still in place (into inner has not been called).
self.socket.as_ref().unwrap()
}
}

impl<'a, T: Session> DerefMut for Ref<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.socket
self.socket.as_mut().unwrap()
}
}

// FIXME: `Session::finish` currently does not do anything, but if it did, this would be a problem,
// because `SocketRef::into_inner` would have to use unsafe code, and there's currently no unsafe
// code in smoltcp at all (other than the `phy` module). The reason it would need unsafe code is
// that it is currently an error to destructure a value that implements Drop (or move out its
// fields in any other way), so it'd have to be transmuted away. This is a deficiency in Rust:
// it is always safe to ignore the Drop impl during destructuring.
//
// impl<'a, T: Session> Drop for Ref<'a, T> {
// fn drop(&mut self) {
// Session::finish(self.socket);
// }
// }
impl<'a, T: Session> Drop for Ref<'a, T> {
fn drop(&mut self) {
if let Some(socket) = self.socket.take() {
Session::finish(socket);
}
}
}