1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
// Copyright 2019 The Rust Project Contributors
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// 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 in the LICENSE file at the
// root of this repository, or online 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.
//
// Portions of this file are derived from the Option implementation in the
// libcore crate distributed as part of the Rust project. The original source
// code was retrieved on April 18, 2019 from:
//
// https://github.com/rust-lang/rust/blob/e928e9441157f63a776ba1f8773818838e0912ea/src/libcore/option.rs
//
// The original source code is subject to the terms of the MIT license, a copy
// of which can be found in the LICENSE file at the root of this repository.
//! Option utilities.
use std::fmt;
use std::ops::Deref;
use either::Either;
/// Extension methods for [`std::option::Option`].
pub trait OptionExt<T> {
/// Converts from `Option<&T>` to `Option<T::Owned>` when `T` implements
/// [`ToOwned`].
///
/// The canonical use case is converting from an `Option<&str>` to an
/// `Option<String>`.
///
/// The name is symmetric with [`Option::cloned`].
fn owned(&self) -> Option<<<T as Deref>::Target as ToOwned>::Owned>
where
T: Deref,
T::Target: ToOwned;
/// Returns a type that displays the option's value if it is present, or
/// the provided default otherwise.
///
/// # Examples
///
/// ```
/// use ore::option::OptionExt;
///
/// fn render(number: Option<i32>) -> String {
/// format!("Your lucky number is {}.", number.display_or("unknown"))
/// }
///
/// assert_eq!(render(Some(42)), "Your lucky number is 42.");
/// assert_eq!(render(None), "Your lucky number is unknown.");
/// ```
fn display_or<D>(self, default: D) -> Either<T, D>
where
T: fmt::Display,
D: fmt::Display;
/// Like [`OptionExt::display_or`], but the default value is computed
/// only if the option is `None`.
///
/// # Examples
///
/// ```
/// use ore::option::OptionExt;
///
/// fn render(number: Option<i32>, guess: i32) -> String {
/// format!(
/// "Your lucky number is {}.",
/// number.display_or_else(|| format!("unknown (best guess: {})", guess)),
/// )
/// }
///
/// assert_eq!(render(Some(42), 7), "Your lucky number is 42.");
/// assert_eq!(render(None, 7), "Your lucky number is unknown (best guess: 7).");
/// ```
fn display_or_else<D, R>(self, default: D) -> Either<T, R>
where
T: fmt::Display,
D: FnOnce() -> R,
R: fmt::Display;
}
impl<T> OptionExt<T> for Option<T> {
fn owned(&self) -> Option<<<T as Deref>::Target as ToOwned>::Owned>
where
T: Deref,
T::Target: ToOwned,
{
self.as_ref().map(|x| x.deref().to_owned())
}
fn display_or<D>(self, default: D) -> Either<T, D>
where
T: fmt::Display,
D: fmt::Display,
{
match self {
Some(t) => Either::Left(t),
None => Either::Right(default),
}
}
fn display_or_else<D, R>(self, default: D) -> Either<T, R>
where
T: fmt::Display,
D: FnOnce() -> R,
R: fmt::Display,
{
match self {
Some(t) => Either::Left(t),
None => Either::Right(default()),
}
}
}