From b76fe52023bca883083472b5dd47e337ff5c3551 Mon Sep 17 00:00:00 2001 From: komorebi-yaodong <1693324937@qq.com> Date: Tue, 4 Jul 2023 10:37:54 +0800 Subject: [PATCH] feat: add rust-either src Log: This metapackage enables feature "serde" for the Rust either crate, by pulling in any additional dependencies needed by that feature. Issue: https://github.com/deepin-community/sig-deepin-sysdev-team/issues/64 Task: https://github.com/deepin-community/sig-deepin-sysdev-team/issues/5 Influence: rust-either src would be added. --- .cargo_vcs_info.json | 5 + .gitignore | 2 + .travis.yml | 33 + Cargo.toml | 39 + Cargo.toml.orig | 33 + LICENSE-APACHE | 201 +++ LICENSE-MIT | 25 + README-crates.io.md | 10 + README.md | 130 +- README.rst | 129 ++ debian/cargo-checksum.json | 1 + debian/changelog | 13 +- debian/compat | 2 +- debian/control | 69 +- debian/copyright | 48 +- debian/copyright.debcargo.hint | 49 + debian/debcargo.toml | 2 + ...librust-either+serde-dev.lintian-overrides | 1 + debian/rules | 3 +- debian/tests/control | 24 + debian/watch | 4 + src/lib.rs | 1146 +++++++++++++++++ src/serde_untagged.rs | 73 ++ src/serde_untagged_optional.rs | 78 ++ 24 files changed, 2083 insertions(+), 37 deletions(-) create mode 100644 .cargo_vcs_info.json create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Cargo.toml create mode 100644 Cargo.toml.orig create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README-crates.io.md create mode 100644 README.rst create mode 100644 debian/cargo-checksum.json create mode 100644 debian/copyright.debcargo.hint create mode 100644 debian/debcargo.toml create mode 100644 debian/librust-either+serde-dev.lintian-overrides create mode 100644 debian/tests/control create mode 100644 debian/watch create mode 100644 src/lib.rs create mode 100644 src/serde_untagged.rs create mode 100644 src/serde_untagged_optional.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..1a91ec1 --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "6d3216446d4828d9fa254a6952b40408fbc9c9bd" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f3a3024 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,33 @@ +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/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ccf747b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# 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 +# +# 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) + +[package] +name = "either" +version = "1.6.1" +authors = ["bluss"] +description = "The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases.\n" +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" +repository = "https://github.com/bluss/either" +[package.metadata.docs.rs] +features = ["serde"] + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true +[dev-dependencies.serde_json] +version = "1.0.0" + +[features] +default = ["use_std"] +use_std = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..5797caf --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,33 @@ +[package] +name = "either" +version = "1.6.1" +authors = ["bluss"] + +license = "MIT/Apache-2.0" +repository = "https://github.com/bluss/either" +documentation = "https://docs.rs/either/1/" +readme = "README-crates.io.md" + +description = """ +The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases. +""" + +keywords = ["data-structure", "no_std"] +categories = ["data-structures", "no-std"] + +[dependencies] +serde = { version = "1.0", optional = true, features = ["derive"] } + +[features] +default = ["use_std"] +use_std = [] + +[dev-dependencies] +serde_json = "1.0.0" + +[package.metadata.release] +no-dev-version = true +tag-name = "{{version}}" + +[package.metadata.docs.rs] +features = ["serde"] diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..9203baa --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README-crates.io.md b/README-crates.io.md new file mode 100644 index 0000000..d368902 --- /dev/null +++ b/README-crates.io.md @@ -0,0 +1,10 @@ +The enum `Either` with variants `Left` and `Right` is a general purpose +sum type with two cases. + +Either has methods that are similar to Option and Result, and it also implements +traits like `Iterator`. + +Includes macros `try_left!()` and `try_right!()` to use for +short-circuiting logic, similar to how the `?` operator is used with `Result`. +Note that `Either` is general purpose. For describing success or error, use the +regular `Result`. diff --git a/README.md b/README.md index 9ebb840..38d3920 100644 --- a/README.md +++ b/README.md @@ -1 +1,129 @@ -# template-repository \ No newline at end of file + +Either +====== + +The enum ``Either`` with variants ``Left`` and ``Right`` and trait +implementations including Iterator, Read, Write. + +Either has methods that are similar to Option and Result. + +Includes convenience macros ``try_left!()`` and ``try_right!()`` to use for +short-circuiting logic. + +Please read the `API documentation here`__ + +__ 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 + +.. |crates| image:: http://meritbadge.herokuapp.com/either +.. _crates: https://crates.io/crates/either + +How to use with cargo:: + + [dependencies] + either = "1.6" + + +Recent Changes +-------------- + +- 1.6.1 + + - Add new methods ``.expect_left()``, ``.unwrap_left()``, + and equivalents on the right, by @spenserblack (#51) + +- 1.6.0 + + - Add new modules ``serde_untagged`` and ``serde_untagged_optional`` to customize + how ``Either`` fields are serialized in other types, by @MikailBag (#49) + +- 1.5.3 + + - Add new method ``.map()`` for ``Either`` by @nvzqz (#40). + +- 1.5.2 + + - Add new methods ``.left_or()``, ``.left_or_default()``, ``.left_or_else()``, + and equivalents on the right, by @DCjanus (#36) + +- 1.5.1 + + - Add ``AsRef`` and ``AsMut`` implementations for common unsized types: + ``str``, ``[T]``, ``CStr``, ``OsStr``, and ``Path``, by @mexus (#29) + +- 1.5.0 + + - Add new methods ``.factor_first()``, ``.factor_second()`` and ``.into_inner()`` + by @mathstuf (#19) + +- 1.4.0 + + - Add inherent method ``.into_iter()`` by @cuviper (#12) + +- 1.3.0 + + - Add opt-in serde support by @hcpl + +- 1.2.0 + + - Add method ``.either_with()`` by @Twey (#13) + +- 1.1.0 + + - Add methods ``left_and_then``, ``right_and_then`` by @rampantmonkey + - Include license files in the repository and released crate + +- 1.0.3 + + - Add crate categories + +- 1.0.2 + + - Forward more ``Iterator`` methods + - Implement ``Extend`` for ``Either`` if ``L, R`` do. + +- 1.0.1 + + - Fix ``Iterator`` impl for ``Either`` to forward ``.fold()``. + +- 1.0.0 + + - Add default crate feature ``use_std`` so that you can opt out of linking to + std. + +- 0.1.7 + + - Add methods ``.map_left()``, ``.map_right()`` and ``.either()``. + - Add more documentation + +- 0.1.3 + + - Implement Display, Error + +- 0.1.2 + + - Add macros ``try_left!`` and ``try_right!``. + +- 0.1.1 + + - Implement Deref, DerefMut + +- 0.1.0 + + - Initial release + - Support Iterator, Read, Write + +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 +option. This file may not be copied, modified, or distributed +except according to those terms. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..38d3920 --- /dev/null +++ b/README.rst @@ -0,0 +1,129 @@ + +Either +====== + +The enum ``Either`` with variants ``Left`` and ``Right`` and trait +implementations including Iterator, Read, Write. + +Either has methods that are similar to Option and Result. + +Includes convenience macros ``try_left!()`` and ``try_right!()`` to use for +short-circuiting logic. + +Please read the `API documentation here`__ + +__ 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 + +.. |crates| image:: http://meritbadge.herokuapp.com/either +.. _crates: https://crates.io/crates/either + +How to use with cargo:: + + [dependencies] + either = "1.6" + + +Recent Changes +-------------- + +- 1.6.1 + + - Add new methods ``.expect_left()``, ``.unwrap_left()``, + and equivalents on the right, by @spenserblack (#51) + +- 1.6.0 + + - Add new modules ``serde_untagged`` and ``serde_untagged_optional`` to customize + how ``Either`` fields are serialized in other types, by @MikailBag (#49) + +- 1.5.3 + + - Add new method ``.map()`` for ``Either`` by @nvzqz (#40). + +- 1.5.2 + + - Add new methods ``.left_or()``, ``.left_or_default()``, ``.left_or_else()``, + and equivalents on the right, by @DCjanus (#36) + +- 1.5.1 + + - Add ``AsRef`` and ``AsMut`` implementations for common unsized types: + ``str``, ``[T]``, ``CStr``, ``OsStr``, and ``Path``, by @mexus (#29) + +- 1.5.0 + + - Add new methods ``.factor_first()``, ``.factor_second()`` and ``.into_inner()`` + by @mathstuf (#19) + +- 1.4.0 + + - Add inherent method ``.into_iter()`` by @cuviper (#12) + +- 1.3.0 + + - Add opt-in serde support by @hcpl + +- 1.2.0 + + - Add method ``.either_with()`` by @Twey (#13) + +- 1.1.0 + + - Add methods ``left_and_then``, ``right_and_then`` by @rampantmonkey + - Include license files in the repository and released crate + +- 1.0.3 + + - Add crate categories + +- 1.0.2 + + - Forward more ``Iterator`` methods + - Implement ``Extend`` for ``Either`` if ``L, R`` do. + +- 1.0.1 + + - Fix ``Iterator`` impl for ``Either`` to forward ``.fold()``. + +- 1.0.0 + + - Add default crate feature ``use_std`` so that you can opt out of linking to + std. + +- 0.1.7 + + - Add methods ``.map_left()``, ``.map_right()`` and ``.either()``. + - Add more documentation + +- 0.1.3 + + - Implement Display, Error + +- 0.1.2 + + - Add macros ``try_left!`` and ``try_right!``. + +- 0.1.1 + + - Implement Deref, DerefMut + +- 0.1.0 + + - Initial release + - Support Iterator, Read, Write + +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 +option. This file may not be copied, modified, or distributed +except according to those terms. diff --git a/debian/cargo-checksum.json b/debian/cargo-checksum.json new file mode 100644 index 0000000..29676fc --- /dev/null +++ b/debian/cargo-checksum.json @@ -0,0 +1 @@ +{"package":"e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457","files":{}} diff --git a/debian/changelog b/debian/changelog index bad88e2..733d343 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,12 @@ -template-repository (1.0-1) unstable; urgency=medium +rust-either (1.6.1-1) unstable; urgency=medium - * Initial release + * Team upload. + * Package either 1.6.1 from crates.io using debcargo 2.5.0 - -- Tsic404 Sat, 28 Jan 2023 13:46:49 +0800 + -- Carlos F. Sanz Sun, 06 Feb 2022 19:48:41 +0100 + +rust-either (1.5.0-1) unstable; urgency=medium + + * Package either 1.5.0 from crates.io using debcargo 2.1.1 + + -- Ximin Luo Sat, 23 Jun 2018 11:38:27 -0700 diff --git a/debian/compat b/debian/compat index b4de394..48082f7 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -11 +12 diff --git a/debian/control b/debian/control index cb7c4a0..e85c1c2 100644 --- a/debian/control +++ b/debian/control @@ -1,15 +1,58 @@ -Source: template-repository -Section: unknown +Source: rust-either +Section: rust Priority: optional -Maintainer: Tsic404 -Build-Depends: debhelper (>= 11) -Standards-Version: 4.1.3 -Homepage: https://github.com/deepin-community/template-repository -#Vcs-Browser: https://salsa.debian.org/debian/deepin-community-template-repository -#Vcs-Git: https://salsa.debian.org/debian/deepin-community-template-repository.git - -Package: template-repository +Build-Depends: debhelper (>= 12), + dh-cargo (>= 25), + cargo:native , + rustc:native , + libstd-rust-dev +Maintainer: Debian Rust Maintainers +Uploaders: + Ximin Luo +Standards-Version: 4.5.1 +Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/either] +Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/either +Rules-Requires-Root: no + +# FIXME (packages."(name)".section) debcargo auto-generated summary for librust-either-dev is very long, consider overriding + +Package: librust-either-dev +Architecture: any +Multi-Arch: same +Depends: + ${misc:Depends} +Suggests: + librust-either+serde-dev (= ${binary:Version}) +Provides: + librust-either+default-dev (= ${binary:Version}), + librust-either+use-std-dev (= ${binary:Version}), + librust-either-1-dev (= ${binary:Version}), + librust-either-1+default-dev (= ${binary:Version}), + librust-either-1+use-std-dev (= ${binary:Version}), + librust-either-1.6-dev (= ${binary:Version}), + librust-either-1.6+default-dev (= ${binary:Version}), + librust-either-1.6+use-std-dev (= ${binary:Version}), + librust-either-1.6.1-dev (= ${binary:Version}), + librust-either-1.6.1+default-dev (= ${binary:Version}), + librust-either-1.6.1+use-std-dev (= ${binary:Version}) +Description: Enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases - Rust source code + This package contains the source for the Rust either crate, packaged by + debcargo for use with cargo and dh-cargo. + +# FIXME (packages."(name)".section) debcargo auto-generated summary for librust-either+serde-dev is very long, consider overriding + +Package: librust-either+serde-dev Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: - +Multi-Arch: same +Depends: + ${misc:Depends}, + librust-either-dev (= ${binary:Version}), + librust-serde-1+default-dev, + librust-serde-1+derive-dev +Provides: + librust-either-1+serde-dev (= ${binary:Version}), + librust-either-1.6+serde-dev (= ${binary:Version}), + librust-either-1.6.1+serde-dev (= ${binary:Version}) +Description: Enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases - feature "serde" + This metapackage enables feature "serde" for the Rust either crate, by pulling + in any additional dependencies needed by that feature. diff --git a/debian/copyright b/debian/copyright index f5c805e..9f14cf5 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,22 +1,36 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: template-repository -Source: https://github.com/deepin-community/template-repository +Upstream-Name: either +Upstream-Contact: bluss +Source: https://github.com/bluss/either Files: * -Copyright: 2023 Tsic404 -License: GPL-2+ - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +Copyright: 2015-2018 bluss +License: MIT or Apache-2.0 + +Files: debian/* +Copyright: 2018 Rust Maintainers + 2018 Ximin Luo +License: MIT or Apache-2.0 + +License: Apache-2.0 + Debian systems provide the Apache 2.0 license in + /usr/share/common-licenses/Apache-2.0 + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: . - You should have received a copy of the GNU General Public License - along with this program. If not, see + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/debian/copyright.debcargo.hint b/debian/copyright.debcargo.hint new file mode 100644 index 0000000..3fffd4d --- /dev/null +++ b/debian/copyright.debcargo.hint @@ -0,0 +1,49 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: either +Upstream-Contact: bluss +Source: https://github.com/bluss/either + +Files: * +Copyright: FIXME (overlay) UNKNOWN-YEARS bluss +License: MIT or Apache-2.0 +Comment: + FIXME (overlay): Since upstream copyright years are not available in + Cargo.toml, they were extracted from the upstream Git repository. This may not + be correct information so you should review and fix this before uploading to + the archive. + +Files: ./LICENSE-MIT +Copyright: 2015 +License: UNKNOWN-LICENSE; FIXME (overlay) +Comment: + FIXME (overlay): These notices are extracted from files. Please review them + before uploading to the archive. + +Files: debian/* +Copyright: + 2018-2022 Debian Rust Maintainers + 2018-2022 Ximin Luo +License: MIT or Apache-2.0 + +License: Apache-2.0 + Debian systems provide the Apache 2.0 license in + /usr/share/common-licenses/Apache-2.0 + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/debian/debcargo.toml b/debian/debcargo.toml new file mode 100644 index 0000000..fdbb775 --- /dev/null +++ b/debian/debcargo.toml @@ -0,0 +1,2 @@ +overlay = "." +uploaders = ["Ximin Luo "] diff --git a/debian/librust-either+serde-dev.lintian-overrides b/debian/librust-either+serde-dev.lintian-overrides new file mode 100644 index 0000000..59bde80 --- /dev/null +++ b/debian/librust-either+serde-dev.lintian-overrides @@ -0,0 +1 @@ +librust-either+serde-dev binary: empty-rust-library-declares-provides * \ No newline at end of file diff --git a/debian/rules b/debian/rules index 2d33f6a..044c1c2 100755 --- a/debian/rules +++ b/debian/rules @@ -1,4 +1,3 @@ #!/usr/bin/make -f - %: - dh $@ + dh $@ --buildsystem cargo diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000..255d4e7 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,24 @@ +Test-Command: /usr/share/cargo/bin/cargo-auto-test either 1.6.1 --all-targets --all-features +Features: test-name=rust-either:@ +Depends: dh-cargo (>= 18), librust-serde-json-1+default-dev, @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test either 1.6.1 --all-targets +Features: test-name=librust-either-dev:default +Depends: dh-cargo (>= 18), librust-serde-json-1+default-dev, @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test either 1.6.1 --all-targets --no-default-features --features use_std +Features: test-name=librust-either-dev:use_std +Depends: dh-cargo (>= 18), librust-serde-json-1+default-dev, @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test either 1.6.1 --all-targets --no-default-features +Features: test-name=librust-either-dev: +Depends: dh-cargo (>= 18), librust-serde-json-1+default-dev, @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test either 1.6.1 --all-targets --no-default-features --features serde +Features: test-name=librust-either+serde-dev:serde +Depends: dh-cargo (>= 18), librust-serde-json-1+default-dev, @ +Restrictions: allow-stderr, skip-not-installable diff --git a/debian/watch b/debian/watch new file mode 100644 index 0000000..9fe2ff7 --- /dev/null +++ b/debian/watch @@ -0,0 +1,4 @@ +version=4 +opts=filenamemangle=s/.*\/(.*)\/download/either-$1\.tar\.gz/g,\ +uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \ +https://qa.debian.org/cgi-bin/fakeupstream.cgi?upstream=crates.io/either .*/crates/either/@ANY_VERSION@/download diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..3ef249f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,1146 @@ +//! The enum [`Either`] with variants `Left` and `Right` is a general purpose +//! sum type with two cases. +//! +//! [`Either`]: enum.Either.html +//! +//! **Crate features:** +//! +//! * `"use_std"` +//! Enabled by default. Disable to make the library `#![no_std]`. +//! +//! * `"serde"` +//! Disabled by default. Enable to `#[derive(Serialize, Deserialize)]` for `Either` +//! + +#![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; + +#[cfg(feature = "serde")] +#[macro_use] +extern crate serde; + +#[cfg(feature = "serde")] +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; + +#[cfg(any(test, feature = "use_std"))] +use std::error::Error; +#[cfg(any(test, feature = "use_std"))] +use std::io::{self, BufRead, Read, Write}; + +pub use Either::{Left, Right}; + +/// The enum `Either` with variants `Left` and `Right` is a general purpose +/// sum type with two cases. +/// +/// 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)] +pub enum Either { + /// A value of type `L`. + Left(L), + /// A value of type `R`. + Right(R), +} + +macro_rules! either { + ($value:expr, $pattern:pat => $result:expr) => { + match $value { + Either::Left($pattern) => $result, + Either::Right($pattern) => $result, + } + }; +} + +/// Macro for unwrapping the left side of an `Either`, which fails early +/// with the opposite side. Can only be used in functions that return +/// `Either` because of the early return of `Right` that it provides. +/// +/// See also `try_right!` for its dual, which applies the same just to the +/// right side. +/// +/// # Example +/// +/// ``` +/// #[macro_use] extern crate either; +/// use either::{Either, Left, Right}; +/// +/// fn twice(wrapper: Either) -> Either { +/// let value = try_left!(wrapper); +/// Left(value * 2) +/// } +/// +/// fn main() { +/// assert_eq!(twice(Left(2)), Left(4)); +/// assert_eq!(twice(Right("ups")), Right("ups")); +/// } +/// ``` +#[macro_export] +macro_rules! try_left { + ($expr:expr) => { + match $expr { + $crate::Left(val) => val, + $crate::Right(err) => return $crate::Right(::std::convert::From::from(err)), + } + }; +} + +/// Dual to `try_left!`, see its documentation for more information. +#[macro_export] +macro_rules! try_right { + ($expr:expr) => { + match $expr { + $crate::Left(err) => return $crate::Left(::std::convert::From::from(err)), + $crate::Right(val) => val, + } + }; +} + +impl Either { + /// Return true if the value is the `Left` variant. + /// + /// ``` + /// use either::*; + /// + /// let values = [Left(1), Right("the right value")]; + /// assert_eq!(values[0].is_left(), true); + /// assert_eq!(values[1].is_left(), false); + /// ``` + pub fn is_left(&self) -> bool { + match *self { + Left(_) => true, + Right(_) => false, + } + } + + /// Return true if the value is the `Right` variant. + /// + /// ``` + /// use either::*; + /// + /// let values = [Left(1), Right("the right value")]; + /// assert_eq!(values[0].is_right(), false); + /// assert_eq!(values[1].is_right(), true); + /// ``` + pub fn is_right(&self) -> bool { + !self.is_left() + } + + /// Convert the left side of `Either` to an `Option`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left("some value"); + /// assert_eq!(left.left(), Some("some value")); + /// + /// let right: Either<(), _> = Right(321); + /// assert_eq!(right.left(), None); + /// ``` + pub fn left(self) -> Option { + match self { + Left(l) => Some(l), + Right(_) => None, + } + } + + /// Convert the right side of `Either` to an `Option`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left("some value"); + /// assert_eq!(left.right(), None); + /// + /// let right: Either<(), _> = Right(321); + /// assert_eq!(right.right(), Some(321)); + /// ``` + pub fn right(self) -> Option { + match self { + Left(_) => None, + Right(r) => Some(r), + } + } + + /// Convert `&Either` to `Either<&L, &R>`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left("some value"); + /// assert_eq!(left.as_ref(), Left(&"some value")); + /// + /// let right: Either<(), _> = Right("some value"); + /// assert_eq!(right.as_ref(), Right(&"some value")); + /// ``` + pub fn as_ref(&self) -> Either<&L, &R> { + match *self { + Left(ref inner) => Left(inner), + Right(ref inner) => Right(inner), + } + } + + /// Convert `&mut Either` to `Either<&mut L, &mut R>`. + /// + /// ``` + /// use either::*; + /// + /// fn mutate_left(value: &mut Either) { + /// if let Some(l) = value.as_mut().left() { + /// *l = 999; + /// } + /// } + /// + /// let mut left = Left(123); + /// let mut right = Right(123); + /// mutate_left(&mut left); + /// mutate_left(&mut right); + /// assert_eq!(left, Left(999)); + /// assert_eq!(right, Right(123)); + /// ``` + pub fn as_mut(&mut self) -> Either<&mut L, &mut R> { + match *self { + Left(ref mut inner) => Left(inner), + Right(ref mut inner) => Right(inner), + } + } + + /// Convert `Either` to `Either`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, ()> = Left(123); + /// assert_eq!(left.flip(), Right(123)); + /// + /// let right: Either<(), _> = Right("some value"); + /// assert_eq!(right.flip(), Left("some value")); + /// ``` + pub fn flip(self) -> Either { + match self { + Left(l) => Right(l), + Right(r) => Left(r), + } + } + + /// Apply the function `f` on the value in the `Left` variant if it is present rewrapping the + /// result in `Left`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.map_left(|x| x * 2), Left(246)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.map_left(|x| x * 2), Right(123)); + /// ``` + pub fn map_left(self, f: F) -> Either + where + F: FnOnce(L) -> M, + { + match self { + Left(l) => Left(f(l)), + Right(r) => Right(r), + } + } + + /// Apply the function `f` on the value in the `Right` variant if it is present rewrapping the + /// result in `Right`. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.map_right(|x| x * 2), Left(123)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.map_right(|x| x * 2), Right(246)); + /// ``` + pub fn map_right(self, f: F) -> Either + where + F: FnOnce(R) -> S, + { + match self { + Left(l) => Left(l), + Right(r) => Right(f(r)), + } + } + + /// Apply one of two functions depending on contents, unifying their result. If the value is + /// `Left(L)` then the first function `f` is applied; if it is `Right(R)` then the second + /// function `g` is applied. + /// + /// ``` + /// use either::*; + /// + /// fn square(n: u32) -> i32 { (n * n) as i32 } + /// fn negate(n: i32) -> i32 { -n } + /// + /// let left: Either = Left(4); + /// assert_eq!(left.either(square, negate), 16); + /// + /// let right: Either = Right(-4); + /// assert_eq!(right.either(square, negate), 4); + /// ``` + pub fn either(self, f: F, g: G) -> T + where + F: FnOnce(L) -> T, + G: FnOnce(R) -> T, + { + match self { + Left(l) => f(l), + Right(r) => g(r), + } + } + + /// Like `either`, but provide some context to whichever of the + /// functions ends up being called. + /// + /// ``` + /// // In this example, the context is a mutable reference + /// use either::*; + /// + /// let mut result = Vec::new(); + /// + /// let values = vec![Left(2), Right(2.7)]; + /// + /// for value in values { + /// value.either_with(&mut result, + /// |ctx, integer| ctx.push(integer), + /// |ctx, real| ctx.push(f64::round(real) as i32)); + /// } + /// + /// assert_eq!(result, vec![2, 3]); + /// ``` + pub fn either_with(self, ctx: Ctx, f: F, g: G) -> T + where + F: FnOnce(Ctx, L) -> T, + G: FnOnce(Ctx, R) -> T, + { + match self { + Left(l) => f(ctx, l), + Right(r) => g(ctx, r), + } + } + + /// Apply the function `f` on the value in the `Left` variant if it is present. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.left_and_then::<_,()>(|x| Right(x * 2)), Right(246)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.left_and_then(|x| Right::<(), _>(x * 2)), Right(123)); + /// ``` + pub fn left_and_then(self, f: F) -> Either + where + F: FnOnce(L) -> Either, + { + match self { + Left(l) => f(l), + Right(r) => Right(r), + } + } + + /// Apply the function `f` on the value in the `Right` variant if it is present. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.right_and_then(|x| Right(x * 2)), Left(123)); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.right_and_then(|x| Right(x * 2)), Right(246)); + /// ``` + pub fn right_and_then(self, f: F) -> Either + where + F: FnOnce(R) -> Either, + { + match self { + Left(l) => Left(l), + Right(r) => f(r), + } + } + + /// Convert the inner value to an iterator. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, Vec> = Left(vec![1, 2, 3, 4, 5]); + /// let mut right: Either, _> = Right(vec![]); + /// right.extend(left.into_iter()); + /// assert_eq!(right, Right(vec![1, 2, 3, 4, 5])); + /// ``` + pub fn into_iter(self) -> Either + where + L: IntoIterator, + R: IntoIterator, + { + match self { + Left(l) => Left(l.into_iter()), + Right(r) => Right(r.into_iter()), + } + } + + /// Return left value or given value + /// + /// Arguments passed to `left_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`left_or_else`], + /// which is lazily evaluated. + /// + /// [`left_or_else`]: #method.left_or_else + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either<&str, &str> = Left("left"); + /// assert_eq!(left.left_or("foo"), "left"); + /// + /// let right: Either<&str, &str> = Right("right"); + /// assert_eq!(right.left_or("left"), "left"); + /// ``` + pub fn left_or(self, other: L) -> L { + match self { + Either::Left(l) => l, + Either::Right(_) => other, + } + } + + /// Return left or a default + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("left".to_string()); + /// assert_eq!(left.left_or_default(), "left"); + /// + /// let right: Either = Right(42); + /// assert_eq!(right.left_or_default(), String::default()); + /// ``` + pub fn left_or_default(self) -> L + where + L: Default, + { + match self { + Either::Left(l) => l, + Either::Right(_) => L::default(), + } + } + + /// Returns left value or computes it from a closure + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("3".to_string()); + /// assert_eq!(left.left_or_else(|_| unreachable!()), "3"); + /// + /// let right: Either = Right(3); + /// assert_eq!(right.left_or_else(|x| x.to_string()), "3"); + /// ``` + pub fn left_or_else(self, f: F) -> L + where + F: FnOnce(R) -> L, + { + match self { + Either::Left(l) => l, + Either::Right(r) => f(r), + } + } + + /// Return right value or given value + /// + /// Arguments passed to `right_or` are eagerly evaluated; if you are passing + /// the result of a function call, it is recommended to use [`right_or_else`], + /// which is lazily evaluated. + /// + /// [`right_or_else`]: #method.right_or_else + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let right: Either<&str, &str> = Right("right"); + /// assert_eq!(right.right_or("foo"), "right"); + /// + /// let left: Either<&str, &str> = Left("left"); + /// assert_eq!(left.right_or("right"), "right"); + /// ``` + pub fn right_or(self, other: R) -> R { + match self { + Either::Left(_) => other, + Either::Right(r) => r, + } + } + + /// Return right or a default + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("left".to_string()); + /// assert_eq!(left.right_or_default(), u32::default()); + /// + /// let right: Either = Right(42); + /// assert_eq!(right.right_or_default(), 42); + /// ``` + pub fn right_or_default(self) -> R + where + R: Default, + { + match self { + Either::Left(_) => R::default(), + Either::Right(r) => r, + } + } + + /// Returns right value or computes it from a closure + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either = Left("3".to_string()); + /// assert_eq!(left.right_or_else(|x| x.parse().unwrap()), 3); + /// + /// let right: Either = Right(3); + /// assert_eq!(right.right_or_else(|_| unreachable!()), 3); + /// ``` + pub fn right_or_else(self, f: F) -> R + where + F: FnOnce(L) -> R, + { + match self { + Either::Left(l) => f(l), + Either::Right(r) => r, + } + } + + /// Returns the left value + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either<_, ()> = Left(3); + /// assert_eq!(left.unwrap_left(), 3); + /// ``` + /// + /// # Panics + /// + /// When `Either` is a `Right` value + /// + /// ```should_panic + /// # use either::*; + /// let right: Either<(), _> = Right(3); + /// right.unwrap_left(); + /// ``` + pub fn unwrap_left(self) -> L + where + R: std::fmt::Debug, + { + match self { + Either::Left(l) => l, + Either::Right(r) => { + panic!("called `Either::unwrap_left()` on a `Right` value: {:?}", r) + } + } + } + + /// Returns the right value + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let right: Either<(), _> = Right(3); + /// assert_eq!(right.unwrap_right(), 3); + /// ``` + /// + /// # Panics + /// + /// When `Either` is a `Left` value + /// + /// ```should_panic + /// # use either::*; + /// let left: Either<_, ()> = Left(3); + /// left.unwrap_right(); + /// ``` + pub fn unwrap_right(self) -> R + where + L: std::fmt::Debug, + { + match self { + Either::Right(r) => r, + Either::Left(l) => panic!("called `Either::unwrap_right()` on a `Left` value: {:?}", l), + } + } + + /// Returns the left value + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let left: Either<_, ()> = Left(3); + /// assert_eq!(left.expect_left("value was Right"), 3); + /// ``` + /// + /// # Panics + /// + /// When `Either` is a `Right` value + /// + /// ```should_panic + /// # use either::*; + /// let right: Either<(), _> = Right(3); + /// right.expect_left("value was Right"); + /// ``` + pub fn expect_left(self, msg: &str) -> L + where + R: std::fmt::Debug, + { + match self { + Either::Left(l) => l, + Either::Right(r) => panic!("{}: {:?}", msg, r), + } + } + + /// Returns the right value + /// + /// # Examples + /// + /// ``` + /// # use either::*; + /// let right: Either<(), _> = Right(3); + /// assert_eq!(right.expect_right("value was Left"), 3); + /// ``` + /// + /// # Panics + /// + /// When `Either` is a `Left` value + /// + /// ```should_panic + /// # use either::*; + /// let left: Either<_, ()> = Left(3); + /// left.expect_right("value was Right"); + /// ``` + pub fn expect_right(self, msg: &str) -> R + where + L: std::fmt::Debug, + { + match self { + Either::Right(r) => r, + Either::Left(l) => panic!("{}: {:?}", msg, l), + } + } +} + +impl Either<(T, L), (T, R)> { + /// Factor out a homogeneous type from an either of pairs. + /// + /// Here, the homogeneous type is the first element of the pairs. + /// + /// ``` + /// use either::*; + /// let left: Either<_, (u32, String)> = Left((123, vec![0])); + /// assert_eq!(left.factor_first().0, 123); + /// + /// let right: Either<(u32, Vec), _> = Right((123, String::new())); + /// assert_eq!(right.factor_first().0, 123); + /// ``` + pub fn factor_first(self) -> (T, Either) { + match self { + Left((t, l)) => (t, Left(l)), + Right((t, r)) => (t, Right(r)), + } + } +} + +impl Either<(L, T), (R, T)> { + /// Factor out a homogeneous type from an either of pairs. + /// + /// Here, the homogeneous type is the second element of the pairs. + /// + /// ``` + /// use either::*; + /// let left: Either<_, (String, u32)> = Left((vec![0], 123)); + /// assert_eq!(left.factor_second().1, 123); + /// + /// let right: Either<(Vec, u32), _> = Right((String::new(), 123)); + /// assert_eq!(right.factor_second().1, 123); + /// ``` + pub fn factor_second(self) -> (Either, T) { + match self { + Left((l, t)) => (Left(l), t), + Right((r, t)) => (Right(r), t), + } + } +} + +impl Either { + /// Extract the value of an either over two equivalent types. + /// + /// ``` + /// use either::*; + /// + /// let left: Either<_, u32> = Left(123); + /// assert_eq!(left.into_inner(), 123); + /// + /// let right: Either = Right(123); + /// assert_eq!(right.into_inner(), 123); + /// ``` + pub fn into_inner(self) -> T { + either!(self, inner => inner) + } + + /// Map `f` over the contained value and return the result in the + /// corresponding variant. + /// + /// ``` + /// use either::*; + /// + /// let value: Either<_, i32> = Right(42); + /// + /// let other = value.map(|x| x * 2); + /// assert_eq!(other, Right(84)); + /// ``` + pub fn map(self, f: F) -> Either + where + F: FnOnce(T) -> M, + { + match self { + Left(l) => Left(f(l)), + Right(r) => Right(f(r)), + } + } +} + +/// Convert from `Result` to `Either` with `Ok => Right` and `Err => Left`. +impl From> for Either { + fn from(r: Result) -> Self { + match r { + Err(e) => Left(e), + Ok(o) => Right(o), + } + } +} + +/// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`. +impl Into> for Either { + fn into(self) -> Result { + match self { + Left(l) => Err(l), + Right(r) => Ok(r), + } + } +} + +impl Extend for Either +where + L: Extend, + R: Extend, +{ + fn extend(&mut self, iter: T) + where + T: IntoIterator, + { + either!(*self, ref mut inner => inner.extend(iter)) + } +} + +/// `Either` is an iterator if both `L` and `R` are iterators. +impl Iterator for Either +where + L: Iterator, + R: Iterator, +{ + type Item = L::Item; + + fn next(&mut self) -> Option { + either!(*self, ref mut inner => inner.next()) + } + + fn size_hint(&self) -> (usize, Option) { + either!(*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)) + } + + fn count(self) -> usize { + either!(self, inner => inner.count()) + } + + fn last(self) -> Option { + either!(self, inner => inner.last()) + } + + fn nth(&mut self, n: usize) -> Option { + either!(*self, ref mut inner => inner.nth(n)) + } + + fn collect(self) -> B + where + B: iter::FromIterator, + { + either!(self, inner => inner.collect()) + } + + fn all(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + either!(*self, ref mut inner => inner.all(f)) + } +} + +impl DoubleEndedIterator for Either +where + L: DoubleEndedIterator, + R: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + either!(*self, ref mut inner => inner.next_back()) + } +} + +impl ExactSizeIterator for Either +where + L: ExactSizeIterator, + R: ExactSizeIterator, +{ +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Read` if both `L` and `R` do. +/// +/// Requires crate feature `"use_std"` +impl Read for Either +where + L: Read, + R: Read, +{ + fn read(&mut self, buf: &mut [u8]) -> io::Result { + either!(*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)) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// Requires crate feature `"use_std"` +impl BufRead for Either +where + L: BufRead, + R: BufRead, +{ + fn fill_buf(&mut self) -> io::Result<&[u8]> { + either!(*self, ref mut inner => inner.fill_buf()) + } + + fn consume(&mut self, amt: usize) { + either!(*self, ref mut inner => inner.consume(amt)) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Write` if both `L` and `R` do. +/// +/// Requires crate feature `"use_std"` +impl Write for Either +where + L: Write, + R: Write, +{ + fn write(&mut self, buf: &[u8]) -> io::Result { + either!(*self, ref mut inner => inner.write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + either!(*self, ref mut inner => inner.flush()) + } +} + +impl AsRef for Either +where + L: AsRef, + R: AsRef, +{ + fn as_ref(&self) -> &Target { + either!(*self, ref inner => inner.as_ref()) + } +} + +macro_rules! impl_specific_ref_and_mut { + ($t:ty, $($attr:meta),* ) => { + $(#[$attr])* + impl AsRef<$t> for Either + where L: AsRef<$t>, R: AsRef<$t> + { + fn as_ref(&self) -> &$t { + either!(*self, ref inner => inner.as_ref()) + } + } + + $(#[$attr])* + impl AsMut<$t> for Either + where L: AsMut<$t>, R: AsMut<$t> + { + fn as_mut(&mut self) -> &mut $t { + either!(*self, ref mut inner => inner.as_mut()) + } + } + }; +} + +impl_specific_ref_and_mut!(str,); +impl_specific_ref_and_mut!( + ::std::path::Path, + cfg(feature = "use_std"), + doc = "Requires crate feature `use_std`." +); +impl_specific_ref_and_mut!( + ::std::ffi::OsStr, + cfg(feature = "use_std"), + doc = "Requires crate feature `use_std`." +); +impl_specific_ref_and_mut!( + ::std::ffi::CStr, + cfg(feature = "use_std"), + doc = "Requires crate feature `use_std`." +); + +impl AsRef<[Target]> for Either +where + L: AsRef<[Target]>, + R: AsRef<[Target]>, +{ + fn as_ref(&self) -> &[Target] { + either!(*self, ref inner => inner.as_ref()) + } +} + +impl AsMut for Either +where + L: AsMut, + R: AsMut, +{ + fn as_mut(&mut self) -> &mut Target { + either!(*self, ref mut inner => inner.as_mut()) + } +} + +impl AsMut<[Target]> for Either +where + L: AsMut<[Target]>, + R: AsMut<[Target]>, +{ + fn as_mut(&mut self) -> &mut [Target] { + either!(*self, ref mut inner => inner.as_mut()) + } +} + +impl Deref for Either +where + L: Deref, + R: Deref, +{ + type Target = L::Target; + + fn deref(&self) -> &Self::Target { + either!(*self, ref inner => &*inner) + } +} + +impl DerefMut for Either +where + L: DerefMut, + R: DerefMut, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + either!(*self, ref mut inner => &mut *inner) + } +} + +#[cfg(any(test, feature = "use_std"))] +/// `Either` implements `Error` if *both* `L` and `R` implement it. +impl Error for Either +where + L: Error, + R: Error, +{ + #[allow(deprecated)] + fn description(&self) -> &str { + either!(*self, ref inner => inner.description()) + } + + #[allow(deprecated)] + #[allow(unknown_lints, bare_trait_objects)] + fn cause(&self) -> Option<&Error> { + either!(*self, ref inner => inner.cause()) + } +} + +impl fmt::Display for Either +where + L: fmt::Display, + R: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + either!(*self, ref inner => inner.fmt(f)) + } +} + +#[test] +fn basic() { + let mut e = Left(2); + let r = Right(2); + assert_eq!(e, Left(2)); + e = r; + assert_eq!(e, Right(2)); + assert_eq!(e.left(), None); + assert_eq!(e.right(), Some(2)); + assert_eq!(e.as_ref().right(), Some(&2)); + assert_eq!(e.as_mut().right(), Some(&mut 2)); +} + +#[test] +fn macros() { + fn a() -> Either { + let x: u32 = try_left!(Right(1337u32)); + Left(x * 2) + } + assert_eq!(a(), Right(1337)); + + fn b() -> Either { + Right(try_right!(Left("foo bar"))) + } + assert_eq!(b(), Left(String::from("foo bar"))); +} + +#[test] +fn deref() { + fn is_str(_: &str) {} + let value: Either = Left(String::from("test")); + is_str(&*value); +} + +#[test] +fn iter() { + let x = 3; + let mut iter = match x { + 3 => Left(0..10), + _ => Right(17..), + }; + + assert_eq!(iter.next(), Some(0)); + assert_eq!(iter.count(), 9); +} + +#[test] +fn read_write() { + use std::io; + + let use_stdio = false; + let mockdata = [0xff; 256]; + + let mut reader = if use_stdio { + Left(io::stdin()) + } else { + Right(&mockdata[..]) + }; + + let mut buf = [0u8; 16]; + assert_eq!(reader.read(&mut buf).unwrap(), buf.len()); + assert_eq!(&buf, &mockdata[..buf.len()]); + + let mut mockbuf = [0u8; 256]; + let mut writer = if use_stdio { + Left(io::stdout()) + } else { + Right(&mut mockbuf[..]) + }; + + let buf = [1u8; 16]; + assert_eq!(writer.write(&buf).unwrap(), buf.len()); +} + +#[test] +#[allow(deprecated)] +fn error() { + let invalid_utf8 = b"\xff"; + let res = if let Err(error) = ::std::str::from_utf8(invalid_utf8) { + Err(Left(error)) + } else if let Err(error) = "x".parse::() { + Err(Right(error)) + } else { + Ok(()) + }; + assert!(res.is_err()); + res.unwrap_err().description(); // make sure this can be called +} + +/// A helper macro to check if AsRef and AsMut are implemented for a given type. +macro_rules! check_t { + ($t:ty) => {{ + fn check_ref>() {} + fn propagate_ref, T2: AsRef<$t>>() { + check_ref::>() + } + fn check_mut>() {} + fn propagate_mut, T2: AsMut<$t>>() { + check_mut::>() + } + }}; +} + +// This "unused" method is here to ensure that compilation doesn't fail on given types. +fn _unsized_ref_propagation() { + check_t!(str); + + fn check_array_ref, Item>() {} + fn check_array_mut, Item>() {} + + fn propagate_array_ref, T2: AsRef<[Item]>, Item>() { + check_array_ref::, _>() + } + + fn propagate_array_mut, T2: AsMut<[Item]>, Item>() { + check_array_mut::, _>() + } +} + +// This "unused" method is here to ensure that compilation doesn't fail on given types. +#[cfg(feature = "use_std")] +fn _unsized_std_propagation() { + check_t!(::std::path::Path); + check_t!(::std::ffi::OsStr); + check_t!(::std::ffi::CStr); +} diff --git a/src/serde_untagged.rs b/src/serde_untagged.rs new file mode 100644 index 0000000..20de074 --- /dev/null +++ b/src/serde_untagged.rs @@ -0,0 +1,73 @@ +//! Untagged serialization/deserialization support for Either. +//! +//! `Either` uses default, externally-tagged representation. +//! However, sometimes it is useful to support several alternative types. +//! For example, we may have a field which is generally Map +//! 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)] +//! #[serde(transparent)] +//! struct IntOrString { +//! #[serde(with = "either::serde_untagged")] +//! inner: Either, HashMap> +//! }; +//! +//! // serialization +//! let data = IntOrString { +//! inner: Either::Left(vec!["Hello".to_string()]) +//! }; +//! // notice: no tags are emitted. +//! assert_eq!(serde_json::to_string(&data)?, r#"["Hello"]"#); +//! +//! // deserialization +//! let data: IntOrString = serde_json::from_str( +//! r#"{"a": 0, "b": 14}"# +//! )?; +//! println!("found {:?}", data); +//! # Ok(()) +//! # } +//! ``` + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum Either { + Left(L), + Right(R), +} + +pub fn serialize(this: &super::Either, serializer: S) -> Result +where + S: Serializer, + L: Serialize, + R: Serialize, +{ + let untagged = match this { + &super::Either::Left(ref left) => Either::Left(left), + &super::Either::Right(ref right) => Either::Right(right), + }; + untagged.serialize(serializer) +} + +pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + L: Deserialize<'de>, + R: Deserialize<'de>, +{ + match Either::deserialize(deserializer) { + Ok(Either::Left(left)) => Ok(super::Either::Left(left)), + Ok(Either::Right(right)) => Ok(super::Either::Right(right)), + Err(error) => Err(error), + } +} diff --git a/src/serde_untagged_optional.rs b/src/serde_untagged_optional.rs new file mode 100644 index 0000000..f0cca36 --- /dev/null +++ b/src/serde_untagged_optional.rs @@ -0,0 +1,78 @@ +//! Untagged serialization/deserialization support for Option>. +//! +//! `Either` uses default, externally-tagged representation. +//! However, sometimes it is useful to support several alternative types. +//! For example, we may have a field which is generally Map +//! 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)] +//! #[serde(transparent)] +//! struct IntOrString { +//! #[serde(with = "either::serde_untagged_optional")] +//! inner: Option, HashMap>> +//! }; +//! +//! // serialization +//! let data = IntOrString { +//! inner: Some(Either::Left(vec!["Hello".to_string()])) +//! }; +//! // notice: no tags are emitted. +//! assert_eq!(serde_json::to_string(&data)?, r#"["Hello"]"#); +//! +//! // deserialization +//! let data: IntOrString = serde_json::from_str( +//! r#"{"a": 0, "b": 14}"# +//! )?; +//! println!("found {:?}", data); +//! # Ok(()) +//! # } +//! ``` + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum Either { + Left(L), + Right(R), +} + +pub fn serialize( + this: &Option>, + serializer: S, +) -> Result +where + S: Serializer, + L: Serialize, + 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, + }; + untagged.serialize(serializer) +} + +pub fn deserialize<'de, L, R, D>(deserializer: D) -> Result>, D::Error> +where + D: Deserializer<'de>, + L: Deserialize<'de>, + R: Deserialize<'de>, +{ + match Option::deserialize(deserializer) { + Ok(Some(Either::Left(left))) => Ok(Some(super::Either::Left(left))), + Ok(Some(Either::Right(right))) => Ok(Some(super::Either::Right(right))), + Ok(None) => Ok(None), + Err(error) => Err(error), + } +}