Skip to content

Commit

Permalink
Add Pin projections and implement Future (MSRV 1.36)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuviper committed Jul 30, 2022
1 parent 39cec17 commit c809c87
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 8 deletions.
8 changes: 1 addition & 7 deletions .github/workflows/ci.yml
Expand Up @@ -13,7 +13,7 @@ jobs:
fail-fast: false
matrix:
rust:
- 1.31.0 # MSRV
- 1.36.0 # MSRV
- stable
- beta
- nightly
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -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"
Expand Down
9 changes: 9 additions & 0 deletions README.rst
Expand Up @@ -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.
Expand Down
47 changes: 47 additions & 0 deletions src/lib.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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>`.
///
/// ```
Expand Down Expand Up @@ -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.
///
Expand Down

0 comments on commit c809c87

Please sign in to comment.