diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 05:05:12 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 05:05:12 +0000 |
commit | e9ccf85a641d4a42b6531de096793f2dcf287c49 (patch) | |
tree | b41a1a87aa97c4c3843626857341baf2b2efbd96 | |
parent | 2e7c47d1b0739ba28172e8fda8a53bdf52e1c948 (diff) | |
parent | 7e3c0a894f738ce95a88a71128bd9d9ecdc03456 (diff) | |
download | either-e9ccf85a641d4a42b6531de096793f2dcf287c49.tar.gz |
Snap for 10453563 from 7e3c0a894f738ce95a88a71128bd9d9ecdc03456 to mainline-os-statsd-releaseaml_sta_341710000aml_sta_341615000aml_sta_341511040aml_sta_341410000aml_sta_341311010aml_sta_341114000aml_sta_341111000aml_sta_341010020aml_sta_340912000aml_sta_340911000aml_net_341111030android14-mainline-os-statsd-release
Change-Id: I26b361e1dd6a45b6e19155addf84facb734d731e
-rw-r--r-- | .cargo_vcs_info.json | 7 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 61 | ||||
-rw-r--r-- | .travis.yml | 33 | ||||
-rw-r--r-- | Android.bp | 16 | ||||
-rw-r--r-- | Cargo.toml | 36 | ||||
-rw-r--r-- | Cargo.toml.orig | 6 | ||||
-rw-r--r-- | METADATA | 14 | ||||
-rw-r--r-- | README.rst | 47 | ||||
-rw-r--r-- | TEST_MAPPING | 33 | ||||
-rw-r--r-- | src/lib.rs | 441 | ||||
-rw-r--r-- | src/serde_untagged.rs | 12 | ||||
-rw-r--r-- | src/serde_untagged_optional.rs | 12 |
12 files changed, 557 insertions, 161 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 1a91ec1..b119b58 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "6d3216446d4828d9fa254a6952b40408fbc9c9bd" - } -} + "sha1": "b0d9a95738ac536240cf3688f67a863afda81295" + }, + "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 @@ -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.1", 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,20 @@ rust_library { host_supported: true, crate_name: "either", cargo_env_compat: true, - cargo_pkg_version: "1.6.1", + cargo_pkg_version: "1.8.1", srcs: ["src/lib.rs"], - edition: "2015", + edition: "2018", features: [ "default", "use_std", ], + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + product_available: true, + vendor_available: true, } -//Non fatal errors: +// Errors when listing tests: // error: test @@ -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.1" 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"] -license = "MIT/Apache-2.0" +keywords = [ + "data-structure", + "no_std", +] +categories = [ + "data-structures", + "no-std", +] +license = "MIT OR 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..a2768f1 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,9 +1,11 @@ [package] name = "either" -version = "1.6.1" +version = "1.8.1" authors = ["bluss"] +edition = "2018" +rust-version = "1.36" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/bluss/either" documentation = "https://docs.rs/either/1/" readme = "README-crates.io.md" @@ -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.1.crate" } - version: "1.6.1" + version: "1.8.1" license_type: NOTICE last_upgrade_date { - year: 2020 - month: 12 - day: 21 + year: 2023 + month: 2 + day: 15 } } @@ -16,21 +16,56 @@ __ 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.1 + + - Clarified that the multiple licenses are combined with OR. + +- 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 +158,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/TEST_MAPPING b/TEST_MAPPING index de3ad0a..fa9201f 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -5,6 +5,9 @@ "path": "external/rust/crates/base64" }, { + "path": "external/rust/crates/hashbrown" + }, + { "path": "external/rust/crates/libsqlite3-sys" }, { @@ -15,40 +18,28 @@ }, { "path": "external/rust/crates/unicode-xid" - } - ], - "presubmit": [ - { - "name": "apkdmverity.test" }, { - "name": "either_test_src_lib" + "path": "packages/modules/Virtualization/apkdmverity" }, { - "name": "keystore2_test" + "path": "packages/modules/Virtualization/microdroid_manager" }, { - "name": "legacykeystore_test" + "path": "system/security/keystore2" }, { - "name": "microdroid_manager_test" + "path": "system/security/keystore2/legacykeystore" } ], - "presubmit-rust": [ - { - "name": "apkdmverity.test" - }, + "presubmit": [ { "name": "either_test_src_lib" - }, - { - "name": "keystore2_test" - }, - { - "name": "legacykeystore_test" - }, + } + ], + "presubmit-rust": [ { - "name": "microdroid_manager_test" + "name": "either_test_src_lib" } ] } @@ -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<L, R> { /// A value of type `L`. Left(L), @@ -55,11 +54,36 @@ pub enum Either<L, R> { 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<String, &'static str>) -> 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<u32, &str>) -> Either<u32, &str> { -/// 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<L: Clone, R: Clone> Clone for Either<L, R> { + 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<L, R> Either<L, R> { /// Return true if the value is the `Left` variant. /// @@ -217,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>`. /// /// ``` @@ -388,6 +457,7 @@ impl<L, R> Either<L, R> { /// 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<L::IntoIter, R::IntoIter> where L: IntoIterator, @@ -558,7 +628,7 @@ impl<L, R> Either<L, R> { /// ``` 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<L, R> Either<L, R> { /// ``` 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<L, R> Either<L, R> { /// ``` 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<L, R> Either<L, R> { /// ``` 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<u16, u32> = Left(3u16); + /// assert_eq!(left.either_into::<u64>(), 3u64); + /// let right: Either<u16, u32> = Right(7u32); + /// assert_eq!(right.either_into::<u64>(), 7u64); + /// ``` + pub fn either_into<T>(self) -> T + where + L: Into<T>, + R: Into<T>, + { + match self { + Either::Left(l) => l.into(), + Either::Right(r) => r.into(), + } + } +} + +impl<L, R> Either<Option<L>, Option<R>> { + /// Factors out `None` from an `Either` of [`Option`]. + /// + /// ``` + /// use either::*; + /// let left: Either<_, Option<String>> = Left(Some(vec![0])); + /// assert_eq!(left.factor_none(), Some(Left(vec![0]))); + /// + /// let right: Either<Option<Vec<u8>>, _> = 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<Either<L, R>> { + match self { + Left(l) => l.map(Either::Left), + Right(r) => r.map(Either::Right), + } + } +} + +impl<L, R, E> Either<Result<L, E>, Result<R, E>> { + /// 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<String, u32>> = Left(Ok(vec![0])); + /// assert_eq!(left.factor_err(), Ok(Left(vec![0]))); + /// + /// let right: Either<Result<Vec<u8>, 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<Either<L, R>, E> { + match self { + Left(l) => l.map(Either::Left), + Right(r) => r.map(Either::Right), + } + } +} + +impl<T, L, R> Either<Result<T, L>, Result<T, R>> { + /// 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<u32, String>> = Left(Err(vec![0])); + /// assert_eq!(left.factor_ok(), Err(Left(vec![0]))); + /// + /// let right: Either<Result<u32, Vec<u8>>, _> = 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<T, Either<L, R>> { + match self { + Left(l) => l.map_err(Either::Left), + Right(r) => r.map_err(Either::Right), + } + } } impl<T, L, R> Either<(T, L), (T, R)> { @@ -711,7 +871,7 @@ impl<T> Either<T, T> { /// 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<L, R> From<Result<R, L>> for Either<L, R> { } /// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`. +#[allow(clippy::from_over_into)] // From requires RFC 2451, Rust 1.41 impl<L, R> Into<Result<R, L>> for Either<L, R> { fn into(self) -> Result<R, L> { match self { @@ -765,7 +926,7 @@ where where T: IntoIterator<Item = A>, { - 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<Self::Item> { - either!(*self, ref mut inner => inner.next()) + for_both!(*self, ref mut inner => inner.next()) } fn size_hint(&self) -> (usize, Option<usize>) { - either!(*self, ref inner => inner.size_hint()) + for_both!(*self, ref inner => inner.size_hint()) } fn fold<Acc, G>(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<F>(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<Self::Item> { - either!(self, inner => inner.last()) + for_both!(self, inner => inner.last()) } fn nth(&mut self, n: usize) -> Option<Self::Item> { - either!(*self, ref mut inner => inner.nth(n)) + for_both!(*self, ref mut inner => inner.nth(n)) } fn collect<B>(self) -> B where B: iter::FromIterator<Self::Item>, { - either!(self, inner => inner.collect()) + for_both!(self, inner => inner.collect()) + } + + fn partition<B, F>(self, f: F) -> (B, B) + where + B: Default + Extend<Self::Item>, + F: FnMut(&Self::Item) -> bool, + { + for_both!(self, inner => inner.partition(f)) } fn all<F>(&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<F>(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.any(f)) + } + + fn find<P>(&mut self, predicate: P) -> Option<Self::Item> + where + P: FnMut(&Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.find(predicate)) + } + + fn find_map<B, F>(&mut self, f: F) -> Option<B> + where + F: FnMut(Self::Item) -> Option<B>, + { + for_both!(*self, ref mut inner => inner.find_map(f)) + } + + fn position<P>(&mut self, predicate: P) -> Option<usize> + where + P: FnMut(Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.position(predicate)) } } @@ -825,7 +1029,26 @@ where R: DoubleEndedIterator<Item = L::Item>, { fn next_back(&mut self) -> Option<Self::Item> { - 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<Self::Item> { + // for_both!(*self, ref mut inner => inner.nth_back(n)) + // } + + fn rfold<Acc, G>(self, init: Acc, f: G) -> Acc + where + G: FnMut(Acc, Self::Item) -> Acc, + { + for_both!(self, inner => inner.rfold(init, f)) + } + + fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> + where + P: FnMut(&Self::Item) -> bool, + { + for_both!(*self, ref mut inner => inner.rfind(predicate)) } } @@ -834,6 +1057,32 @@ where L: ExactSizeIterator, R: ExactSizeIterator<Item = L::Item>, { + fn len(&self) -> usize { + for_both!(*self, ref inner => inner.len()) + } +} + +impl<L, R> iter::FusedIterator for Either<L, R> +where + L: iter::FusedIterator, + R: iter::FusedIterator<Item = L::Item>, +{ +} + +/// `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"))] @@ -846,11 +1095,33 @@ where R: Read, { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - 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<u8>) -> io::Result<usize> { - 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<u8>) -> io::Result<usize> { + for_both!(*self, ref mut inner => inner.read_to_end(buf)) + } + + fn read_to_string(&mut self, buf: &mut std::string::String) -> io::Result<usize> { + for_both!(*self, ref mut inner => inner.read_to_string(buf)) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either<L, R>` implements `Seek` if both `L` and `R` do. +/// +/// Requires crate feature `"use_std"` +impl<L, R> Seek for Either<L, R> +where + L: Seek, + R: Seek, +{ + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + 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<u8>) -> io::Result<usize> { + for_both!(*self, ref mut inner => inner.read_until(byte, buf)) + } + + fn read_line(&mut self, buf: &mut std::string::String) -> io::Result<usize> { + 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<usize> { - 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<Target>, { 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<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()) } } @@ -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<Target = L::Target>, { 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<u32, u32> { 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<String, &str> = Left(String::from("test")); is_str(&*value); @@ -1065,6 +1359,37 @@ fn iter() { } #[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<String> would suffice, too. //! //! ```rust -//! #[macro_use] -//! extern crate serde; -//! // or `use serde::{Serialize, Deserialize};` in newer rust versions. -//! //! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! 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<L, R> { 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<String> would suffice, too. //! //! ```rust -//! #[macro_use] -//! extern crate serde; -//! // or `use serde::{Serialize, Deserialize};` in newer rust versions. -//! //! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! 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) } |