Add Pin projections and implement Future (MSRV 1.36)

This commit is contained in:
Josh Stone 2022-07-29 16:58:13 -07:00
parent fad7d3ae64
commit b136420e40
4 changed files with 58 additions and 8 deletions

View File

@ -13,7 +13,7 @@ jobs:
fail-fast: false
matrix:
rust:
- 1.31.0 # MSRV
- 1.36.0 # MSRV
- stable
- beta
- nightly
@ -30,12 +30,6 @@ jobs:
with:
toolchain: ${{ matrix.rust }}
- name: (1.31.0) Downgrade serde_json
if: ${{ matrix.rust == '1.31.0' }}
run: |
cargo generate-lockfile
cargo update -p serde_json --precise 1.0.39
- name: Build (no_std)
run: cargo build --no-default-features

View File

@ -3,7 +3,7 @@ name = "either"
version = "1.7.0"
authors = ["bluss"]
edition = "2018"
rust-version = "1.31"
rust-version = "1.36"
license = "MIT/Apache-2.0"
repository = "https://github.com/bluss/either"

View File

@ -31,6 +31,15 @@ How to use with cargo::
Recent Changes
--------------
- UNRELEASED
- **MSRV**: ``either`` now requires Rust 1.36 or later.
- Add new methods ``.as_pin_ref()`` and ``.as_pin_mut()`` to project a
pinned ``Either`` as inner ``Pin`` variants, by @cuviper (#77)
- Implement the ``Future`` trait, by @cuviper (#77)
- 1.7.0
- **MSRV**: ``either`` now requires Rust 1.31 or later.

View File

@ -26,9 +26,11 @@ pub mod serde_untagged_optional;
use core::convert::{AsMut, AsRef};
use core::fmt;
use core::future::Future;
use core::iter;
use core::ops::Deref;
use core::ops::DerefMut;
use core::pin::Pin;
#[cfg(any(test, feature = "use_std"))]
use std::error::Error;
@ -255,6 +257,35 @@ impl<L, R> Either<L, R> {
}
}
/// Convert `Pin<&Either<L, R>>` to `Either<Pin<&L>, Pin<&R>>`,
/// pinned projections of the inner variants.
pub fn as_pin_ref(self: Pin<&Self>) -> Either<Pin<&L>, Pin<&R>> {
// SAFETY: We can use `new_unchecked` because the `inner` parts are
// guaranteed to be pinned, as they come from `self` which is pinned.
unsafe {
match *Pin::get_ref(self) {
Left(ref inner) => Left(Pin::new_unchecked(inner)),
Right(ref inner) => Right(Pin::new_unchecked(inner)),
}
}
}
/// Convert `Pin<&mut Either<L, R>>` to `Either<Pin<&mut L>, Pin<&mut R>>`,
/// pinned projections of the inner variants.
pub fn as_pin_mut(self: Pin<&mut Self>) -> Either<Pin<&mut L>, Pin<&mut R>> {
// SAFETY: `get_unchecked_mut` is fine because we don't move anything.
// We can use `new_unchecked` because the `inner` parts are guaranteed
// to be pinned, as they come from `self` which is pinned, and we never
// offer an unpinned `&mut L` or `&mut R` through `Pin<&mut Self>`. We
// also don't have an implementation of `Drop`, nor manual `Unpin`.
unsafe {
match *Pin::get_unchecked_mut(self) {
Left(ref mut inner) => Left(Pin::new_unchecked(inner)),
Right(ref mut inner) => Right(Pin::new_unchecked(inner)),
}
}
}
/// Convert `Either<L, R>` to `Either<R, L>`.
///
/// ```
@ -1038,6 +1069,22 @@ where
{
}
/// `Either<L, R>` is a future if both `L` and `R` are futures.
impl<L, R> Future for Either<L, R>
where
L: Future,
R: Future<Output = L::Output>,
{
type Output = L::Output;
fn poll(
self: Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
for_both!(self.as_pin_mut(), inner => inner.poll(cx))
}
}
#[cfg(any(test, feature = "use_std"))]
/// `Either<L, R>` implements `Read` if both `L` and `R` do.
///