From 3325f3a49af51de0c2fc03448fda0683468511d1 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 9 Dec 2022 11:42:03 +0100 Subject: Upgrade either to 1.8.0 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/either For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: I5812348e7f89c81eecbe33dca322b24a19f19094 --- .cargo_vcs_info.json | 7 +- .github/workflows/ci.yml | 61 ++++++ .travis.yml | 33 --- Android.bp | 14 +- Cargo.toml | 34 +++- Cargo.toml.orig | 4 +- METADATA | 12 +- README.rst | 43 +++- src/lib.rs | 441 +++++++++++++++++++++++++++++++++++------ src/serde_untagged.rs | 12 +- src/serde_untagged_optional.rs | 12 +- 11 files changed, 536 insertions(+), 137 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 1a91ec1..5b9e1d5 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "6d3216446d4828d9fa254a6952b40408fbc9c9bd" - } -} + "sha1": "0e1124933c4d6a6ded1ad6137c70c69e23a9d22f" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..905cbf5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +name: CI + +jobs: + ci: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: + - 1.36.0 # MSRV + - stable + - beta + - nightly + features: + - "" + - "serde" + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + + - name: Build (no_std) + run: cargo build --no-default-features + + - name: Build + run: cargo build --features "${{ matrix.features }}" + + - name: Test + run: cargo test --features "${{ matrix.features }}" + + - name: Doc + run: cargo doc --features "${{ matrix.features }}" + + clippy: + name: Rustfmt and Clippy + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up nightly Rust + uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt, clippy + + - name: Rustfmt + run: cargo fmt --all -- --check + + - name: Clippy + run: cargo clippy # -- -D warnings diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f3a3024..0000000 --- a/.travis.yml +++ /dev/null @@ -1,33 +0,0 @@ -language: rust -sudo: false - -# run builds for all the trains (and more) -rust: - - stable - - beta - - nightly - -branches: - only: - - master -# the main build -script: - - | - cargo build --features "${FEATURES}" && - cargo test --features "${FEATURES}" && - cargo doc --features "${FEATURES}" - -env: - matrix: - - FEATURES="" - - FEATURES="serde" - -matrix: - include: - - rust: 1.12.0 - env: FEATURES="" - before_script: - - | - cargo generate-lockfile && - cargo update -p serde_json --precise 1.0.0 && - cargo update -p serde --precise 1.0.0 diff --git a/Android.bp b/Android.bp index 1cbd146..4bd81e9 100644 --- a/Android.bp +++ b/Android.bp @@ -42,14 +42,14 @@ rust_test { host_supported: true, crate_name: "either", cargo_env_compat: true, - cargo_pkg_version: "1.6.1", + cargo_pkg_version: "1.8.0", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, test_options: { unit_test: true, }, - edition: "2015", + edition: "2018", features: [ "default", "use_std", @@ -64,14 +64,18 @@ rust_library { host_supported: true, crate_name: "either", cargo_env_compat: true, - cargo_pkg_version: "1.6.1", + cargo_pkg_version: "1.8.0", srcs: ["src/lib.rs"], - edition: "2015", + edition: "2018", features: [ "default", "use_std", ], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], } -//Non fatal errors: +// Errors when listing tests: // error: test diff --git a/Cargo.toml b/Cargo.toml index ccf747b..eb1c5b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,34 +3,46 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] +edition = "2018" +rust-version = "1.36" name = "either" -version = "1.6.1" +version = "1.8.0" authors = ["bluss"] -description = "The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases.\n" +description = """ +The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases. +""" documentation = "https://docs.rs/either/1/" readme = "README-crates.io.md" -keywords = ["data-structure", "no_std"] -categories = ["data-structures", "no-std"] +keywords = [ + "data-structure", + "no_std", +] +categories = [ + "data-structures", + "no-std", +] license = "MIT/Apache-2.0" repository = "https://github.com/bluss/either" -[package.metadata.docs.rs] -features = ["serde"] [package.metadata.release] no-dev-version = true tag-name = "{{version}}" + +[package.metadata.docs.rs] +features = ["serde"] + [dependencies.serde] version = "1.0" features = ["derive"] optional = true + [dev-dependencies.serde_json] version = "1.0.0" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 5797caf..5d4c933 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,7 +1,9 @@ [package] name = "either" -version = "1.6.1" +version = "1.8.0" authors = ["bluss"] +edition = "2018" +rust-version = "1.36" license = "MIT/Apache-2.0" repository = "https://github.com/bluss/either" diff --git a/METADATA b/METADATA index 58f339d..5140042 100644 --- a/METADATA +++ b/METADATA @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/either +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "either" description: "The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases." third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/either/either-1.6.1.crate" + value: "https://static.crates.io/crates/either/either-1.8.0.crate" } - version: "1.6.1" + version: "1.8.0" license_type: NOTICE last_upgrade_date { - year: 2020 + year: 2022 month: 12 - day: 21 + day: 9 } } diff --git a/README.rst b/README.rst index 38d3920..43c156a 100644 --- a/README.rst +++ b/README.rst @@ -16,21 +16,52 @@ __ https://docs.rs/either/ |build_status|_ |crates|_ -.. |build_status| image:: https://travis-ci.org/bluss/either.svg?branch=master -.. _build_status: https://travis-ci.org/bluss/either +.. |build_status| image:: https://github.com/bluss/either/workflows/CI/badge.svg?branch=master +.. _build_status: https://github.com/bluss/either/actions -.. |crates| image:: http://meritbadge.herokuapp.com/either +.. |crates| image:: https://img.shields.io/crates/v/either.svg .. _crates: https://crates.io/crates/either How to use with cargo:: [dependencies] - either = "1.6" + 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. + + - Export the macro ``for_both!``, by @thomaseizinger (#58) + + - Implement the ``io::Seek`` trait, by @Kerollmops (#60) + + - Add new method ``.either_into()`` for ``Into`` conversion, by @TonalidadeHidrica (#63) + + - Add new methods ``.factor_ok()``, ``.factor_err()``, and ``.factor_none()``, + by @zachs18 (#67) + + - Specialize ``source`` in the ``Error`` implementation, by @thomaseizinger (#69) + + - Specialize more iterator methods and implement the ``FusedIterator`` trait, + by @Ten0 (#66) and @cuviper (#71) + + - Specialize ``Clone::clone_from``, by @cuviper (#72) + - 1.6.1 - Add new methods ``.expect_left()``, ``.unwrap_left()``, @@ -123,7 +154,7 @@ License Dual-licensed to be compatible with the Rust project. Licensed under the Apache License, Version 2.0 -http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -http://opensource.org/licenses/MIT, at your +https://www.apache.org/licenses/LICENSE-2.0 or the MIT license +https://opensource.org/licenses/MIT, at your option. This file may not be copied, modified, or distributed except according to those terms. diff --git a/src/lib.rs b/src/lib.rs index 3ef249f..9a271c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,13 +13,10 @@ //! #![doc(html_root_url = "https://docs.rs/either/1/")] -#![cfg_attr(all(not(test), not(feature = "use_std")), no_std)] -#[cfg(all(not(test), not(feature = "use_std")))] -extern crate core as std; +#![no_std] -#[cfg(feature = "serde")] -#[macro_use] -extern crate serde; +#[cfg(any(test, feature = "use_std"))] +extern crate std; #[cfg(feature = "serde")] pub mod serde_untagged; @@ -27,18 +24,20 @@ pub mod serde_untagged; #[cfg(feature = "serde")] pub mod serde_untagged_optional; -use std::convert::{AsMut, AsRef}; -use std::fmt; -use std::iter; -use std::ops::Deref; -use std::ops::DerefMut; +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; #[cfg(any(test, feature = "use_std"))] -use std::io::{self, BufRead, Read, Write}; +use std::io::{self, BufRead, Read, Seek, SeekFrom, Write}; -pub use Either::{Left, Right}; +pub use crate::Either::{Left, Right}; /// The enum `Either` with variants `Left` and `Right` is a general purpose /// sum type with two cases. @@ -46,8 +45,8 @@ pub use Either::{Left, Right}; /// The `Either` type is symmetric and treats its variants the same way, without /// preference. /// (For representing success or error, use the regular `Result` enum instead.) -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum Either { /// A value of type `L`. Left(L), @@ -55,11 +54,36 @@ pub enum Either { Right(R), } -macro_rules! either { +/// Evaluate the provided expression for both [`Either::Left`] and [`Either::Right`]. +/// +/// This macro is useful in cases where both sides of [`Either`] can be interacted with +/// in the same way even though the don't share the same type. +/// +/// Syntax: `either::for_both!(` *expression* `,` *pattern* `=>` *expression* `)` +/// +/// # Example +/// +/// ``` +/// use either::Either; +/// +/// fn length(owned_or_borrowed: Either) -> usize { +/// either::for_both!(owned_or_borrowed, s => s.len()) +/// } +/// +/// fn main() { +/// let borrowed = Either::Right("Hello world!"); +/// let owned = Either::Left("Hello world!".to_owned()); +/// +/// assert_eq!(length(borrowed), 12); +/// assert_eq!(length(owned), 12); +/// } +/// ``` +#[macro_export] +macro_rules! for_both { ($value:expr, $pattern:pat => $result:expr) => { match $value { - Either::Left($pattern) => $result, - Either::Right($pattern) => $result, + $crate::Either::Left($pattern) => $result, + $crate::Either::Right($pattern) => $result, } }; } @@ -74,11 +98,10 @@ macro_rules! either { /// # Example /// /// ``` -/// #[macro_use] extern crate either; /// use either::{Either, Left, Right}; /// /// fn twice(wrapper: Either) -> Either { -/// let value = try_left!(wrapper); +/// let value = either::try_left!(wrapper); /// Left(value * 2) /// } /// @@ -92,7 +115,7 @@ macro_rules! try_left { ($expr:expr) => { match $expr { $crate::Left(val) => val, - $crate::Right(err) => return $crate::Right(::std::convert::From::from(err)), + $crate::Right(err) => return $crate::Right(::core::convert::From::from(err)), } }; } @@ -102,12 +125,29 @@ macro_rules! try_left { macro_rules! try_right { ($expr:expr) => { match $expr { - $crate::Left(err) => return $crate::Left(::std::convert::From::from(err)), + $crate::Left(err) => return $crate::Left(::core::convert::From::from(err)), $crate::Right(val) => val, } }; } +impl Clone for Either { + fn clone(&self) -> Self { + match self { + Left(inner) => Left(inner.clone()), + Right(inner) => Right(inner.clone()), + } + } + + fn clone_from(&mut self, source: &Self) { + match (self, source) { + (Left(dest), Left(source)) => dest.clone_from(source), + (Right(dest), Right(source)) => dest.clone_from(source), + (dest, source) => *dest = source.clone(), + } + } +} + impl Either { /// Return true if the value is the `Left` variant. /// @@ -217,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`. /// /// ``` @@ -388,6 +457,7 @@ impl Either { /// right.extend(left.into_iter()); /// assert_eq!(right, Right(vec![1, 2, 3, 4, 5])); /// ``` + #[allow(clippy::should_implement_trait)] pub fn into_iter(self) -> Either where L: IntoIterator, @@ -558,7 +628,7 @@ impl Either { /// ``` pub fn unwrap_left(self) -> L where - R: std::fmt::Debug, + R: core::fmt::Debug, { match self { Either::Left(l) => l, @@ -589,7 +659,7 @@ impl Either { /// ``` pub fn unwrap_right(self) -> R where - L: std::fmt::Debug, + L: core::fmt::Debug, { match self { Either::Right(r) => r, @@ -618,7 +688,7 @@ impl Either { /// ``` pub fn expect_left(self, msg: &str) -> L where - R: std::fmt::Debug, + R: core::fmt::Debug, { match self { Either::Left(l) => l, @@ -647,13 +717,103 @@ impl Either { /// ``` pub fn expect_right(self, msg: &str) -> R where - L: std::fmt::Debug, + L: core::fmt::Debug, { match self { Either::Right(r) => r, Either::Left(l) => panic!("{}: {:?}", msg, l), } } + + /// Convert the contained value into `T` + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// // Both u16 and u32 can be converted to u64. + /// let left: Either = Left(3u16); + /// assert_eq!(left.either_into::(), 3u64); + /// let right: Either = Right(7u32); + /// assert_eq!(right.either_into::(), 7u64); + /// ``` + pub fn either_into(self) -> T + where + L: Into, + R: Into, + { + match self { + Either::Left(l) => l.into(), + Either::Right(r) => r.into(), + } + } +} + +impl Either, Option> { + /// Factors out `None` from an `Either` of [`Option`]. + /// + /// ``` + /// use either::*; + /// let left: Either<_, Option> = Left(Some(vec![0])); + /// assert_eq!(left.factor_none(), Some(Left(vec![0]))); + /// + /// let right: Either>, _> = Right(Some(String::new())); + /// assert_eq!(right.factor_none(), Some(Right(String::new()))); + /// ``` + // TODO(MSRV): doc(alias) was stabilized in Rust 1.48 + // #[doc(alias = "transpose")] + pub fn factor_none(self) -> Option> { + match self { + Left(l) => l.map(Either::Left), + Right(r) => r.map(Either::Right), + } + } +} + +impl Either, Result> { + /// Factors out a homogenous type from an `Either` of [`Result`]. + /// + /// Here, the homogeneous type is the `Err` type of the [`Result`]. + /// + /// ``` + /// use either::*; + /// let left: Either<_, Result> = Left(Ok(vec![0])); + /// assert_eq!(left.factor_err(), Ok(Left(vec![0]))); + /// + /// let right: Either, u32>, _> = Right(Ok(String::new())); + /// assert_eq!(right.factor_err(), Ok(Right(String::new()))); + /// ``` + // TODO(MSRV): doc(alias) was stabilized in Rust 1.48 + // #[doc(alias = "transpose")] + pub fn factor_err(self) -> Result, E> { + match self { + Left(l) => l.map(Either::Left), + Right(r) => r.map(Either::Right), + } + } +} + +impl Either, Result> { + /// Factors out a homogenous type from an `Either` of [`Result`]. + /// + /// Here, the homogeneous type is the `Ok` type of the [`Result`]. + /// + /// ``` + /// use either::*; + /// let left: Either<_, Result> = Left(Err(vec![0])); + /// assert_eq!(left.factor_ok(), Err(Left(vec![0]))); + /// + /// let right: Either>, _> = Right(Err(String::new())); + /// assert_eq!(right.factor_ok(), Err(Right(String::new()))); + /// ``` + // TODO(MSRV): doc(alias) was stabilized in Rust 1.48 + // #[doc(alias = "transpose")] + pub fn factor_ok(self) -> Result> { + match self { + Left(l) => l.map_err(Either::Left), + Right(r) => r.map_err(Either::Right), + } + } } impl Either<(T, L), (T, R)> { @@ -711,7 +871,7 @@ impl Either { /// assert_eq!(right.into_inner(), 123); /// ``` pub fn into_inner(self) -> T { - either!(self, inner => inner) + for_both!(self, inner => inner) } /// Map `f` over the contained value and return the result in the @@ -747,6 +907,7 @@ impl From> for Either { } /// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`. +#[allow(clippy::from_over_into)] // From requires RFC 2451, Rust 1.41 impl Into> for Either { fn into(self) -> Result { match self { @@ -765,7 +926,7 @@ where where T: IntoIterator, { - either!(*self, ref mut inner => inner.extend(iter)) + for_both!(*self, ref mut inner => inner.extend(iter)) } } @@ -778,44 +939,87 @@ where type Item = L::Item; fn next(&mut self) -> Option { - either!(*self, ref mut inner => inner.next()) + for_both!(*self, ref mut inner => inner.next()) } fn size_hint(&self) -> (usize, Option) { - either!(*self, ref inner => inner.size_hint()) + for_both!(*self, ref inner => inner.size_hint()) } fn fold(self, init: Acc, f: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { - either!(self, inner => inner.fold(init, f)) + for_both!(self, inner => inner.fold(init, f)) + } + + fn for_each(self, f: F) + where + F: FnMut(Self::Item), + { + for_both!(self, inner => inner.for_each(f)) } fn count(self) -> usize { - either!(self, inner => inner.count()) + for_both!(self, inner => inner.count()) } fn last(self) -> Option { - either!(self, inner => inner.last()) + for_both!(self, inner => inner.last()) } fn nth(&mut self, n: usize) -> Option { - either!(*self, ref mut inner => inner.nth(n)) + for_both!(*self, ref mut inner => inner.nth(n)) } fn collect(self) -> B where B: iter::FromIterator, { - either!(self, inner => inner.collect()) + for_both!(self, inner => inner.collect()) + } + + fn partition(self, f: F) -> (B, B) + where + B: Default + Extend, + F: FnMut(&Self::Item) -> bool, + { + for_both!(self, inner => inner.partition(f)) } fn all(&mut self, f: F) -> bool where F: FnMut(Self::Item) -> bool, { - either!(*self, ref mut inner => inner.all(f)) + for_both!(*self, ref mut inner => inner.all(f)) + } + + fn any(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.any(f)) + } + + fn find

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.find(predicate)) + } + + fn find_map(&mut self, f: F) -> Option + where + F: FnMut(Self::Item) -> Option, + { + for_both!(*self, ref mut inner => inner.find_map(f)) + } + + fn position

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.position(predicate)) } } @@ -825,7 +1029,26 @@ where R: DoubleEndedIterator, { fn next_back(&mut self) -> Option { - either!(*self, ref mut inner => inner.next_back()) + for_both!(*self, ref mut inner => inner.next_back()) + } + + // TODO(MSRV): This was stabilized in Rust 1.37 + // fn nth_back(&mut self, n: usize) -> Option { + // for_both!(*self, ref mut inner => inner.nth_back(n)) + // } + + fn rfold(self, init: Acc, f: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + for_both!(self, inner => inner.rfold(init, f)) + } + + fn rfind

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.rfind(predicate)) } } @@ -834,6 +1057,32 @@ where L: ExactSizeIterator, R: ExactSizeIterator, { + fn len(&self) -> usize { + for_both!(*self, ref inner => inner.len()) + } +} + +impl iter::FusedIterator for Either +where + L: iter::FusedIterator, + R: iter::FusedIterator, +{ +} + +/// `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"))] @@ -846,11 +1095,33 @@ where R: Read, { fn read(&mut self, buf: &mut [u8]) -> io::Result { - either!(*self, ref mut inner => inner.read(buf)) + for_both!(*self, ref mut inner => inner.read(buf)) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - either!(*self, ref mut inner => inner.read_to_end(buf)) + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + for_both!(*self, ref mut inner => inner.read_exact(buf)) + } + + fn read_to_end(&mut self, buf: &mut std::vec::Vec) -> io::Result { + for_both!(*self, ref mut inner => inner.read_to_end(buf)) + } + + fn read_to_string(&mut self, buf: &mut std::string::String) -> io::Result { + for_both!(*self, ref mut inner => inner.read_to_string(buf)) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Seek` if both `L` and `R` do. +/// +/// Requires crate feature `"use_std"` +impl Seek for Either +where + L: Seek, + R: Seek, +{ + fn seek(&mut self, pos: SeekFrom) -> io::Result { + for_both!(*self, ref mut inner => inner.seek(pos)) } } @@ -862,11 +1133,19 @@ where R: BufRead, { fn fill_buf(&mut self) -> io::Result<&[u8]> { - either!(*self, ref mut inner => inner.fill_buf()) + for_both!(*self, ref mut inner => inner.fill_buf()) } fn consume(&mut self, amt: usize) { - either!(*self, ref mut inner => inner.consume(amt)) + for_both!(*self, ref mut inner => inner.consume(amt)) + } + + fn read_until(&mut self, byte: u8, buf: &mut std::vec::Vec) -> io::Result { + for_both!(*self, ref mut inner => inner.read_until(byte, buf)) + } + + fn read_line(&mut self, buf: &mut std::string::String) -> io::Result { + for_both!(*self, ref mut inner => inner.read_line(buf)) } } @@ -880,11 +1159,19 @@ where R: Write, { fn write(&mut self, buf: &[u8]) -> io::Result { - either!(*self, ref mut inner => inner.write(buf)) + for_both!(*self, ref mut inner => inner.write(buf)) + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + for_both!(*self, ref mut inner => inner.write_all(buf)) + } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + for_both!(*self, ref mut inner => inner.write_fmt(fmt)) } fn flush(&mut self) -> io::Result<()> { - either!(*self, ref mut inner => inner.flush()) + for_both!(*self, ref mut inner => inner.flush()) } } @@ -894,7 +1181,7 @@ where R: AsRef, { fn as_ref(&self) -> &Target { - either!(*self, ref inner => inner.as_ref()) + for_both!(*self, ref inner => inner.as_ref()) } } @@ -905,7 +1192,7 @@ macro_rules! impl_specific_ref_and_mut { where L: AsRef<$t>, R: AsRef<$t> { fn as_ref(&self) -> &$t { - either!(*self, ref inner => inner.as_ref()) + for_both!(*self, ref inner => inner.as_ref()) } } @@ -914,7 +1201,7 @@ macro_rules! impl_specific_ref_and_mut { where L: AsMut<$t>, R: AsMut<$t> { fn as_mut(&mut self) -> &mut $t { - either!(*self, ref mut inner => inner.as_mut()) + for_both!(*self, ref mut inner => inner.as_mut()) } } }; @@ -943,7 +1230,7 @@ where R: AsRef<[Target]>, { fn as_ref(&self) -> &[Target] { - either!(*self, ref inner => inner.as_ref()) + for_both!(*self, ref inner => inner.as_ref()) } } @@ -953,7 +1240,7 @@ where R: AsMut, { fn as_mut(&mut self) -> &mut Target { - either!(*self, ref mut inner => inner.as_mut()) + for_both!(*self, ref mut inner => inner.as_mut()) } } @@ -963,7 +1250,7 @@ where R: AsMut<[Target]>, { fn as_mut(&mut self) -> &mut [Target] { - either!(*self, ref mut inner => inner.as_mut()) + for_both!(*self, ref mut inner => inner.as_mut()) } } @@ -975,7 +1262,7 @@ where type Target = L::Target; fn deref(&self) -> &Self::Target { - either!(*self, ref inner => &*inner) + for_both!(*self, ref inner => &**inner) } } @@ -985,7 +1272,7 @@ where R: DerefMut, { fn deref_mut(&mut self) -> &mut Self::Target { - either!(*self, ref mut inner => &mut *inner) + for_both!(*self, ref mut inner => &mut *inner) } } @@ -996,15 +1283,18 @@ where L: Error, R: Error, { + fn source(&self) -> Option<&(dyn Error + 'static)> { + for_both!(*self, ref inner => inner.source()) + } + #[allow(deprecated)] fn description(&self) -> &str { - either!(*self, ref inner => inner.description()) + for_both!(*self, ref inner => inner.description()) } #[allow(deprecated)] - #[allow(unknown_lints, bare_trait_objects)] - fn cause(&self) -> Option<&Error> { - either!(*self, ref inner => inner.cause()) + fn cause(&self) -> Option<&dyn Error> { + for_both!(*self, ref inner => inner.cause()) } } @@ -1013,8 +1303,8 @@ where L: fmt::Display, R: fmt::Display, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - either!(*self, ref inner => inner.fmt(f)) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for_both!(*self, ref inner => inner.fmt(f)) } } @@ -1033,6 +1323,8 @@ fn basic() { #[test] fn macros() { + use std::string::String; + fn a() -> Either { let x: u32 = try_left!(Right(1337u32)); Left(x * 2) @@ -1047,6 +1339,8 @@ fn macros() { #[test] fn deref() { + use std::string::String; + fn is_str(_: &str) {} let value: Either = Left(String::from("test")); is_str(&*value); @@ -1064,6 +1358,37 @@ fn iter() { assert_eq!(iter.count(), 9); } +#[test] +fn seek() { + use std::io; + + let use_empty = false; + let mut mockdata = [0x00; 256]; + for i in 0..256 { + mockdata[i] = i as u8; + } + + let mut reader = if use_empty { + // Empty didn't impl Seek until Rust 1.51 + Left(io::Cursor::new([])) + } else { + Right(io::Cursor::new(&mockdata[..])) + }; + + let mut buf = [0u8; 16]; + assert_eq!(reader.read(&mut buf).unwrap(), buf.len()); + assert_eq!(buf, mockdata[..buf.len()]); + + // the first read should advance the cursor and return the next 16 bytes thus the `ne` + assert_eq!(reader.read(&mut buf).unwrap(), buf.len()); + assert_ne!(buf, mockdata[..buf.len()]); + + // if the seek operation fails it should read 16..31 instead of 0..15 + reader.seek(io::SeekFrom::Start(0)).unwrap(); + assert_eq!(reader.read(&mut buf).unwrap(), buf.len()); + assert_eq!(buf, mockdata[..buf.len()]); +} + #[test] fn read_write() { use std::io; diff --git a/src/serde_untagged.rs b/src/serde_untagged.rs index 20de074..72078c3 100644 --- a/src/serde_untagged.rs +++ b/src/serde_untagged.rs @@ -6,15 +6,11 @@ //! but in typical cases Vec would suffice, too. //! //! ```rust -//! #[macro_use] -//! extern crate serde; -//! // or `use serde::{Serialize, Deserialize};` in newer rust versions. -//! //! # fn main() -> Result<(), Box> { //! use either::Either; //! use std::collections::HashMap; //! -//! #[derive(Serialize, Deserialize, Debug)] +//! #[derive(serde::Serialize, serde::Deserialize, Debug)] //! #[serde(transparent)] //! struct IntOrString { //! #[serde(with = "either::serde_untagged")] @@ -39,7 +35,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[derive(Serialize, Deserialize)] +#[derive(serde::Serialize, serde::Deserialize)] #[serde(untagged)] enum Either { Left(L), @@ -53,8 +49,8 @@ where R: Serialize, { let untagged = match this { - &super::Either::Left(ref left) => Either::Left(left), - &super::Either::Right(ref right) => Either::Right(right), + super::Either::Left(left) => Either::Left(left), + super::Either::Right(right) => Either::Right(right), }; untagged.serialize(serializer) } diff --git a/src/serde_untagged_optional.rs b/src/serde_untagged_optional.rs index f0cca36..fb3239a 100644 --- a/src/serde_untagged_optional.rs +++ b/src/serde_untagged_optional.rs @@ -6,15 +6,11 @@ //! but in typical cases Vec would suffice, too. //! //! ```rust -//! #[macro_use] -//! extern crate serde; -//! // or `use serde::{Serialize, Deserialize};` in newer rust versions. -//! //! # fn main() -> Result<(), Box> { //! use either::Either; //! use std::collections::HashMap; //! -//! #[derive(Serialize, Deserialize, Debug)] +//! #[derive(serde::Serialize, serde::Deserialize, Debug)] //! #[serde(transparent)] //! struct IntOrString { //! #[serde(with = "either::serde_untagged_optional")] @@ -56,9 +52,9 @@ where R: Serialize, { let untagged = match this { - &Some(super::Either::Left(ref left)) => Some(Either::Left(left)), - &Some(super::Either::Right(ref right)) => Some(Either::Right(right)), - &None => None, + Some(super::Either::Left(left)) => Some(Either::Left(left)), + Some(super::Either::Right(right)) => Some(Either::Right(right)), + None => None, }; untagged.serialize(serializer) } -- cgit v1.2.3