From c809c87174868d3ad9b894877da35e0bce50e41f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 29 Jul 2022 16:58:13 -0700 Subject: [PATCH] Add `Pin` projections and implement `Future` (MSRV 1.36) --- .github/workflows/ci.yml | 8 +------ Cargo.toml | 2 +- README.rst | 9 ++++++++ src/lib.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 072430f..905cbf5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/Cargo.toml b/Cargo.toml index a5beca5..c95bcdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/README.rst b/README.rst index 992e49c..25b2832 100644 --- a/README.rst +++ b/README.rst @@ -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. diff --git a/src/lib.rs b/src/lib.rs index a4f2a54..b7036b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 Either { } } + /// Convert `Pin<&Either>` to `Either, Pin<&R>>`, + /// pinned projections of the inner variants. + pub fn as_pin_ref(self: Pin<&Self>) -> Either, 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>` to `Either, Pin<&mut R>>`, + /// pinned projections of the inner variants. + pub fn as_pin_mut(self: Pin<&mut Self>) -> Either, 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` to `Either`. /// /// ``` @@ -1038,6 +1069,22 @@ where { } +/// `Either` is a future if both `L` and `R` are futures. +impl Future for Either +where + L: Future, + R: Future, +{ + type Output = L::Output; + + fn poll( + self: Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + for_both!(self.as_pin_mut(), inner => inner.poll(cx)) + } +} + #[cfg(any(test, feature = "use_std"))] /// `Either` implements `Read` if both `L` and `R` do. ///