tame/tamer/src/convert.rs

142 lines
4.3 KiB
Rust

// Additional type conversion abstractions
//
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
//
// This file is part of TAME.
//
// This program 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 3 of the License, or
// (at your option) any later version.
//
// This program 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.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//! TAMER opinionated traits for conversion between types.
//!
//! _This should not be used for error reporting to users!_
//! Panics in TAMER represent internal compiler errors.
//!
//! This module introduces two new traits:
//!
//! - [`ExpectFrom`] implemented for all [`TryFrom`]; and
//! - [`ExpectInto`] implemented for all [`TryInto`].
//!
//! These traits provide two new methods:
//!
//! - `expect_{from,into}`, which is equivalent to calling
//! [`Result::expect`] on the result; and
//! - `unwrap_{from,into}`, which is equivalent to calling
//! [`Result::unwrap`] on the result.
//!
//! These two traits are intended to eliminate boilerplate in situations
//! where _it is expected that these will never fail_.
//! There may be better options;
//! these are most useful in writing tests.
use crate::{
diagnose::{panic::DiagnosticPanic, NO_DESC},
f::ThunkOrStaticRef,
};
use std::{
convert::{TryFrom, TryInto},
fmt::{Debug, Display},
};
/// Safe type conversion that may panic under some circumstances.
///
/// This is implemented for every type implementing [`TryFrom`] and is
/// intended to be used in situations where we are certain that failure
/// cannot occur,
/// or where failure would otherwise be folowed by [`Result::expect`] or
/// [`Result::unwrap`].
///
/// Once Rust is further along with a sound trait impl specialization
/// implementation,
/// this system ought to utilize spans when available for diagnostic
/// messages.
///
/// See the [module-level documentation](self) for more information.
pub trait ExpectFrom<T>: TryFrom<T>
where
<Self as TryFrom<T>>::Error: Debug,
{
/// Attempt to convert `value` using `T::try_from`,
/// causing a panic with the given `msg` on failure.
///
/// Panics
/// ======
/// Causes a panic on failure.
fn expect_from<M: ThunkOrStaticRef<str>>(value: T, msg: M) -> Self
where
M::Output: Display,
{
Self::try_from(value).diagnostic_expect(|| NO_DESC, msg)
}
/// Attempt to convert and unwrap `value` using `T::try_from`.
///
/// Panics
/// ======
/// Causes a panic on failure.
fn unwrap_from(value: T) -> Self {
Self::try_from(value).diagnostic_unwrap(|| NO_DESC)
}
}
impl<T, U> ExpectFrom<U> for T
where
T: TryFrom<U>,
<T as TryFrom<U>>::Error: Debug,
{
}
/// An attempted conversion that consumes `self`,
/// which may or may not be expensive and will panic on failure.
///
/// This is implemented for every type implementing [`TryInto`] and is
/// intended to be used in situations where we are certain that failure
/// cannot occur,
/// or where failure would otherwise be folowed by [`Result::expect`] or
/// [`Result::unwrap`].
///
/// See the [module-level documentation](self) for more information.
pub trait ExpectInto<T>: TryInto<T>
where
<Self as TryInto<T>>::Error: Debug,
{
/// Attempt to convert a value using `self.try_into()`,
/// causing a panic with the given `msg` on failure.
///
/// Panics
/// ======
/// Causes a panic on failure.
fn expect_into<M: ThunkOrStaticRef<str>>(self, msg: M) -> T
where
M::Output: Display,
{
self.try_into().diagnostic_expect(|| NO_DESC, msg)
}
/// Attempt to convert and unwrap a value using `self.try_into()`.
///
/// Panics
/// ======
/// Causes a panic on failure.
fn unwrap_into(self) -> T {
self.try_into().diagnostic_unwrap(|| NO_DESC)
}
}
impl<T, U> ExpectInto<U> for T
where
T: TryInto<U>,
<T as TryInto<U>>::Error: Debug,
{
}