Skip to content

Commit

Permalink
Merge pull request #77 from cuviper/pin-future
Browse files Browse the repository at this point in the history
Add `Pin` projections and implement `Future` (MSRV 1.36)
  • Loading branch information
cuviper committed Aug 17, 2022
2 parents fad7d3a + a966956 commit 0e11249
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 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
4 changes: 2 additions & 2 deletions Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "either"
version = "1.7.0"
version = "1.8.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
13 changes: 12 additions & 1 deletion README.rst
Expand Up @@ -25,12 +25,23 @@ __ https://docs.rs/either/
How to use with cargo::

[dependencies]
either = "1.7"
either = "1.8"


Recent Changes
--------------

- 1.8.0

- **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)

- Specialize more methods of the ``io`` traits, by @Kixunil and @cuviper (#75)

- 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 0e11249

Please sign in to comment.