### 5 releases (3 stable)

2.0.0 | Nov 11, 2020 |
---|---|

1.1.0 | Nov 11, 2020 |

1.0.0 | Sep 18, 2019 |

0.1.1 | Sep 8, 2019 |

0.1.0 | Sep 8, 2019 |

#**1463** in Rust patterns

**GPL-3.0-or-later**

27KB

204 lines

# These

represents a 3-way split of data. Think of it as a `These`

except that we have an extra case that can contain both the result `Result`

and
the error `T`

. This can be useful for when we can still compute the final result
but we have also encountered an error.`E`

`enum` `These`<T, U> `{`
This`(`T`)``,`
That`(`U`)``,`
Both`(`T`,` U`)`
`}`

We have three constructors

which holds a `This`

, `T`

which holds a `That`

,
and `U`

which holds both.`Both`

# Here and There

If we want to talk about all

s we use the terminology `T`

. So this
means we either have a `Here`

or `This`

. Or in code:`Both`

`use` `these``::`These`;`
`fn` `is_here``<`T`:` `Copy`, U`:` `Copy``>``(``these``:` `&``These``<`T, U`>``)`` ``->` `bool` `{`
these`.``is_this``(``)` `||` these`.``is_these``(``)`
`}`

If we want to talk about all

s we use the terminology `U`

. So this
means we either have a `There`

or `That`

. Or in code`Both`

`use` `these``::`These`;`
`fn` `is_here``<`T`:` `Copy`, U`:` `Copy``>``(``these``:` `These``<`T, U`>``)`` ``->` `bool` `{`
these`.``is_that``(``)` `||` these`.``is_these``(``)`
`}`

# Contrived Example

Let us say that we have a function that only allows numbers that are less than
10. We expose a new type

and expect our users to use `LessThanTen`

to validate `is_less_than_ten`

s into this type. We can use `i8`

and model this below:`Result`

`#``[``derive``(``Debug``,` PartialEq`)``]`
`struct` `LessThanTen``(``i8``)``;`
`#``[``derive``(``Debug``,` PartialEq`)``]`
`pub` `enum` `Error` `{`
IsGreaterThanOrEqualToTen`,`
`}`
`pub` `fn` `is_less_than_ten``(``i``:` `i8``)`` ``->` `Result``<`LessThanTen, Error`>` `{`
`if` i `<` `10` `{`
`Ok``(`LessThanTen`(`i`)``)`
`}` `else` `{`
`Err``(``Error``::`IsGreaterThanOrEqualToTen`)`
`}`
`}`
`assert_eq!``(``is_less_than_ten``(``8``)``,` `Ok``(`LessThanTen`(``8``)``)``)``;`
`assert_eq!``(``is_less_than_ten``(``10``)``,` `Err``(``Error``::`IsGreaterThanOrEqualToTen`)``)``;`

But after a while we realise we can start to support all numbers that are less than 20.
We can do a similar approach, but we would like to be backwards compatible, and also keep
track of when we encounter numbers that are greater than 10. Maybe we would like to keep
statistics on these errors, or convert successful results to

for backwards
compatibility. We can use `LessThanTen`

to solve this and can modelled as below:`These`

`use` `these``::`These`;`
`#``[``derive``(``Debug``,` PartialEq`)``]`
`struct` `LessThanTen``(``i8``)``;`
`#``[``derive``(``Debug``,` PartialEq`)``]`
`struct` `LessThanTwenty``(``i8``)``;`
`#``[``derive``(``Debug``,` PartialEq`)``]`
`pub` `enum` `Error` `{`
IsGreaterThanOrEqualToTen`,`
IsGreaterThanOrEqualToTwenty`,`
`}`
`pub` `fn` `is_less_than_ten``(``i``:` `i8``)`` ``->` `Result``<`LessThanTen, Error`>` `{`
`if` i `<` `10` `{`
`Ok``(`LessThanTen`(`i`)``)`
`}` `else` `{`
`Err``(``Error``::`IsGreaterThanOrEqualToTen`)`
`}`
`}`
`pub` `fn` `is_less_than_twenty``(``i``:` `i8``)`` ``->` `These``<`Error, LessThanTwenty`>` `{`
`if` i `<` `10` `{`
`These``::`That`(`LessThanTwenty`(`i`)``)`
`}` `else` `if` i `<` `20` `{`
`These``::`Both`(``Error``::`IsGreaterThanOrEqualToTen`,` LessThanTwenty`(`i`)``)`
`}` `else` `{`
`These``::`This`(``Error``::`IsGreaterThanOrEqualToTwenty`)`
`}`
`}`
`//` Convert to the backwards compatible scenario
`pub` `fn` `backwards_compatible``(``r``:` `These``<`Error, LessThanTwenty`>``)`` ``->` `Result``<`LessThanTen, Error`>` `{`
r`.``collapse_these``(`
`|``e``|` `Err``(`e`)``,`
`|``LessThanTwenty``(``i``)``|` `Ok``(`LessThanTen`(`i`)``)``,`
`|``e``,` _`|` `Err``(`e`)``,`
`)`
`}`
`assert_eq!``(``is_less_than_ten``(``8``)``,` `Ok``(`LessThanTen`(``8``)``)``)``;`
`assert_eq!``(``is_less_than_ten``(``10``)``,` `Err``(``Error``::`IsGreaterThanOrEqualToTen`)``)``;`
`assert_eq!``(``is_less_than_twenty``(``8``)``,` `These``::`That`(`LessThanTwenty`(``8``)``)``)``;`
`assert_eq!``(``is_less_than_twenty``(``10``)``,` `These``::`Both`(``Error``::`IsGreaterThanOrEqualToTen`,` LessThanTwenty`(``10``)``)``)``;`
`assert_eq!``(``is_less_than_twenty``(``20``)``,` `These``::`This`(``Error``::`IsGreaterThanOrEqualToTwenty`)``)``;`
`assert_eq!``(``backwards_compatible``(``is_less_than_twenty``(``8``)``)``,` `Ok``(`LessThanTen`(``8``)``)``)``;`