Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Pin projections and implement Future (MSRV 1.36) #77

Merged
merged 2 commits into from Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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