Coder Social home page Coder Social logo

either's Introduction

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

build_status crates

How to use with cargo:

[dependencies]
either = "1.10"

Recent Changes

  • 1.10.0
    • Add new methods .factor_iter(), .factor_iter_mut(), and .factor_into_iter() that return Either items, plus .iter() and .iter_mut() to convert to direct referene iterators; by @aj-bagwell and @cuviper (#91)
  • 1.9.0
    • Add new methods .map_either() and .map_either_with(), by @nasadorian (#82)
  • 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(), 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<T, T> 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<L, R> 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 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.

either's People

Contributors

aj-bagwell avatar anderender avatar aomader avatar atouchet avatar bluss avatar cuviper avatar dcjanus avatar hcpl avatar kerollmops avatar kixunil avatar lipen avatar m4rw3r avatar manonthemat avatar mathstuf avatar mexus avatar mglagla avatar mikailbag avatar nasadorian avatar nvzqz avatar pthariensflame avatar rampantmonkey avatar rivertam avatar spenserblack avatar stebalien avatar ten0 avatar thomaseizinger avatar tonalidadehidrica avatar trivikr avatar twey avatar zachs18 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

either's Issues

EitherN heads-up

I'm working on my own crate https://github.com/cramertj/EitherN-rs to allow for Either over more than two types (e.g Either4 with variants One, Two, Three, and Four). I wanted to check with @bluss and the other contributors. As my library's functionality will share many implementation details with this one, I wanted to make sure no one here feels like I'm stealing their hard work. Let me know if you have any problems or would prefer I do anything differently. Thanks!

Rename `Left` and `Right` to `A` and `B`

Hi! This is a completely crazy idea and is almost centrally a won't fix, because either is 1.0, but I decided to log it anyway.

I've recently saw an enum Either<T, U> { A(T), B(U) } in warp and now I think that Haskell's left/right terminology is a mistake :D Here are the benefits of A/B

  • Equal length of variants
  • Less typing
  • Nice symmetry between .0, .1 for pairs and ::A, ::B for co-pairs
  • "Either A or B" sounds more natural then "Either left or right". Like, we have A/B testing and such.
  • A and B have less semantic meaning than Left, Right.
  • Naturally extends to more varians: enum ABC<T, U, V> { A(T), B(U), C(V) }.

EDIT: apparently, there's no ab crate yet ๐Ÿค”

set serde derive to use serde untagged

Think the way serde is derived is a non-intuitive way. As I think most people do not want the left and right tags for the values.

Suggest adding untagged to the serde derive. However this would be a breaking change. I do not belive many people are using the serde fetaure as its now implemented.

This will allow us to do something like:

type ComplicatedType  = HashMap<String, Either<Vec<String>, String>>

Some json that would be parsed now would be

{
    "some_key": "hello",
    "some_other_random_key": ["hello","world!"]
}

Allow pin projection

Not sure whether this is in scope for this library but in rust-libp2p, we have a custom Either type because we need pin projection.

Would you accept a PR for a feature-flagged pin projection implementation using the pin-project library?

Either::as_ref method

Hi everyone,

I've just hit an issue while trying to replace an impl AsRef with a concrete Either type in a return position, here's an example: https://play.rust-lang.org/?gist=1f4771605ae47ea7e4e10881a994a2dc&version=stable&mode=debug&edition=2015

I believe it happens because Either::as_ref method effectively hides the AsRef::as_ref method :(

Shouldn't it be renamed to something like to_ref so it doesn't overlap with the AsRef trait, or is there any reason behind this specific name? The same goes for as_mut and probably for into_iter as well.

Implement From<L> and From<R> for Either<L, R>

I suggest adding the two impls:

impl From<L> for Either<L, R>

and

impl From<R> for Either<L, R>

(don't know the right syntax by heart)

This enables the following nice use-case:

fn foo(e: Either<i32, f32>) {
  // use e
}

fn main() {
  foo(32.into());
  foo(42.0.into());
}

Instead of explicitly writing out the type each time.

Is there a problem with this/am I missing something? Otherwise I would write up a PR. Thanks!

A way to update value using the previous one

Hello. I've not found a way to update Left(prev_value) to Right(new_value) in case when I need the previous value to create the new one. In Option we have the method take that replaces an old value with None, and returns the old one to us. It would be nice to have something like this:

pub fn morph(&mut self, f: F, g: G) -> Either<L, R>
where
    F: FnOnce(L) -> R,
    G: FnOnce(R) -> L

Now to do this, I have to use Option wrapping Either to be able to have the third None state.

struct Data {
    member: Option<Either<L, R>>
}

impl Data {
    fn update_member(&mut self) {
        self.member = self.member.take().map(
            |member| member.map_either(
                |old_value| create_new_value(old_value),
                |old_value| create_new_value(old_value)
            ).flip()
        );
    }
}

But actually I don't need it, and it makes me write more code for checking the option's state later. I just want to have a member with two correct states: L and R.

Thanks

serde derive feature

Inspired by serde-rs/serde#2584, I looked through my dep tree and saw that either includes serde with the "derive" feature.

Unfortunately, it's not so simple how to remove the feature here.

Removing derive altogether

Either uses serde for 3 things,

  1. Tagged Representation
  2. Untagged Representation
  3. Optional Untagged Representation

For 1, We can write a manual implementation of the de/serializers with no problem. For 2 and 3, the derived deserializer makes use of doc(hidden) APIs in order to cache the serde tree in case it needs to perform a second deserialisation.

Depending on serde_derive directly

dtolnay was initially against this idea because the versions of serde/derive need to be in lockstep.

There seems to be some effort to ensure it using some fancy target trickery. This is in the latest release of 1.0.186.

The trouble here is that either has 1 feature, serde. For compat with older resolvers, I think I would need to rename the serde package to serde_pkg and make the serde feature include both serde_pkg and serde_derive


Should I make a PR with the second option? The first option is possible but it requires a lot more effort to duplicate the private APIs

include LICENSE into repo and crate

Apache-2.0 license requires license file to be distributed along with sources. And MIT license would not hurt to have in archives as well.

Add `flatten`, `flatten_right` and `flatten_left` methods

I think the Either crate is really good, and here are some methods I would love to see:

flatten

I think there should be a flatten method, like for std::Result and std::Option:

impl<L,R> Either<Either<L,R>, Either<L,R>> {
    pub fn flatten(self) -> Either<L,R> {
        match self {
            Left(x) | Right(x) => x
        }
    }
}

As you can see from the implementation, this is the same as into_inner but I think it is good to have this for two reasons:

  • The terminology "flatten" is often used for flattening such nested structures

One alternative may be to let flatten use any Either<T,T> (and thus skip combine).

flatten_right/flatten_left

Two more propsed functions are flatten_right and flatten_left:

impl<L,R> Either<Either<L,R>, R> {
    pub fn flatten_left(self) -> Either<L,R> {
        match self {
            Left(x) => x,
            Right(x) => Right(x)
        }
    }
}

impl<L,R> Either<L, Either<L,R>> {
    pub fn flatten_right(self) -> Either<L,R> {
        match self {
            Right(x) => Right(x),
            Left(x) => x
        }
    }
}

flatten_left is just flatten on std::Result, but it is nice to have corresponding left and right methods to strengthen the intuition that there is nothing special with the left or the right variant, they are both considered equal.

I am fine with doing the implementation itself but I would be glad about comments, naming suggestions and general suggestions! Do you think this would be useful? Maybe it would be confusing with flatten and into_inner doing the same thing so I am fine with dropping that, but flatten_left and flatten_right seems useful imo.

Support for factoring out types

In the futures crate, there exists their own Either type currently. The crate commonly creates an Either over two pairs. I'd like to add methods which factor out common types from both sides:

Either<(T, A), (U, A)> -> (A, Either<T, U>)
Either<(A, T), (A, U)> -> (A, Either<T, U>)
Either<A, A> -> A

Would these be suitable here or do you think they're better as standalone functions in futures? The last one probably makes the most sense here at least.

Generalize inner types for better Serde integration

Right now, I'm running into an issue where I'd like to deseralize a type like this:

#[derive(Deserialize)]
struct Foo<'a> {
    #[serde(borrow)]
    bar: Either<Cow<'a, str>, Baz<'a>>,
}

#[derive(Deserialize)]
struct Baz<'a> {
    #[serde(borrow)]
    xyz: Cow<'a, str>,
}

On older versions of Rust/Either/Serde, you'll get an error message like so:

   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
   |
   = note: `Foo<'a>` must implement `Deserialize<'0>`, for any lifetime `'0`...
   = note: ...but `Foo<'_>` actually implements `Deserialize<'1>`, for some specific lifetime `'1`

Although running the same code on all updated versions of software just gives you a much longer error.

error[E0277]: the trait bound `Either<Cow<'a, str>, Baz<'a>>: Deserialize<'_>` is not satisfied
    --> src/lib.rs:10:10
     |
10   |     bar: Either<Cow<'a, str>, Baz<'a>>,
     |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `Either<Cow<'a, str>, Baz<'a>>`
     |
     = help: the following other types implement trait `Deserialize<'de>`:
               bool
               char
               isize
               i8
               i16
               i32
               i64
               i128
             and 137 others
note: required by a bound in `next_element`
    --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.192/src/de/mod.rs:1726:12
     |
1724 |     fn next_element<T>(&mut self) -> Result<Option<T>, Self::Error>
     |        ------------ required by a bound in this associated function
1725 |     where
1726 |         T: Deserialize<'de>,
     |            ^^^^^^^^^^^^^^^^ required by this bound in `SeqAccess::next_element`

This should be possible, given the fact that I can replace Either<L, R> with Result<Ok, Err> like so, and it'll actually compile, and act properly in software.

#[derive(Deserialize)]
struct Foo<'a> {
    #[serde(borrow)]
    bar: Result<Cow<'a, str>, Baz<'a>>,
}

Not entirely sure what the deal is, but I believe if Result can do it, then Either should be able to as well? I'm not sure if there are any technical details getting in the way of implementing this, but there shouldn't be much stopping us from just duplicating the Result implementation here.

Unable to use "either::serde_untagged", instructions unclear

I am providing a reprex for the use of either::serde_untagged.
I have not been able to use this feature, because
this line:
#[serde(with = "either::serde_untagged")]
fails to compile, and I cannot figure out why.

//main.rs
use serde::{Serialize, Deserialize};
use either::Either;

fn main() {
    #[derive(Serialize, Deserialize, Debug)]
    #[serde(transparent)]
    struct IntOrString {
        #[serde(with = "either::serde_untagged")]
        inner: Either<Vec<String>, u8>
    };
}
//Cargo Toml deps
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
either = "1.6.1"

I am grateful for any help

Add more Iterator helper methods

At the moment the impl Iterator for Either and into_iter both require that L and R are iterators over the same type. I think that makes sense as it covers the nicest use case, but it does not cover cases where they are different.

Some examples that would be nice to iterate over:

  • Either<Vec<i64>, &[i64]>
  • Either<&[i32], &[i64]>
  • Either<Range<u64>, &[i64]>

I suggest adding a factor_iter method, wich takes Either<Iter<L>, Iter<R>> and converts it to a Iter<Either<L, R>>.

Ideally I was hoping for something that would do something like into_iter_into(self: Either<IntoIter<L: Into<T>>, IntoIter<R: Into<T>>>) -> Iter<T> but the myriad of Rust conversion traits (From, Into, AsRef, Borrow, Copy) are implemented on different types, and there are no blanket implementions (and can't be until there is trait specialisation).

For example u32: Into<u64> but &u32 is not, so it would work on Either<Vec<u32>, Vec<u64>> but not Either<&[u32], &[u64]>. Aslo since there are a pile of Into impls for everything the type inferenceing never works and you need to tell it what T is.

There is one other Iterator themed method that I do think merits adding which is an analog to the iter() method from Vec as it does not always make sense to consume the data just to iterate over it.

It is only a simple wrapper for self.as_ref().into_iter() but I think it is nice to have it in the docs.

Conversion from Option

An Option<T> is equivalent to Either<T, ()>, so a conversion like: impl<T> From<Option<T>> for Either<T, ()> would be nice. This can be useful for generic algorithms.

Publicly expose the `either!` macro?

The macro can be useful outside of this crate if one wants to deal with both variants in the same way but without them having the same type. For example:

trait Foo {
    type T;

    fn foo(self) -> Bar<Self::T>;
}

struct Bar<T> {
    inner: T,
}

impl<L, R, LT, RT> Foo for Either<L, R>
where
    L: Foo<T = LT>,
    R: Foo<T = RT>,
{
    type T = Either<LT, RT>;

    fn foo(self) -> Bar<Self::T> {
        let either_bar = either!(self, inner => inner.foo().inner);

        Bar { inner: either_bar }
    }
}

Change `impl Future for Either` to `Output = Either`

Currently, the implementation of Future for Either requires that both Futures resolve to the same type:

either/src/lib.rs

Lines 1127 to 1141 in af9f5fb

/// `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))
}
}

This limits, which kinds of Futures can be expressed using Either. It would be more useful to set the Output type to Either<A::Output, B::Output>. This is an API breaking change.

The original behaviour can be restored using the Either::into_inner function. In case both Futures, A and B have the same Output, the into_inner function can be used to "unwrap" the Either:

either/src/lib.rs

Lines 916 to 930 in af9f5fb

impl<T> Either<T, T> {
/// 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<u32, _> = Right(123);
/// assert_eq!(right.into_inner(), 123);
/// ```
pub fn into_inner(self) -> T {
for_both!(self, inner => inner)
}

Either constructors from `bool`

Hello.

I am curious if this was discussed or considered before. I searched the issues and PRs (for "bool") and found nothing similar.

Basically something like this:

trait Eitherable {
    fn either<L, R>(&self, left: L, right: R) -> Either<L, R>;
    fn either_else<L, FL: FnOnce() -> L, R, FR: FnOnce() -> R>(
        &self,
        l_func: FL,
        r_func: FR,
    ) -> Either<L, R>;
}

impl Eitherable for bool {
    fn either<L, R>(&self, left: L, right: R) -> Either<L, R> {
        if *self {
            Left(left)
        } else {
            Right(right)
        }
    }

    fn either_else<L, FL: FnOnce() -> L, R, FR: FnOnce() -> R>(
        &self,
        l_func: FL,
        r_func: FR,
    ) -> Either<L, R> {
        if *self {
            Left(l_func())
        } else {
            Right(r_func())
        }
    }
}

which allows nice one liner constructors like this :

my_bool.either(left_value, right_value)

instead of

if my_bool {
        Either::Left(left_value)
} else {
        Either::Right(right_balue)
}

Similarly for Options

Implement `bimap` which combines `left_map` and `right_map`

bimap is a function from the Bifunctor typeclass commonly seen implemented for the Either type.

This library already has map_left and map_right, so the implementation would simply be a combination of the two. Would the maintainers be interested in adding this combinator?

Example as an extension:

trait EitherExt {
  type L;
  type R;
  fn bimap<M, S, F: Fn(Self::L) -> M, G: Fn(Self::R) -> S>(
    self,
    f: F,
    g: G,
  ) -> Either<M, S>;
}

impl<L, R> EitherExt for Either<L, R> {
  type L = L;
  type R = R;
  fn bimap<M, S, F: Fn(Self::L) -> M, G: Fn(Self::R) -> S>(
    self,
    f: F,
    g: G,
  ) -> Either<M, S> {
    self.map_left(f).map_right(g)
  }
}

implement `IntoIterator`

Clippy complains:

warning: defining a method called `into_iter` on this type; consider implementing the `std::iter::IntoIterator` trait or choosing a less ambiguous name
   --> src/main.rs:373:5
    |
373 | /     pub fn into_iter(self) -> Either<L::IntoIter, R::IntoIter>
374 | |         where L: IntoIterator,
375 | |               R: IntoIterator<Item = L::Item>
376 | |     {
...   |
380 | |         }
381 | |     }
    | |_____^

and I think it is right. What is the purpose of not implementing IntoIterator?

rustc warning: trait objects without an explicit `dyn` are deprecated

Following warning is shown while using either@1.5.3 is used as a dependency:

warning: trait objects without an explicit `dyn` are deprecated
   --> /home/trivikr/.cargo/registry/src/github.com-1ecc6299db9ec823/either-1.5.3/src/lib.rs:839:32
    |
839 |     fn cause(&self) -> Option<&Error> {
    |                                ^^^^^ help: use `dyn`: `dyn Error`
    |
    = note: #[warn(bare_trait_objects)] on by default

The code which needs to be updated:
https://github.com/bluss/either/blob/cd15a341118b5af765450dcb6380c6dee17ed0f2/src/lib.rs#L839-L841

Alternative `Deref` implementations

This might not go anywhere, but here seemed like the right place to open the conversation.

I think there is a need for a type that captures the possibility of being either owned or some kind of reference, but without requiring the ToOwned constraint of Cow.

Currently Either has this Deref impl:

impl<L, R> Deref for Either<L, R> 
where
    L: Deref,
    R: Deref<Target = L::Target>,

Which is nice for Either<&T, Box<T>> or even things like Either<Ref<'a, T>, Either<Rc<T>, Box<T>>> etc. But Deref isn't implemented for Either<T, &T> which is a shame, because Cow also won't work here unless T: ToOwned<Owned = T>, which it mostly isn't unless T: Clone. An impl for Either that would work there would look like this:

impl<L, R> Deref for Either<L, R> 
where
    R: Deref<Target = L>, 

But it can't co-exist with the current implementation.

A workaround is to introduce a newtype:

struct Own<T>(T);
impl<T> Deref for Own<T> {
     type Target = T;
     fn deref(&self) -> Self::Target {
          self.0
     }
}

So you can do now use Either<Own<T>, &T>.

I'm sure many other crates have rolled their own (though I didn't find any), but it would be better if there was one canonical way to do this. What's the best way to achieve that? Try to do something in either, some other crate or a completely new one?

Can't seem to use without std

Cargo.toml has what seems to me to be the right thing from the documentation:

[dependencies.either]
version = "1.5.0"
default-features = false

and yet cargo build complains, in a no_std project:

   Compiling either v1.5.0
error[E0463]: can't find crate for `std`
  |
  = note: the `thumbv7m-none-eabi` target may not be installed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.
error: Could not compile `either`.

Disclaimer: I'm a newb, and probably doing something dumb, but I can't see what. Today's nightly, in case it matters.

New iterator method 'try_fold' can be optimized

Either can gain even more optimized iterator methods by overriding the try_fold method added in 1.27; however, this will cause a pretty big bump in the minimum supported rust version (which appears to be 1.12 based on CI test configuration).

Provide "into-common-type" function

It would be useful to have this kind of method:

impl <L, R> Either<L, R> {
    fn into_common<T>(self) -> T where T: From<L> + From<R> {
        match self {
            Either::Left(l) => l.into(),
            Either::Right(r) => r.into(),
        }
    }
}

Does it sound a good idea? If so, I'll send a PR. I'm wondering what function name would be nice.

Feat: Conditionally applied methods

Coming from rust-itertools/itertools#881 - methods that let you apply other methods conditionally would be helpful.
Something that lets you do:

fn u8_to_bools(value: u8, rtl: bool) -> [bool; 8] {
    let mut result = [false; 8];
    result
        .iter_mut()
        // Applies `Iterator::rev` if and only if `rtl` is `true`.
        // Otherwise does nothing.
        .apply_if(rtl, Iterator::rev)
        .enumerate()
        .for_each(|(i, b)| *b = ((value >> i) & 1) == 1);

    result
}

Along with other methods for ternary conditions, etc., like:

fn get_pairs(bytes: &[u8], overlap: bool) -> Vec<(u8, u8)> {
    bytes
        .iter()
        .copied()
        // Applies `Itertools::tuple_windows` if and only if the `overlap` is `true`.
        // Otherwise applies `Itertools::tuples`.
        .apply_either(overlap, Itertools::tuple_windows, Itertools::tuples)
        .collect()
}

While these examples revolve around iterators, the scope itself of these conditionally applied methods is much larger and in my humble opinion very useful.

It's simple to implement and could be very useful, especially when you have a large method chain and breaking it up for an if[-else] block would negatively affect the readability (see my doc examples).

I have already written a simple implementation on my local fork of either. Correct me if I'm wrong, but this only needs minor changes to work with the either crate instead.

If this feature request gets accepted, I would love to contribute to it myself.

Unsized marker for AsRef

Apparently AsRef implementation of Either lacks an "unsized" marker ?Sized on Target. It prevents of implementing AsRef<str> for the Either, for instance.

While default Either doesn't compile (without the marker on playground) ...

extern crate either; // 1.5.0
use either::Either;

fn get_default(s: Option<impl AsRef<str>>) -> impl AsRef<str> {
    s.map(Either::Left).unwrap_or_else(|| Either::Right("default"))
}

fn main() {
    println!("{}", get_default(None::<String>).as_ref());
    println!("{}", get_default(Some("not default")).as_ref());
}

... an example with the marker compiles just ok :) with the marker on playground

enum Either2<L, R> {
    Left(L),
    Right(R),
}

impl<L, R, T: ?Sized> AsRef<T> for Either2<L, R>
where
    L: AsRef<T>,
    R: AsRef<T>,
{
    fn as_ref(&self) -> &T {
        match self {
            Either2::Left(x) => x.as_ref(),
            Either2::Right(x) => x.as_ref(),
        }
    }
}

fn get_default(s: Option<impl AsRef<str>>) -> impl AsRef<str> {
    s.map(Either2::Left)
        .unwrap_or_else(|| Either2::Right("default"))
}

fn main() {
    println!("{}", get_default(None::<String>).as_ref());
    println!("{}", get_default(Some("not default")).as_ref());
}

So, my question is: was the ?Sized marker omitted on purpose, or should I make a PR which adds the marker? :)

serde_untagged_optional doesn't handle when field does not exist.

Hi, not sure if there's a good way to handle this, but I wanted to use Option like I usually do in serde where if the field does not exist it is None, however this is not how it works here:

use serde::{Deserialize};
use either::Either;

#[derive(Deserialize, Debug)]
struct Test {
    #[serde(with = "either::serde_untagged_optional")]
    field: Option<Either<String, Vec<String>>>,
    another_field: u32,
}

fn main() {
    // deserialization
    let data: Test = serde_json::from_str(
        r#"{"another_field": 6}"#
    ).unwrap();
    println!("found {:?}", data);
}

This panics because field is not found.

I've worked around this issue by just having a container struct for that particular field and just use either::serde_untagged but was just curious if this was intended behavior or not.

#[derive(Deserialize, Debug)]
struct Container(#[serde(with = "either::serde_untagged")] Either<String, Vec<String>>);

#[derive(Deserialize, Debug)]
struct Test {
    field: Option<Container>,
    another_field: u32,
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.