Search code examples
rustrust-tokio

Difference between `tokio::pin!` and `std::pin::pin!`?


I originally thought the former was just a re-export of the latter but looks like that's not the case. What's the difference between the two pin! macros and how does one go about deciding which one to use?


Solution

  • tokio::pin!() is older, so if you need to support a version of Rust older than 1.68.0, you must use it or a similar macro from an alternative crate (e.g. futures::pin_mut!()).

    The main difference is than std's pin!() is more comfortable and more convenient. All third-party pin!() macros one of the two forms:

    pin!(let mut variable = value);
    
    // or
    
    let variable = todo!();
    pin!(variable);
    

    (Often with convenient features, such as declaring multiple variables in one macro call). While std's pin!() has the form:

    let mut variable = pin!(value);
    

    Besides being better looking (this looks more like a function call than a custom macro), it also has the unique capability to be placed in any expression position, e.g. in function calls:

    foo(pin!(value));
    

    Although if the function's return value borrows from the pinned place, this won't compile.

    Std exploits its special status to do that. Other than it, no crate can create such macro that will be usable in both variable declarations and expressions (although two separate macros could be created). So crates opted to just provide only the former.