tamer: f: impl_mono_map! macro
This helps to remove some boilerplate. Testing this out in `asg::graph::object::tpl` before applying it to other things; really `Map` can just go away entirely then since it can be implemented in terms of `TryMap`, but maybe it should stick around for manual impls (implementing `TryMap` manually is more work). DEV-13163main
parent
3c9e1add20
commit
66512bf20d
|
@ -50,26 +50,9 @@ impl Tpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map<Span> for Tpl {
|
impl_mono_map! {
|
||||||
fn map(self, f: impl FnOnce(Span) -> Span) -> Self::Target {
|
Span => Tpl(@, shape),
|
||||||
match self {
|
TplShape => Tpl(span, @),
|
||||||
Self(span, shape) => Self(f(span), shape),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryMap<TplShape> for Tpl {
|
|
||||||
fn try_map<E>(
|
|
||||||
self,
|
|
||||||
f: impl FnOnce(TplShape) -> Self::FnResult<E>,
|
|
||||||
) -> Self::Result<E> {
|
|
||||||
match self {
|
|
||||||
Self(span, x) => match f(x) {
|
|
||||||
Ok(shape) => Ok(Self(span, shape)),
|
|
||||||
Err((shape, e)) => Err((Self(span, shape), e)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Tpl {
|
impl Display for Tpl {
|
||||||
|
@ -239,7 +222,7 @@ object_rel! {
|
||||||
let span = to_oi.resolve(asg).span();
|
let span = to_oi.resolve(asg).span();
|
||||||
|
|
||||||
from_oi.try_map_obj(asg, |tpl| {
|
from_oi.try_map_obj(asg, |tpl| {
|
||||||
tpl.try_map(|shape| {
|
tpl.try_map(|shape: TplShape| {
|
||||||
shape.try_adapt_to(TplShape::Expr(span), tpl_name)
|
shape.try_adapt_to(TplShape::Expr(span), tpl_name)
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
@ -269,7 +252,7 @@ object_rel! {
|
||||||
|
|
||||||
// TODO: Refactor; very similar to Expr edge above.
|
// TODO: Refactor; very similar to Expr edge above.
|
||||||
from_oi.try_map_obj(asg, |tpl| {
|
from_oi.try_map_obj(asg, |tpl| {
|
||||||
tpl.try_map(|shape| {
|
tpl.try_map(|shape: TplShape| {
|
||||||
shape.try_adapt_to(apply_shape, tpl_name)
|
shape.try_adapt_to(apply_shape, tpl_name)
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -180,6 +180,80 @@ pub trait TryMap<T, U = T>: Sized {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate monomorphic [`TryMap`] and [`Map`] implementations for the
|
||||||
|
/// provided type.
|
||||||
|
///
|
||||||
|
/// This macro is suitable for otherwise-boilerplate `impl`s for these
|
||||||
|
/// traits.
|
||||||
|
/// If you expect anything more than a generic `map` or `try_map` operation,
|
||||||
|
/// then you should implement the traits manually.
|
||||||
|
///
|
||||||
|
/// Only tuple structs are supported at present.
|
||||||
|
///
|
||||||
|
/// For example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate tamer;
|
||||||
|
/// # use tamer::impl_mono_map;
|
||||||
|
/// # use tamer::f::Map;
|
||||||
|
/// # fn main() {
|
||||||
|
/// #[derive(Debug, PartialEq)]
|
||||||
|
/// struct Foo(u8, Bar);
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, PartialEq)]
|
||||||
|
/// enum Bar { A, B };
|
||||||
|
///
|
||||||
|
/// impl_mono_map! {
|
||||||
|
/// u8 => Foo(@, bar),
|
||||||
|
/// Bar => Foo(n, @),
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// assert_eq!(Foo(5, Bar::A).overwrite(Bar::B), Foo(5, Bar::B));
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Each line above generates a pair of `impl`s,
|
||||||
|
/// each for `Foo`,
|
||||||
|
/// where `@` represents the tuple item being mapped over.
|
||||||
|
#[macro_export] // for doc test above
|
||||||
|
macro_rules! impl_mono_map {
|
||||||
|
($($t:ty => $tup:ident( $($pre:ident,)* @ $(, $post:ident),* ),)+) => {
|
||||||
|
$(
|
||||||
|
impl $crate::f::TryMap<$t> for $tup {
|
||||||
|
fn try_map<E>(
|
||||||
|
self,
|
||||||
|
f: impl FnOnce($t) -> Self::FnResult<E>,
|
||||||
|
) -> Self::Result<E> {
|
||||||
|
match self {
|
||||||
|
Self($($pre,)* x $(, $post),*) => match f(x) {
|
||||||
|
Ok(y) => Ok(Self($($pre,)* y $(, $post),*)),
|
||||||
|
Err((y, e)) => Err((
|
||||||
|
Self($($pre,)* y $(, $post),*),
|
||||||
|
e,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::f::Map<$t> for $tup {
|
||||||
|
fn map(self, f: impl FnOnce($t) -> $t) -> Self::Target {
|
||||||
|
use std::convert::Infallible;
|
||||||
|
use $crate::f::TryMap;
|
||||||
|
|
||||||
|
// `unwrap()` requires `E: Debug`,
|
||||||
|
// so this avoids that bound.
|
||||||
|
match self.try_map::<Infallible>(|x| Ok(f(x))) {
|
||||||
|
Ok(y) => y,
|
||||||
|
// Verbosely emphasize unreachability
|
||||||
|
Err::<_, (_, Infallible)>(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A nullary [`Fn`] delaying some computation.
|
/// A nullary [`Fn`] delaying some computation.
|
||||||
///
|
///
|
||||||
/// For the history and usage of this term in computing,
|
/// For the history and usage of this term in computing,
|
||||||
|
|
|
@ -253,6 +253,8 @@ pub mod global;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod f;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod diagnose;
|
pub mod diagnose;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -260,7 +262,6 @@ pub mod xir;
|
||||||
|
|
||||||
pub mod asg;
|
pub mod asg;
|
||||||
pub mod convert;
|
pub mod convert;
|
||||||
pub mod f;
|
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
|
|
Loading…
Reference in New Issue