tamer: convert::{ExpectFrom, ExpectInto}: New traits

These traits are intended to eliminate boilerplate, primarily in tests, in
situations where from/into is not expected to fail.

Given that TAMER must only panic for internal compiler errors, this should
not often be used outside of test cases.  Further, there may be better
options in the future (e.g. QNames could be statically compiled rather than
trying to convert at runtime, in this case).
main
Mike Gerwitz 2021-09-08 16:00:14 -04:00
parent 12bb88e4b5
commit 2586827d64
3 changed files with 109 additions and 6 deletions

View File

@ -0,0 +1,102 @@
// Additional type conversion abstractions
//
// Copyright (C) 2014-2021 Ryan Specialty Group, 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 std::convert::{TryFrom, TryInto};
use std::fmt::Debug;
/// 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`].
///
/// See the [module-level documentation](self) for more information.
pub trait ExpectFrom<T>: TryFrom<T>
where
<Self as TryFrom<T>>::Error: Debug,
{
fn expect_from(value: T, msg: &str) -> T {
T::try_from(value).expect(msg)
}
fn unwrap_from(value: T) -> T {
T::try_from(value).unwrap()
}
}
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,
{
fn expect_into(self, msg: &str) -> T {
self.try_into().expect(msg)
}
fn unwrap_into(self) -> T {
self.try_into().unwrap()
}
}
impl<T, U> ExpectInto<U> for T
where
T: TryInto<U>,
<T as TryInto<U>>::Error: Debug,
{
}

View File

@ -447,8 +447,8 @@ pub fn parser_from<Ix: SymbolIndexSize>(
#[cfg(test)]
mod test {
use super::*;
use crate::convert::ExpectInto;
use crate::sym::GlobalSymbolIntern;
use std::convert::TryInto;
type Ix = u16;
@ -461,7 +461,7 @@ mod test {
#[test]
fn attr_from_toks() {
let name: QName<Ix> = "attr".try_into().unwrap();
let name: QName<Ix> = "attr".unwrap_into();
let value = AttrValue::Escaped("value".intern());
let toks = std::array::IntoIter::new([
@ -484,7 +484,7 @@ mod test {
#[test]
fn empty_element_from_toks() {
let name = ("ns", "elem").try_into().unwrap();
let name = ("ns", "elem").unwrap_into();
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(name, *S),
@ -510,9 +510,9 @@ mod test {
#[test]
fn empty_element_with_attrs_from_toks() {
let name = ("ns", "elem").try_into().unwrap();
let attr1 = "a".try_into().unwrap();
let attr2 = "b".try_into().unwrap();
let name = ("ns", "elem").unwrap_into();
let attr1 = "a".unwrap_into();
let attr2 = "b".unwrap_into();
let val1 = AttrValue::Escaped("val1".intern());
let val2 = AttrValue::Escaped("val2".intern());

View File

@ -34,6 +34,7 @@ extern crate lazy_static;
#[cfg(feature = "wip-frontends")]
pub mod frontend;
pub mod convert;
pub mod fs;
pub mod ir;
pub mod ld;