Created
July 29, 2018 22:52
-
-
Save ExpHP/bed01185efadf28a5b44768a0736617b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/crates.d/crates.toml b/crates.d/crates.toml | |
| index d5c2351..480de2a 100644 | |
| --- a/crates.d/crates.toml | |
| +++ b/crates.d/crates.toml | |
| @@ -85,3 +85,4 @@ lammps-sys = { tag = "v0.3.0", git = "https://github.com/ExpHP/lammps-sys" } | |
| rayon = "0.8" | |
| vasp-poscar = "0.1.1" | |
| path_abs = { rev = "72c767cfabe27", git = "https://github.com/vitiral/path_abs" } | |
| +frunk = "0.1.36" | |
| diff --git a/crates.d/rsp2-tasks.Cargo.toml b/crates.d/rsp2-tasks.Cargo.toml | |
| index a7a0862..c44bc29 100644 | |
| --- a/crates.d/rsp2-tasks.Cargo.toml | |
| +++ b/crates.d/rsp2-tasks.Cargo.toml | |
| @@ -40,3 +40,4 @@ path = "lib.rs" | |
| !!serde-json | |
| !!serde-yaml | |
| !!path-abs | |
| +!!frunk | |
| diff --git a/src/tasks/Cargo.toml b/src/tasks/Cargo.toml | |
| index c1d320e..415ebfa 100644 | |
| --- a/src/tasks/Cargo.toml | |
| +++ b/src/tasks/Cargo.toml | |
| @@ -45,3 +45,4 @@ serde_derive = "1" | |
| serde_json = "1" | |
| serde_yaml = "0.7" | |
| path_abs = { rev = "72c767cfabe27", git = "https://github.com/vitiral/path_abs" } | |
| +frunk = "0.1.36" | |
| diff --git a/src/tasks/cmd/ev_analyses.rs b/src/tasks/cmd/ev_analyses.rs | |
| index 0fe101a..e556900 100644 | |
| --- a/src/tasks/cmd/ev_analyses.rs | |
| +++ b/src/tasks/cmd/ev_analyses.rs | |
| @@ -1,14 +1,16 @@ | |
| - | |
| - | |
| -use ::errors::{Result, ok}; | |
| use ::ui::color::{ColorByRange, PaintAs, NullPainter}; | |
| -use ::ui::cfg_merging::{no_summary, merge_summaries, make_nested_mapping}; | |
| +use ::ui::cfg_merging::{merge_summaries, make_nested_mapping, no_summary}; | |
| use ::util::zip_eq; | |
| use ::types::basis::Basis3; | |
| use ::math::bands::{GammaUnfolder, ScMatrix}; | |
| +use ::std::rc::Rc; | |
| +use ::std::mem; | |
| +use ::traits::alternate::{FnOnce, FnMut, Fn, StdFnMut, CallT}; | |
| +use ::std::cell::RefCell; | |
| +use ::rsp2_tasks_config::Settings; | |
| +use ::errors::{StdResult, Result, ok}; | |
| #[allow(unused)] // compiler bug | |
| use ::itertools::Itertools; | |
| -use ::rsp2_tasks_config::Settings; | |
| #[allow(unused)] // compiler bug | |
| use ::rsp2_structure::{CoordStructure, Part, Partition}; | |
| @@ -16,6 +18,718 @@ use ::rsp2_structure::{CoordStructure, Part, Partition}; | |
| use ::std::fmt; | |
| use ::serde_yaml::Value as YamlValue; | |
| +mod cached { | |
| + use super::*; | |
| + use ::traits::alternate::{FnOnce}; | |
| + use self::inductive::hlist::{HList1, HNil}; | |
| + | |
| + // NOTE: All clones must be tied to the same cache. | |
| + pub trait Cached: Clone { | |
| + type Value; | |
| + | |
| + fn call_cached(&self) -> Rc<Self::Value>; | |
| + } | |
| + | |
| + pub struct Constant<A>(Rc<A>); | |
| + impl<A> Clone for Constant<A> { | |
| + fn clone(&self) -> Self { Constant(self.0.clone()) } | |
| + } | |
| + | |
| + impl<A> Constant<A> { | |
| + pub fn new(a: A) -> Self { Constant(Rc::new(a)) } | |
| + } | |
| + | |
| + impl<A> Cached for Constant<A> { | |
| + type Value = A; | |
| + fn call_cached(&self) -> Rc<A> { self.0.clone() } | |
| + } | |
| + | |
| + pub use self::function::Function; | |
| + mod function { | |
| + use super::*; | |
| + | |
| + pub struct Function<R, F>(Rc<RefCell<Inner<R, F>>>); | |
| + impl<R, F> Clone for Function<R, F> { | |
| + fn clone(&self) -> Self { Function(self.0.clone()) } | |
| + } | |
| + | |
| + enum Inner<R, F> { | |
| + Result(Rc<R>), | |
| + Func(F), | |
| + MidComputation, | |
| + } | |
| + | |
| + impl<R, F> Cached for Function<R, F> where F: FnOnce<HNil, Output=Rc<R>> { | |
| + type Value = R; | |
| + | |
| + fn call_cached(&self) -> Rc<R> { | |
| + let mut inner = self.0.borrow_mut(); | |
| + let result = match mem::replace(&mut *inner, Inner::MidComputation) { | |
| + Inner::MidComputation => panic!("detected cyclic dependency in Cached objects!"), | |
| + Inner::Func(f) => f.call_once(HNil), | |
| + Inner::Result(r) => r, | |
| + }; | |
| + *inner = Inner::Result(result.clone()); | |
| + result | |
| + } | |
| + } | |
| + } | |
| + | |
| + pub use self::map::Map; | |
| + mod map { | |
| + use super::*; | |
| + | |
| + pub struct Map<A, R, F>(Function<R, Closure<A, F>>); | |
| + impl<A, R, F> Clone for Map<A, R, F> { | |
| + fn clone(&self) -> Self { Map(self.0.clone()) } | |
| + } | |
| + | |
| + struct Closure<A, F> { | |
| + arg: A, | |
| + continuation: F, | |
| + } | |
| + | |
| + impl<W, A, R, F> FnOnce<HNil> for Closure<A, F> | |
| + where A: Cached<Value=W>, F: FnOnce<HList1<Rc<W>>, Output=Rc<R>>, | |
| + { | |
| + type Output = Rc<R>; | |
| + | |
| + fn call_once(self, HNil: HNil) -> Rc<R> | |
| + { self.continuation.call_once(hlist![self.arg.call_cached()]) } | |
| + } | |
| + | |
| + impl<W, A, R, F> Cached for Map<A, R, F> | |
| + where A: Cached<Value=W>, F: FnOnce<HList1<Rc<W>>, Output=Rc<R>>, | |
| + { | |
| + type Value = R; | |
| + | |
| + fn call_cached(&self) -> Rc<R> | |
| + { self.0.call_cached() } | |
| + } | |
| + } | |
| + | |
| + pub use self::and_then::AndThen; | |
| + mod and_then { | |
| + use super::*; | |
| + | |
| + pub struct AndThen<A, R, F>(Function<R, Closure<A, F>>); | |
| + impl<A, R, F> Clone for AndThen<A, R, F> { | |
| + fn clone(&self) -> Self { AndThen(self.0.clone()) } | |
| + } | |
| + | |
| + struct Closure<A, F> { | |
| + arg: A, | |
| + continuation: F, | |
| + } | |
| + | |
| + impl<D, W, A, R, F> FnOnce<HNil> for Closure<A, F> | |
| + where A: Cached<Value=W>, F: FnOnce<HList1<Rc<W>>, Output=D>, D: Cached<Value=R>, | |
| + { | |
| + type Output = Rc<R>; | |
| + | |
| + fn call_once(self, HNil: HNil) -> Rc<R> | |
| + { self.continuation.call_once(hlist![self.arg.call_cached()]).call_cached() } | |
| + } | |
| + | |
| + impl<D, W, A, R, F> Cached for AndThen<A, R, F> | |
| + where A: Cached<Value=W>, F: FnOnce<HList1<Rc<W>>, Output=D>, D: Cached<Value=R>, | |
| + { | |
| + type Value = R; | |
| + | |
| + fn call_cached(&self) -> Rc<R> | |
| + { self.0.call_cached() } | |
| + } | |
| + } | |
| +} | |
| + | |
| +mod closures { | |
| + use super::*; | |
| + use self::inductive::hlist::{HList, HNil, HCons, HList1, HList2, h_cons}; | |
| + | |
| + #[derive(Debug, Copy, Clone, Default)] | |
| + pub struct Id; | |
| + derive_alternate_fn! { | |
| + impl[X] Fn<Hlist![X]> for Id { | |
| + type Output = X; | |
| + | |
| + fn call(&self, hlist_pat![x]: Hlist![X]) -> X | |
| + { x } | |
| + } | |
| + } | |
| + | |
| + /// Variadic function that puts all its arguments into one HList. | |
| + /// | |
| + /// This function has no inverse, since a function can only have one output. | |
| + /// (instead, you must use an HOF adapter like `OnHLists`) | |
| + #[derive(Debug, Copy, Clone, Default)] | |
| + pub struct MakeHList; | |
| + derive_alternate_fn! { | |
| + impl[X: HList] Fn<X> for MakeHList { | |
| + type Output = X; | |
| + | |
| + fn call(&self, x: X) -> X | |
| + { x } | |
| + } | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + pub type SwapT<List> = <Swap as FnOnce<List>>::Output; | |
| + | |
| + /// Swap the first two elements of an HList. | |
| + #[derive(Debug, Copy, Clone, Default)] | |
| + pub struct Swap; | |
| + derive_alternate_fn! { | |
| + impl[A, B, Rest: HList] Fn<HList1<HCons<A, HCons<B, Rest>>>> for Swap { | |
| + type Output = HCons<B, HCons<A, Rest>>; | |
| + | |
| + fn call(&self, hlist_pat![list]: HList1<HCons<A, HCons<B, Rest>>>) -> Self::Output { | |
| + let (a, list) = list.pop(); | |
| + let (b, list) = list.pop(); | |
| + h_cons(b, h_cons(a, list)) | |
| + } | |
| + } | |
| + } | |
| + | |
| + /// Make a function of multiple arguments act on one HList. | |
| + /// | |
| + /// Similar in spirit to Haskell's `uncurry`. | |
| + #[derive(Debug, Copy, Clone, Default)] | |
| + pub struct OnHLists<F>(pub F); | |
| + | |
| + /// Inverse of `OnHLists`. Make a function of HList act on multiple arguments. | |
| + pub type UnHLists<F> = Of<F, MakeHList>; | |
| + /// Fake constructor for `UnHLists`. | |
| + #[allow(bad_style)] | |
| + pub fn UnHLists<F>(f: F) -> UnHLists<F> { Of(f, MakeHList) } | |
| + | |
| + impl<F, L: HList> Fn<HList1<L>> for OnHLists<F> | |
| + where F: Fn<L>, | |
| + { | |
| + fn call(&self, hlist_pat![list]: HList1<L>) -> Self::Output | |
| + { self.0.call(list) } | |
| + } | |
| + | |
| + impl<F, L: HList> FnMut<HList1<L>> for OnHLists<F> | |
| + where F: FnMut<L>, | |
| + { | |
| + fn call_mut(&mut self, hlist_pat![list]: HList1<L>) -> Self::Output | |
| + { self.0.call_mut(list) } | |
| + } | |
| + | |
| + impl<F, L: HList> FnOnce<HList1<L>> for OnHLists<F> | |
| + where F: FnOnce<L>, | |
| + { | |
| + type Output = F::Output; | |
| + | |
| + fn call_once(self, hlist_pat![list]: HList1<L>) -> Self::Output | |
| + { self.0.call_once(list) } | |
| + } | |
| + | |
| + /// Flip the first two arguments of a function. | |
| + /// | |
| + /// Even though this is just a type alias, you can construct one | |
| + /// by writing `Flip(f)`. (this is because in reality, there is | |
| + /// also a free function with the same name) | |
| + pub type Flip<F> = UnHLists<Of<OnHLists<F>, Swap>>; | |
| + | |
| + /// Constructor for the type `Flip<F>`. | |
| + #[allow(bad_style)] | |
| + pub fn Flip<F>(f: F) -> Flip<F> | |
| + { UnHLists(Of(OnHLists(f), Swap)) } | |
| + | |
| + #[allow(unused)] | |
| + fn test_on_hlist() { | |
| + assert_eq!(OnHLists(|a, b| a + b).call_once(hlist![hlist![1, 5]]), 6); | |
| + assert_eq!(UnHLists(|hlist_pat![a, b]| a + b).call_once(hlist![1, 5]), 6); | |
| + | |
| + let v = vec![3]; | |
| + assert_eq!(OnHLists(|| v).call_once(hlist![hlist![]]), vec![3]); | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + fn test_swap() { | |
| + assert_eq!(Swap.call_once(hlist![hlist![1, 5]]), hlist![5, 1]); | |
| + assert_eq!(Swap.call_once(hlist![hlist![1, 5, 4]]), hlist![5, 1, 4]); | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + fn test_flip() { | |
| + assert_eq!(Fn::call(&Flip(|a, b| a - b ), hlist![1, 5] ), 4); | |
| + assert_eq!(Fn::call(&Flip(|a, b, c| (a - b) * c), hlist![1, 5, 7]), 28); | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + pub type OfT<F, G, Args> = <Of<F, G> as FnOnce<Args>>::Output; | |
| + #[derive(Debug, Copy, Clone, Default)] | |
| + pub struct Of<F, G>(pub F, pub G); | |
| + impl<Args: HList, B, C, F, G> Fn<Args> for Of<F, G> | |
| + where | |
| + G: Fn<Args, Output=B>, | |
| + F: Fn<HList1<B>, Output=C>, | |
| + { | |
| + fn call(&self, args: Args) -> C | |
| + { self.0.call(hlist![self.1.call(args)]) } | |
| + } | |
| + | |
| + impl<Args: HList, B, C, F, G> FnMut<Args> for Of<F, G> | |
| + where | |
| + G: FnMut<Args, Output=B>, | |
| + F: FnMut<HList1<B>, Output=C>, | |
| + { | |
| + fn call_mut(&mut self, args: Args) -> C | |
| + { self.0.call_mut(hlist![self.1.call_mut(args)]) } | |
| + } | |
| + | |
| + impl<Args: HList, B, C, F, G> FnOnce<Args> for Of<F, G> | |
| + where | |
| + G: FnOnce<Args, Output=B>, | |
| + F: FnOnce<HList1<B>, Output=C>, | |
| + { | |
| + type Output = C; | |
| + | |
| + fn call_once(self, args: Args) -> C | |
| + { self.0.call_once(hlist![self.1.call_once(args)]) } | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + fn test_of() { | |
| + struct A; struct B; struct C; | |
| + struct F; struct G; | |
| + impl FnOnce<HList1<A>> for F { | |
| + type Output = B; | |
| + fn call_once(self, _: HList1<A>) -> B { B } | |
| + } | |
| + impl FnOnce<HList1<B>> for G { | |
| + type Output = C; | |
| + fn call_once(self, _: HList1<B>) -> C { C } | |
| + } | |
| + let _: B = F.call_once(hlist![A]); | |
| + let _: C = G.call_once(hlist![B]); | |
| + let _: C = Of(G, F).call_once(hlist![A]); | |
| + } | |
| +} | |
| + | |
| +/// Inductive types, to assist traits that simulate variadic generics. | |
| +pub mod inductive { | |
| + use super::*; | |
| + | |
| + pub use self::peano::{P0, Succ, IsPeano, Pred}; | |
| + pub mod peano { | |
| + use super::*; | |
| + | |
| + pub use self::constants::*; | |
| + pub mod constants { | |
| + use super::*; | |
| + pub use super::P0; | |
| + #[doc = "Peano integer."] pub type P1 = Succ<P0>; | |
| + #[doc = "Peano integer."] pub type P2 = Succ<P1>; | |
| + #[doc = "Peano integer."] pub type P3 = Succ<P2>; | |
| + #[doc = "Peano integer."] pub type P4 = Succ<P3>; | |
| + #[doc = "Peano integer."] pub type P5 = Succ<P4>; | |
| + #[doc = "Peano integer."] pub type P6 = Succ<P5>; | |
| + #[doc = "Peano integer."] pub type P7 = Succ<P6>; | |
| + #[doc = "Peano integer."] pub type P8 = Succ<P7>; | |
| + #[doc = "Peano integer."] pub type P9 = Succ<P8>; | |
| + } | |
| + | |
| + /// The Peano integer zero. (base case) | |
| + #[derive(Debug, Default, Copy, Clone)] | |
| + pub struct P0; | |
| + | |
| + /// A Peano integer incremented by 1. (inductive case) | |
| + #[derive(Debug, Default, Copy, Clone)] | |
| + pub struct Succ<A: IsPeano>(pub A); | |
| + | |
| + /// Marker trait for Peano integers, for "type safety" within the type system. | |
| + pub trait IsPeano {} | |
| + impl IsPeano for P0 {} | |
| + impl<N: IsPeano> IsPeano for Succ<N> {} | |
| + | |
| + /// Subtract 1 from a nonzero Peano integer. | |
| + /// | |
| + /// More accurately, this solves the equation `p + 1 = x` for `p`. | |
| + pub type Pred<A> = <A as Positive>::Pred; | |
| + | |
| + pub trait Positive: IsPeano { | |
| + type Pred: IsPeano; | |
| + } | |
| + | |
| + impl<N: IsPeano> Positive for Succ<N> { | |
| + type Pred = N; | |
| + } | |
| + } | |
| + | |
| + pub mod hlist { | |
| + use super::*; | |
| + | |
| + pub use frunk::hlist::{HList, HCons, HNil, h_cons}; | |
| + | |
| + // wake me up when clion can parse type macros properly | |
| + pub type HList1<A> = HCons<A, HNil>; | |
| + pub type HList2<A, B> = HCons<A, HList1<B>>; | |
| + pub type HList3<A, B, C> = HCons<A, HList2<B, C>>; | |
| + pub type HList4<A, B, C, D> = HCons<A, HList3<B, C, D>>; | |
| + | |
| + //---------------- | |
| + | |
| + #[doc(hidden)] | |
| + pub type MapT<List, F> = <List as Map<F>>::Output; | |
| + | |
| + pub trait Map<F>: HList { | |
| + type Output: HList; | |
| + | |
| + fn map(self, f: F) -> Self::Output; | |
| + } | |
| + | |
| + impl<F> Map<F> for HNil { | |
| + type Output = HNil; | |
| + | |
| + #[inline(always)] | |
| + fn map(self, _: F) -> Self::Output | |
| + { HNil } | |
| + } | |
| + | |
| + impl<A, B, Rest: Map<F>, F> Map<F> for HCons<A, Rest> | |
| + where F: FnMut<HList1<A>, Output=B>, | |
| + { | |
| + type Output = HCons<B, MapT<Rest, F>>; | |
| + | |
| + #[inline(always)] | |
| + fn map(self, mut f: F) -> Self::Output { | |
| + let (a, rest) = self.pop(); | |
| + h_cons(f.call_mut(hlist![a]), rest.map(f)) | |
| + } | |
| + } | |
| + | |
| + //---------------- | |
| + | |
| + pub struct HConsClosure; | |
| + derive_alternate_fn! { | |
| + impl[A, List: HList] Fn<Hlist![A, List]> for HConsClosure { | |
| + type Output = HCons<A, List>; | |
| + | |
| + fn call(&self, hlist_pat![a, list]: Hlist![A, List]) -> Self::Output | |
| + { h_cons(a, list) } | |
| + } | |
| + } | |
| + | |
| + | |
| + pub struct ReverseClosure; | |
| + derive_alternate_fn! { | |
| + impl[List: ::frunk::hlist::IntoReverse] Fn<Hlist![List]> for hlist::ReverseClosure { | |
| + type Output = List::Output; | |
| + | |
| + fn call(&self, hlist_pat![list]: Hlist![List]) -> Self::Output | |
| + { list.into_reverse() } | |
| + } | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + fn test_reverse() { | |
| + struct A; struct B; struct C; | |
| + let hlist_pat![] = ReverseClosure.call_once(hlist![hlist![]]); | |
| + let hlist_pat![A] = ReverseClosure.call_once(hlist![hlist![A]]); | |
| + let hlist_pat![B, A] = ReverseClosure.call_once(hlist![hlist![A, B]]); | |
| + let hlist_pat![C, B, A] = ReverseClosure.call_once(hlist![hlist![A, B, C]]); | |
| + } | |
| + } | |
| +} | |
| + | |
| +pub mod option { | |
| + use super::*; | |
| + use ::std::ops::{Deref, DerefMut}; | |
| + use ::std::marker::PhantomData; | |
| + use self::inductive::hlist::{self, HNil, HCons, HList, HList1, HList2}; | |
| + | |
| + #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Default)] | |
| + pub struct Just<T>(pub T); | |
| + #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] | |
| + pub struct Nothing<T>(pub PhantomData<T>); | |
| + pub type Maybe<T> = Option<T>; | |
| + | |
| + // for type-level type-checking | |
| + pub trait IsMaybe { } | |
| + impl<T> IsMaybe for Just<T> { } | |
| + impl<T> IsMaybe for Maybe<T> { } | |
| + impl<T> IsMaybe for Nothing<T> { } | |
| + | |
| + impl<T> Deref for Just<T> { | |
| + type Target = T; | |
| + | |
| + fn deref(&self) -> &Self::Target | |
| + { &self.0 } | |
| + } | |
| + | |
| + impl<T> DerefMut for Just<T> { | |
| + fn deref_mut(&mut self) -> &mut Self::Target | |
| + { &mut self.0 } | |
| + } | |
| + | |
| + impl<T> Default for Nothing<T> { fn default() -> Self { Nothing(Default::default()) } } | |
| + impl<T> Clone for Nothing<T> { fn clone(&self) -> Self { Default::default() } } | |
| + impl<T> Copy for Nothing<T> { } | |
| + | |
| + #[allow(unused)] | |
| + pub type MapT<A, F> = <A as Map<F>>::Output; | |
| + pub trait Map<F>: Sized + IsMaybe { | |
| + type Output; | |
| + | |
| + fn map(self, f: F) -> Self::Output; | |
| + } | |
| + | |
| + impl<A, B, F: FnOnce<HList1<A>, Output=B>> Map<F> for Just<A> { | |
| + type Output = Just<B>; | |
| + | |
| + fn map(self, f: F) -> Self::Output | |
| + { Just(f.call_once(hlist![self.0])) } | |
| + } | |
| + | |
| + impl<A, B, F: FnOnce<HList1<A>, Output=B>> Map<F> for Maybe<A> { | |
| + type Output = Maybe<B>; | |
| + | |
| + fn map(self, f: F) -> Self::Output | |
| + { Option::map(self, |x| f.call_once(hlist![x])) } | |
| + } | |
| + | |
| + impl<A, B, F: FnOnce<HList1<A>, Output=B>> Map<F> for Nothing<A> { | |
| + type Output = Nothing<B>; | |
| + | |
| + fn map(self, _: F) -> Self::Output | |
| + { Default::default() } | |
| + } | |
| + | |
| +// #[allow(unused)] | |
| +// pub type ZipT<A, B> = ZipWithT<closures::MakeTuple, A, B>; | |
| +// pub trait Zip<Rhs: IntoMaybe>: ZipWith<Rhs, closures::MakeTuple> { | |
| +// fn zip(self, other: Rhs) -> Self::Output; | |
| +// } | |
| +// impl<A, B: IntoMaybe> Zip<B> for A where A: ZipWith<B, closures::MakeTuple> { | |
| +// fn zip(self, other: B) -> Self::Output | |
| +// { self.zip_with(other, closures::MakeTuple) } | |
| +// } | |
| + | |
| + #[allow(unused)] | |
| + pub type ZipWithT<F, A, B> = <A as ZipWith<B, F>>::Output; | |
| + pub trait ZipWith<Rhs: IntoMaybe, F>: Sized + IntoMaybe { | |
| + type Output; | |
| + | |
| + fn zip_with(self, other: Rhs, f: F) -> Self::Output; | |
| + } | |
| + | |
| + pub use self::list_zip::{ListZip, ListZipT}; | |
| + mod list_zip { | |
| + use super::*; | |
| + | |
| + #[allow(unused)] | |
| + pub type ListZipT<List> = <List as ListZip>::Output; | |
| + pub trait ListZip: HList { | |
| + type Output: IsMaybe; | |
| + | |
| + fn list_zip(self) -> Self::Output; | |
| + } | |
| + | |
| + impl<List: Impl> ListZip for List | |
| + where | |
| + ImplT<Self>: Map<hlist::ReverseClosure>, | |
| + MapT<ImplT<Self>, hlist::ReverseClosure>: IsMaybe, | |
| + { | |
| + type Output = MapT<ImplT<Self>, hlist::ReverseClosure>; | |
| + | |
| + fn list_zip(self) -> Self::Output | |
| + { | |
| + let maybe_reversed = self.rec(Just(HNil)); | |
| + maybe_reversed.map(hlist::ReverseClosure) | |
| + } | |
| + } | |
| + | |
| + pub type ImplInit = Just<HNil>; | |
| + pub type ImplT<List> = <List as Impl>::Output; | |
| + pub trait Impl<Acc: IsMaybe = ImplInit>: HList { | |
| + type Output: IsMaybe; | |
| + | |
| + fn rec(self, acc: Acc) -> Self::Output; | |
| + } | |
| + | |
| + impl<Acc: IsMaybe> Impl<Acc> for HNil { | |
| + type Output = Acc; | |
| + | |
| + fn rec(self, acc: Acc) -> Self::Output { acc } | |
| + } | |
| + | |
| + impl< | |
| + A: IntoMaybe<TyArg=AInner> + ZipWith<Acc, hlist::HConsClosure, Output=Z>, | |
| + Acc: IntoMaybe<TyArg=AccInner>, | |
| + AccInner, | |
| + AInner, | |
| + Z: IsMaybe, | |
| + Rest: Impl<Z, Output=R>, | |
| + R: IsMaybe, | |
| + > Impl<Acc> for HCons<A, Rest> | |
| + { | |
| + type Output = R; | |
| + | |
| + fn rec(self, acc: Acc) -> Self::Output | |
| + { self.tail.rec(self.head.zip_with(acc, hlist::HConsClosure)) } | |
| + } | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + pub type AsRefT<A> = <A as AsRef>::Output; | |
| + pub trait AsRef { | |
| + type Output; | |
| + | |
| + fn as_ref(self) -> Self::Output; | |
| + } | |
| + | |
| + impl<'a, A> AsRef for &'a Maybe<A> { | |
| + type Output = Maybe<&'a A>; | |
| + | |
| + fn as_ref(self) -> Self::Output | |
| + { Option::as_ref(self) } | |
| + } | |
| + | |
| + impl<'a, A> AsRef for &'a Just<A> { | |
| + type Output = Just<&'a A>; | |
| + | |
| + fn as_ref(self) -> Self::Output | |
| + { Just(&self.0) } | |
| + } | |
| + | |
| + impl<'a, A> AsRef for &'a Nothing<A> { | |
| + type Output = Nothing<&'a A>; | |
| + | |
| + fn as_ref(self) -> Self::Output | |
| + { Default::default() } | |
| + } | |
| + | |
| + #[derive(Debug, Copy, Clone, Default)] | |
| + pub struct AsRefClosure; | |
| + derive_alternate_fn! { | |
| + impl[A: AsRef] Fn<HList1<A>> for AsRefClosure { | |
| + type Output = AsRefT<A>; | |
| + | |
| + fn call(&self, hlist_pat![a]: HList1<A>) -> Self::Output | |
| + { a.as_ref() } | |
| + } | |
| + } | |
| + | |
| + pub trait IntoMaybe: IsMaybe { | |
| + type TyArg; | |
| + | |
| + fn into_maybe(self) -> Maybe<Self::TyArg>; | |
| + fn as_maybe(&self) -> Maybe<&Self::TyArg>; | |
| + } | |
| + | |
| + impl<A> IntoMaybe for Just<A> { | |
| + type TyArg = A; | |
| + | |
| + fn into_maybe(self) -> Maybe<A> { Some(self.0) } | |
| + fn as_maybe(&self) -> Maybe<&A> { Some(&self.0) } | |
| + } | |
| + | |
| + impl<A> IntoMaybe for Maybe<A> { | |
| + type TyArg = A; | |
| + | |
| + fn into_maybe(self) -> Maybe<A> { self } | |
| + fn as_maybe(&self) -> Maybe<&A> { self.as_ref() } | |
| + } | |
| + | |
| + impl<A> IntoMaybe for Nothing<A> { | |
| + type TyArg = A; | |
| + | |
| + fn into_maybe(self) -> Maybe<A> { None } | |
| + fn as_maybe(&self) -> Maybe<&A> { None } | |
| + } | |
| + | |
| + pub trait ExpectFromOption<B>: IsMaybe { | |
| + fn expect_from(b: Option<B>) -> Self; | |
| + } | |
| + | |
| + impl<A> ExpectFromOption<A> for Maybe<A> { | |
| + fn expect_from(a: Option<A>) -> Self { a } | |
| + } | |
| + | |
| + impl<A> ExpectFromOption<A> for Just<A> { | |
| + fn expect_from(a: Option<A>) -> Self { Just(a.unwrap()) } | |
| + } | |
| + | |
| + impl<A> ExpectFromOption<A> for Nothing<A> { | |
| + fn expect_from(a: Option<A>) -> Self | |
| + { match a { | |
| + Some(_) => panic!("expect_from: expected nothing, got Some(_)!"), | |
| + None => Default::default(), | |
| + }} | |
| + } | |
| + | |
| + #[allow(unused)] | |
| + pub type FoldOkT<A> = <A as FoldOk>::Output; | |
| + pub trait FoldOk { | |
| + type Output; | |
| + | |
| + fn fold_ok(self) -> Self::Output; | |
| + } | |
| + | |
| + impl<A, E> FoldOk for Maybe<StdResult<A, E>> { | |
| + type Output = StdResult<Maybe<A>, E>; | |
| + | |
| + fn fold_ok(self) -> Self::Output | |
| + { match self { | |
| + Some(x) => Ok(Some(x?)), | |
| + None => Ok(None), | |
| + }} | |
| + } | |
| + | |
| + impl<A, E> FoldOk for Just<StdResult<A, E>> { | |
| + type Output = StdResult<Just<A>, E>; | |
| + | |
| + fn fold_ok(self) -> Self::Output | |
| + { Ok(Just(self.0?)) } | |
| + } | |
| + | |
| + | |
| + impl<A, E> FoldOk for Nothing<StdResult<A, E>> { | |
| + type Output = StdResult<Nothing<A>, E>; | |
| + | |
| + fn fold_ok(self) -> Self::Output | |
| + { Ok(Default::default()) } | |
| + } | |
| + | |
| + macro_rules! impl_zip_with { | |
| + ( $( [$A:ident, $B:ident] => $C:ident;)* ) | |
| + => { | |
| + $( | |
| + impl<A, B, C, F: FnOnce<HList2<A, B>, Output=C>> ZipWith<$B<B>, F> for $A<A> | |
| + where F: FnOnce<HList2<A, B>>, | |
| + { | |
| + type Output = $C<C>; | |
| + | |
| + fn zip_with(self, other: $B<B>, f: F) -> Self::Output { | |
| + ExpectFromOption::expect_from({ | |
| + match (self.into_maybe(), other.into_maybe()) { | |
| + (Some(a), Some(b)) => Some(f.call_once(hlist![a, b])), | |
| + _ => None, | |
| + } | |
| + }) | |
| + } | |
| + } | |
| + )* | |
| + }; | |
| + } | |
| + | |
| + impl_zip_with!{ | |
| + [Nothing, Nothing] => Nothing; | |
| + [ Maybe, Nothing] => Nothing; | |
| + [ Just, Nothing] => Nothing; | |
| + [Nothing, Maybe] => Nothing; | |
| + [Nothing, Just] => Nothing; | |
| + [ Maybe, Maybe] => Maybe; | |
| + [ Maybe, Just] => Maybe; | |
| + [ Just, Maybe] => Maybe; | |
| + [ Just, Just] => Just; | |
| + } | |
| +} | |
| + | |
| + | |
| #[derive(Debug, Clone)] pub struct AtomCoordinates(pub CoordStructure); | |
| #[derive(Debug, Clone)] pub struct AtomLayers(pub Vec<usize>); | |
| #[derive(Debug, Clone)] pub struct LayerScMatrices(pub Vec<ScMatrix>); | |
| @@ -25,49 +739,105 @@ use ::serde_yaml::Value as YamlValue; | |
| pub use self::gamma_system_analysis::GammaSystemAnalysis; | |
| pub mod gamma_system_analysis { | |
| use super::*; | |
| + use self::inductive::hlist::{self, HList}; | |
| + | |
| + pub trait Analyze<F> { | |
| + type Output; | |
| + | |
| + fn analyze(self, f: F) -> Self::Output; | |
| + } | |
| + | |
| + impl<'a, F, Z, M, As: HList, Rs: HList, Out> Analyze<As> for F | |
| + where | |
| + As: hlist::Map<option::AsRefClosure, Output=Rs>, | |
| + Rs: option::ListZip<Output=Z>, | |
| + Z: option::Map<closures::OnHLists<F>, Output=M>, | |
| + M: option::FoldOk<Output=Out>, | |
| + { | |
| + type Output = Out; | |
| + | |
| + fn analyze(self, args: As) -> Self::Output { | |
| + args.map(option::AsRefClosure) | |
| + .list_zip() | |
| + .map(closures::OnHLists(self)) | |
| + .fold_ok() | |
| + } | |
| + } | |
| - pub struct Input<'a> { | |
| - pub atom_coords: &'a Option<AtomCoordinates>, | |
| - pub atom_layers: &'a Option<AtomLayers>, | |
| - pub layer_sc_mats: &'a Option<LayerScMatrices>, | |
| - pub ev_frequencies: &'a Option<EvFrequencies>, | |
| - pub ev_eigenvectors: &'a Option<EvEigenvectors>, | |
| + pub struct Input<'a, A, B, C, D, E> | |
| + where A: 'a, B: 'a, C: 'a, D: 'a, E: 'a, | |
| + { | |
| + pub atom_coords: &'a A, | |
| + pub atom_layers: &'a B, | |
| + pub layer_sc_mats: &'a C, | |
| + pub ev_frequencies: &'a D, | |
| + pub ev_eigenvectors: &'a E, | |
| } | |
| - pub struct GammaSystemAnalysis { | |
| - pub ev_frequencies: Option<EvFrequencies>, | |
| - pub ev_acousticness: Option<EvAcousticness>, | |
| - pub ev_polarization: Option<EvPolarization>, | |
| - pub ev_layer_gamma_probs: Option<EvLayerGammaProbs>, | |
| - pub ev_layer_acousticness: Option<EvLayerAcousticness>, | |
| + pub struct GammaSystemAnalysis<A, B, C, D, E> | |
| + where | |
| + { | |
| + pub ev_frequencies: A, | |
| + pub ev_acousticness: B, | |
| + pub ev_polarization: C, | |
| + pub ev_layer_gamma_probs: D, | |
| + pub ev_layer_acousticness: E, | |
| } | |
| - impl<'a> Input<'a> { | |
| - pub fn compute(&self) -> Result<GammaSystemAnalysis> | |
| + impl< | |
| + 'a, | |
| + InAtomCoordinates, | |
| + InAtomLayers, | |
| + InLayerScMatrices, | |
| + InEvFrequencies, | |
| + InEvEigenvectors, | |
| + > Input< | |
| + 'a, | |
| + InAtomCoordinates, | |
| + InAtomLayers, | |
| + InLayerScMatrices, | |
| + InEvFrequencies, | |
| + InEvEigenvectors, | |
| + > { | |
| + pub fn compute< | |
| + OutEvAcousticness, | |
| + OutEvPolarization, | |
| + OutEvLayerGammaProbs, | |
| + OutEvLayerAcousticness, | |
| + >(&self) -> Result<GammaSystemAnalysis< | |
| + InEvFrequencies, | |
| + OutEvAcousticness, | |
| + OutEvPolarization, | |
| + OutEvLayerGammaProbs, | |
| + OutEvLayerAcousticness, | |
| + >> | |
| + where | |
| + InEvFrequencies: Clone, | |
| + ev_acousticness::Analysis: Analyze<hlist::HList1<&'a InEvEigenvectors>, Output=Result<OutEvAcousticness>>, | |
| + ev_polarization::Analysis: Analyze<hlist::HList1<&'a InEvEigenvectors>, Output=Result<OutEvPolarization>>, | |
| + ev_layer_gamma_probs::Analysis: Analyze<hlist::HList4<&'a InAtomLayers, &'a InAtomCoordinates, &'a InLayerScMatrices, &'a InEvEigenvectors>, Output=Result<OutEvLayerGammaProbs>>, | |
| + ev_layer_acousticness::Analysis: Analyze<hlist::HList2<&'a InAtomLayers, &'a InEvEigenvectors>, Output=Result<OutEvLayerAcousticness>>, | |
| {ok({ | |
| let Input { | |
| atom_coords, atom_layers, layer_sc_mats, | |
| ev_frequencies, ev_eigenvectors, | |
| } = *self; | |
| - // This is a bit repetitive, perhaps, but the upshot is that | |
| - // it is *impossible* to make a mistake here; it would not compile. | |
| - | |
| - let ev_acousticness = ev_acousticness::Input { | |
| + let ev_acousticness = ev_acousticness::Analysis.analyze(hlist![ | |
| ev_eigenvectors, | |
| - }.maybe_compute()?; | |
| + ])?; | |
| - let ev_polarization = ev_polarization::Input { | |
| + let ev_polarization = ev_polarization::Analysis.analyze(hlist![ | |
| ev_eigenvectors, | |
| - }.maybe_compute()?; | |
| + ])?; | |
| - let ev_layer_acousticness = ev_layer_acousticness::Input { | |
| - ev_eigenvectors, atom_layers, | |
| - }.maybe_compute()?; | |
| + let ev_layer_gamma_probs = ev_layer_gamma_probs::Analysis.analyze(hlist![ | |
| + atom_layers, atom_coords, layer_sc_mats, ev_eigenvectors, | |
| + ])?; | |
| - let ev_layer_gamma_probs = ev_layer_gamma_probs::Input { | |
| - ev_eigenvectors, atom_layers, atom_coords, layer_sc_mats, | |
| - }.maybe_compute()?; | |
| + let ev_layer_acousticness = ev_layer_acousticness::Analysis.analyze(hlist![ | |
| + atom_layers, ev_eigenvectors, | |
| + ])?; | |
| let ev_frequencies = ev_frequencies.clone(); | |
| @@ -104,24 +874,13 @@ macro_rules! wrap_maybe_compute { | |
| $( { $($Thing_body_if_brace)* } )* | |
| $($( ( $($Thing_body_if_paren)* ) )* ; )* | |
| - pub struct Input<'a> { | |
| - $(pub $arg : &'a Option<$Arg> ,)* | |
| - } | |
| + pub struct Analysis; | |
| + impl<'a> FnOnce<Hlist![$(&'a $Arg,)*]> for Analysis { | |
| + type Output = Result<$Thing>; | |
| - impl<'a> Input<'a> { | |
| - pub fn maybe_compute(self) -> Result<Option<$Thing>> { | |
| - $( | |
| - let $arg = match self.$arg { | |
| - &Some(ref x) => x, | |
| - &None => return Ok(None), | |
| - }; | |
| - )* | |
| - Ok(Some(compute($($arg),*)?)) | |
| - } | |
| + fn call_once(self, hlist_pat![$($arg),*] : Hlist![$(&'a $Arg),*]) -> Self::Output | |
| + $fn_body | |
| } | |
| - | |
| - fn compute($($arg: &$Arg),*) -> Result<$Thing> | |
| - $fn_body | |
| } | |
| )* | |
| } | |
| @@ -132,22 +891,17 @@ pub use self::ev_acousticness::EvAcousticness; | |
| pub mod ev_acousticness { | |
| use super::*; | |
| + use self::inductive::hlist::HList1; | |
| + | |
| pub struct EvAcousticness(pub Vec<f64>); | |
| - pub struct Input<'a> { | |
| - pub ev_eigenvectors: &'a Option<EvEigenvectors>, | |
| - } | |
| - impl<'a> Input<'a> { | |
| - pub fn maybe_compute(self) -> Result<Option<EvAcousticness>> { | |
| - let ev_eigenvectors = match self.ev_eigenvectors { | |
| - &Some(ref x) => x, | |
| - &None => return Ok(None), | |
| - }; | |
| - Ok(Some(compute(ev_eigenvectors)?)) | |
| + pub struct Analysis; | |
| + impl<'a> FnOnce<HList1<&'a EvEigenvectors>> for Analysis { | |
| + type Output = Result<EvAcousticness>; | |
| + | |
| + fn call_once(self, hlist_pat![ev_eigenvectors]: HList1<&EvEigenvectors>) -> Self::Output { | |
| + Ok(EvAcousticness((ev_eigenvectors.0).0.iter().map(|ket| ket.acousticness()).collect())) | |
| } | |
| } | |
| - fn compute(ev_eigenvectors: &EvEigenvectors) -> Result<EvAcousticness> { | |
| - Ok(EvAcousticness((ev_eigenvectors.0).0.iter().map(|ket| ket.acousticness()).collect())) | |
| - } | |
| } | |
| wrap_maybe_compute! { | |
| @@ -254,8 +1008,28 @@ pub enum ColumnsMode { | |
| ForMachines, | |
| } | |
| -impl GammaSystemAnalysis { | |
| +impl<A, B, C, D, E> GammaSystemAnalysis<A, B, C, D, E> | |
| +where | |
| + A: option::IntoMaybe<TyArg=EvFrequencies>, | |
| + B: option::IntoMaybe<TyArg=EvAcousticness>, | |
| + C: option::IntoMaybe<TyArg=EvPolarization>, | |
| + D: option::IntoMaybe<TyArg=EvLayerGammaProbs>, | |
| + E: option::IntoMaybe<TyArg=EvLayerAcousticness>, | |
| +{ | |
| pub fn make_columns(&self, mode: ColumnsMode) -> Option<Columns> { | |
| + let &GammaSystemAnalysis { | |
| + ref ev_frequencies, | |
| + ref ev_acousticness, | |
| + ref ev_polarization, | |
| + ref ev_layer_gamma_probs, | |
| + ref ev_layer_acousticness, | |
| + } = self; | |
| + let ev_frequencies = ev_frequencies.as_maybe(); | |
| + let ev_acousticness = ev_acousticness.as_maybe(); | |
| + let ev_polarization = ev_polarization.as_maybe(); | |
| + let ev_layer_gamma_probs = ev_layer_gamma_probs.as_maybe(); | |
| + let ev_layer_acousticness = ev_layer_acousticness.as_maybe(); | |
| + | |
| use self::Color::{Colorful, Colorless}; | |
| let mut columns = vec![]; | |
| @@ -264,7 +1038,7 @@ impl GammaSystemAnalysis { | |
| let fix2 = |c, title: &str, data: &_| fixed_prob_column(c, Precision(2), title, data); | |
| let dp = display_prob_column; | |
| - if let Some(ref data) = self.ev_frequencies { | |
| + if let Some(ref data) = ev_frequencies { | |
| let col = Columns { | |
| header: "Frequency(cm-1)".into(), | |
| entries: data.0.to_vec(), | |
| @@ -276,21 +1050,21 @@ impl GammaSystemAnalysis { | |
| )) | |
| }; | |
| - if let Some(ref data) = self.ev_acousticness { | |
| + if let Some(ref data) = ev_acousticness { | |
| columns.push(match mode { | |
| ColumnsMode::ForHumans => dp(Colorful, "Acoust.", &data.0), | |
| ColumnsMode::ForMachines => fix2(Colorless, "Acou", &data.0), | |
| }) | |
| }; | |
| - if let Some(ref data) = self.ev_layer_acousticness { | |
| + if let Some(ref data) = ev_layer_acousticness { | |
| columns.push(match mode { | |
| ColumnsMode::ForHumans => dp(Colorful, "Layer", &data.0), | |
| ColumnsMode::ForMachines => fix2(Colorless, "Lay.", &data.0), | |
| }) | |
| }; | |
| - if let Some(ref data) = self.ev_polarization { | |
| + if let Some(ref data) = ev_polarization { | |
| let data = |k| data.0.iter().map(|v| v[k]).collect_vec(); | |
| let name = |k| "XYZ".chars().nth(k).unwrap().to_string(); | |
| @@ -316,7 +1090,7 @@ impl GammaSystemAnalysis { | |
| }); | |
| } | |
| - if let Some(ref data) = self.ev_layer_gamma_probs { | |
| + if let Some(ref data) = ev_layer_gamma_probs { | |
| for (n, probs) in data.0.iter().enumerate() { | |
| columns.push(match mode { | |
| ColumnsMode::ForHumans => fix1(Colorful, &format!("G{:02}", n+1), &probs), | |
| @@ -337,9 +1111,7 @@ impl GammaSystemAnalysis { | |
| }), | |
| } | |
| } | |
| -} | |
| -impl GammaSystemAnalysis { | |
| pub fn make_summary(&self, settings: &Settings) -> YamlValue { | |
| let GammaSystemAnalysis { | |
| ref ev_acousticness, ref ev_polarization, | |
| @@ -350,14 +1122,14 @@ impl GammaSystemAnalysis { | |
| // This is where the newtypes start to get in the way; | |
| // turn as many things as we can into Option<Vec<T>> (indexed by ket) | |
| // for ease of composition. | |
| - let frequency = ev_frequencies.as_ref().map(|d| d.0.to_vec()); | |
| - let acousticness = ev_acousticness.as_ref().map(|d| d.0.to_vec()); | |
| - let polarization = ev_polarization.as_ref().map(|d| d.0.to_vec()); | |
| - let layer_acousticness = ev_layer_acousticness.as_ref().map(|d| d.0.to_vec()); | |
| + let frequency = ev_frequencies.as_maybe().map(|d| d.0.to_vec()); | |
| + let acousticness = ev_acousticness.as_maybe().map(|d| d.0.to_vec()); | |
| + let polarization = ev_polarization.as_maybe().map(|d| d.0.to_vec()); | |
| + let layer_acousticness = ev_layer_acousticness.as_maybe().map(|d| d.0.to_vec()); | |
| // Work with Option<Vec<A>> as an applicative functor (for fixed length Vec) | |
| fn map1<A, R, F>(a: &Option<Vec<A>>, mut f: F) -> Option<Vec<R>> | |
| - where F: FnMut(&A) -> R | |
| + where F: for<'a> StdFnMut(&'a A) -> R | |
| { | |
| let a = a.as_ref()?; | |
| Some(a.iter().map(|a| f(a)).collect()) | |
| @@ -365,7 +1137,7 @@ impl GammaSystemAnalysis { | |
| // (haskell's LiftA2) | |
| fn map2<B, A, R, F>(a: &Option<Vec<A>>, b: &Option<Vec<B>>, mut f: F) -> Option<Vec<R>> | |
| - where F: FnMut(&A, &B) -> R | |
| + where F: for<'a, 'b> StdFnMut(&'a A, &'b B) -> R | |
| { | |
| Some({ | |
| zip_eq(a.as_ref()?, b.as_ref()?) | |
| @@ -430,7 +1202,7 @@ impl GammaSystemAnalysis { | |
| // For gamma probs, don't bother with all layers; just a couple. | |
| [0, 1].iter().for_each(|&layer_n| { | |
| - let probs = ev_layer_gamma_probs.as_ref().map(|d| d.0[layer_n].to_vec()); | |
| + let probs = ev_layer_gamma_probs.as_maybe().map(|d| d.0[layer_n].to_vec()); | |
| let layer_key = format!("layer-{}", layer_n + 1); | |
| let pred = at_least(settings.layer_gamma_threshold, &probs); | |
| @@ -445,7 +1217,8 @@ impl GammaSystemAnalysis { | |
| let items = tuples.into_iter().map(|(index, &(frequency, probability))| { | |
| Item { index, frequency, probability } | |
| }).collect_vec(); | |
| - let value = ::serde_yaml::to_value(&items).unwrap(); | |
| + | |
| + let value = ::serde_yaml::to_value(items).unwrap(); | |
| out.push(make_nested_mapping(&["layer-gammas", &layer_key], value)); | |
| } | |
| }); | |
| @@ -524,6 +1297,7 @@ use self::columns::{Columns, Color, Precision, fixed_prob_column, display_prob_c | |
| mod columns { | |
| use super::*; | |
| use std::iter::{Chain, Once, once}; | |
| + use self::inductive::hlist::HList1; | |
| #[derive(Debug, Clone)] | |
| pub struct Columns<T = String> { | |
| @@ -562,13 +1336,17 @@ mod columns { | |
| /// Values are string-formatted by some mapping function, and optionally colorized | |
| /// according to the magnitude of their value. | |
| fn quick_column<C, D, F>(painter: &PaintAs<D, C>, header: &str, values: &[C], width: usize, mut show: F) -> Columns | |
| - where | |
| - C: PartialOrd, | |
| - F: FnMut(&C) -> D, | |
| - D: fmt::Display, | |
| + where | |
| + C: PartialOrd, | |
| + F: StdFnMut(&C) -> D, | |
| + D: fmt::Display, | |
| { Columns { | |
| header: format!(" {:^width$}", header, width = width), | |
| - entries: values.iter().map(|x| format!(" {}", painter.paint_as(x, show(x)))).collect(), | |
| + entries: { | |
| + values.iter() | |
| + .map(|x| format!(" {}", painter.paint_as(x, show(x)))) | |
| + .collect() | |
| + }, | |
| }} | |
| pub struct Precision(pub usize); | |
| @@ -583,7 +1361,7 @@ mod columns { | |
| Color::Colorful => Box::new(default_prob_color_range()), | |
| Color::Colorless => Box::new(NullPainter), | |
| }; | |
| - quick_column(&*painter, header, values, precision.0 + 2, |&x| FixedProb(x, precision.0)) | |
| + quick_column(&*painter, header, values, precision.0 + 2, |&x: &_| FixedProb(x, precision.0)) | |
| } | |
| pub fn display_prob_column(color: Color, header: &str, values: &[f64]) -> Columns | |
| @@ -592,19 +1370,6 @@ mod columns { | |
| Color::Colorful => Box::new(default_prob_color_range()), | |
| Color::Colorless => Box::new(NullPainter), | |
| }; | |
| - quick_column(&*painter, header, values, 7, |&x| DisplayProb(x)) | |
| + quick_column(&*painter, header, values, 7, |&x: &_| DisplayProb(x)) | |
| } | |
| } | |
| - | |
| -// let energy_per_atom = { | |
| -// let f = |structure: ElementStructure| ok({ | |
| -// let na = structure.num_atoms() as f64; | |
| -// lmp.build(structure)?.compute_value()? / na | |
| -// }); | |
| -// let f_path = |s: &AsPath| ok(f(poscar::load(self.open(s)?)?)?); | |
| - | |
| -// let initial = f_path(&"initial.vasp")?; | |
| -// let final_ = f_path(&"final.vasp")?; | |
| -// let before_ev_chasing = f_path(&"structure-01.1.vasp")?; | |
| -// EnergyPerAtom { initial, final_, before_ev_chasing } | |
| -// }; | |
| diff --git a/src/tasks/cmd/mod.rs b/src/tasks/cmd/mod.rs | |
| index 05dd721..e7a2255 100644 | |
| --- a/src/tasks/cmd/mod.rs | |
| +++ b/src/tasks/cmd/mod.rs | |
| @@ -139,6 +139,7 @@ impl TrialDir { | |
| trace!("Computing eigensystem info"); | |
| let ev_analysis = { | |
| use self::ev_analyses::*; | |
| + use self::ev_analyses::option::Just; | |
| // (NOTE: all these Options look pointless now, but the layer | |
| // stuff shall soon become optional. | |
| @@ -146,23 +147,27 @@ impl TrialDir { | |
| // The other Options *are* kind of pointless, but they simplifies the | |
| // design of the analysis module) | |
| gamma_system_analysis::Input { | |
| - atom_coords: &Some(AtomCoordinates(structure.map_metadata_to(|_| ()))), | |
| + atom_coords: &Just(AtomCoordinates(structure.map_metadata_to(|_| ()))), | |
| atom_layers: &Some(AtomLayers(atom_layers.clone())), | |
| layer_sc_mats: &Some(LayerScMatrices(layer_sc_mats.clone())), | |
| - ev_frequencies: &Some(EvFrequencies(evals.clone())), | |
| - ev_eigenvectors: &Some(EvEigenvectors(evecs.clone())), | |
| + ev_frequencies: &Just(EvFrequencies(evals.clone())), | |
| + ev_eigenvectors: &Just(EvEigenvectors(evecs.clone())), | |
| }.compute()? | |
| }; | |
| { | |
| - let file = self.create_file(format!("eigenvalues.{:02}", iteration))?; | |
| - write_eigen_info_for_machines(&ev_analysis, file)?; | |
| - write_eigen_info_for_humans(&ev_analysis, &mut |s| ok(info!("{}", s)))?; | |
| + let mut file = self.create_file(format!("eigenvalues.{:02}", iteration))?; | |
| + ev_analysis.make_columns(ev_analyses::ColumnsMode::ForMachines) | |
| + .expect("(bug) no columns, not even frequency?") | |
| + .into_iter().map(|s| ok(writeln!(file, "{}", s)?)).collect::<Result<()>>()?; | |
| + ev_analysis.make_columns(ev_analyses::ColumnsMode::ForHumans) | |
| + .expect("(bug) no columns, not even frequency?") | |
| + .into_iter().map(|s| ok(info!("{}", s))).collect::<Result<()>>()?; | |
| } | |
| let mut structure = structure; | |
| let bad_evs: Vec<_> = { | |
| - let acousticness = ev_analysis.ev_acousticness.as_ref().expect("(bug) always computed!"); | |
| + let acousticness = &ev_analysis.ev_acousticness.0; | |
| izip!(1.., &evals, &evecs.0, &acousticness.0) | |
| .take_while(|&(_, &freq, _, _)| freq < 0.0) | |
| .filter(|&(_, _, _, &acousticness)| acousticness < 0.95) | |
| @@ -224,7 +229,12 @@ impl TrialDir { | |
| poscar::dump(self.create_file("final.vasp")?, "", &structure)?; | |
| - write_eigen_info_for_machines(&ev_analysis, self.create_file("eigenvalues.final")?)?; | |
| + { | |
| + let mut file = self.create_file("eigenvalues.final")?; | |
| + ev_analysis.make_columns(ev_analyses::ColumnsMode::ForMachines) | |
| + .expect("(bug) no columns, not even frequency?") | |
| + .into_iter().map(|s| ok(writeln!(file, "{}", s)?)).collect::<Result<()>>()?; | |
| + } | |
| // let (k_evals, k_evecs) = read_eigensystem(&bands_dir, &Q_K)?; | |
| // let kinfos = get_k_eigensystem_info( | |
| @@ -232,7 +242,10 @@ impl TrialDir { | |
| // ); | |
| // write_summary_file(settings, &lmp, &einfos, &kinfos)?; | |
| - self.write_summary_file(settings, &lmp, &ev_analysis)?; | |
| + { | |
| + let rest = ev_analysis.make_summary(settings); | |
| + self.write_summary_file(&lmp, rest)?; | |
| + } | |
| })} | |
| } | |
| @@ -447,32 +460,12 @@ fn multi_threshold_deconstruct( | |
| } | |
| })} | |
| -fn write_eigen_info_for_humans( | |
| - analysis: &GammaSystemAnalysis, | |
| - writeln: &mut FnMut(String) -> Result<()>, | |
| -) -> Result<()> | |
| -{ | |
| - analysis.make_columns(ev_analyses::ColumnsMode::ForHumans) | |
| - .expect("(bug) no columns, not even frequency?") | |
| - .into_iter().map(writeln).collect() | |
| -} | |
| - | |
| -fn write_eigen_info_for_machines<W: Write>( | |
| - analysis: &GammaSystemAnalysis, | |
| - mut file: W, | |
| -) -> Result<()> | |
| -{ | |
| - analysis.make_columns(ev_analyses::ColumnsMode::ForMachines) | |
| - .expect("(bug) no columns, not even frequency?") | |
| - .into_iter().map(|s| ok(writeln!(file, "{}", s)?)).collect() | |
| -} | |
| impl TrialDir { | |
| fn write_summary_file( | |
| &self, | |
| - settings: &Settings, | |
| lmp: &LammpsBuilder, | |
| - ev_analysis: &GammaSystemAnalysis, | |
| + rest: ::serde_yaml::Value, | |
| ) -> Result<()> {ok({ | |
| use ::ui::cfg_merging::{make_nested_mapping, no_summary, merge_summaries}; | |
| use ::rsp2_structure_io::poscar; | |
| @@ -488,7 +481,7 @@ impl TrialDir { | |
| // be done by saving structures into strongly typed objects | |
| // for the analysis module | |
| let mut out = vec![]; | |
| - out.push(ev_analysis.make_summary(settings)); | |
| + out.push(rest); | |
| out.push({ | |
| let f = |structure: ElementStructure| ok({ | |
| let na = structure.num_atoms() as f64; | |
| diff --git a/src/tasks/lib.rs b/src/tasks/lib.rs | |
| index 1a25cf4..11af448 100644 | |
| --- a/src/tasks/lib.rs | |
| +++ b/src/tasks/lib.rs | |
| @@ -22,6 +22,7 @@ extern crate rsp2_fs_util; | |
| #[macro_use] extern crate rsp2_util_macros; | |
| #[macro_use] extern crate rsp2_clap; | |
| +#[macro_use] extern crate frunk; | |
| #[macro_use] extern crate extension_trait; | |
| extern crate rayon; | |
| extern crate rand; | |
| diff --git a/src/tasks/traits/alternate.rs b/src/tasks/traits/alternate.rs | |
| index 0d83400..1a6e6a9 100644 | |
| --- a/src/tasks/traits/alternate.rs | |
| +++ b/src/tasks/traits/alternate.rs | |
| @@ -2,7 +2,7 @@ | |
| //! implemented manually on a type without unstable compiler features. | |
| // These traits basically just let us use more functions in more places without | |
| -// sacrificing too much DRYness, and without having to wait for existential | |
| +// sacrificing too much DRY-ness, and without having to wait for existential | |
| // types to get stabilized. | |
| pub use ::std::prelude::v1::{ | |
| Fn as StdFn, | |
| @@ -10,13 +10,20 @@ pub use ::std::prelude::v1::{ | |
| FnOnce as StdFnOnce, | |
| }; | |
| +use ::std::ops::{Deref, DerefMut}; | |
| +use ::frunk::hlist::{HList, HNil, HCons}; | |
| + | |
| /// Alternate `Fn` that can be manually implemented on stable. | |
| /// | |
| /// It is automatically implemented for all types that implement | |
| /// the standard library's `Fn`. The advantage is that it may | |
| /// also be implemented for explicitly defined "unboxed closures". | |
| -pub trait Fn<Args>: FnMut<Args> { | |
| +pub trait Fn<Args: HList>: FnMut<Args> { | |
| fn call(&self, args: Args) -> Self::Output; | |
| + | |
| + /// Get a borrowed form of the closure. | |
| + #[inline(always)] | |
| + fn by_ref(&self) -> Ref<Self> { Ref(self) } | |
| } | |
| /// Alternate `FnMut` that can be manually implemented on stable. | |
| @@ -24,29 +31,172 @@ pub trait Fn<Args>: FnMut<Args> { | |
| /// It is automatically implemented for all types that implement | |
| /// the standard library's `FnMut`. The advantage is that it may | |
| /// also be implemented for explicitly defined "unboxed closures". | |
| -pub trait FnMut<Args>: FnOnce<Args> { | |
| +pub trait FnMut<Args: HList>: FnOnce<Args> { | |
| fn call_mut(&mut self, args: Args) -> Self::Output; | |
| + | |
| + /// Get a borrowed form of the closure. | |
| + #[inline(always)] | |
| + fn by_ref_mut(&mut self) -> RefMut<Self> { RefMut(self) } | |
| } | |
| +pub type CallT<F, Args> = <F as FnOnce<Args>>::Output; | |
| + | |
| /// Alternate FnOnce that can be manually implemented on stable. | |
| /// | |
| /// It is automatically implemented for all types that implement | |
| /// the standard library's `FnOnce`. The advantage is that it may | |
| /// also be implemented for explicitly defined "unboxed closures". | |
| -pub trait FnOnce<Args> { | |
| +pub trait FnOnce<Args: HList> { | |
| type Output; | |
| + | |
| fn call_once(self, args: Args) -> Self::Output; | |
| } | |
| -impl<F, R, Args> FnOnce<Args> for F where F: StdFnOnce(Args) -> R { | |
| - type Output = R; | |
| - fn call_once(self, args: Args) -> Self::Output { self(args) } | |
| +// --------------- | |
| + | |
| +macro_rules! derive_fn_from_std { | |
| + ($([$([$a:ident : $A:ident])*])*) => { | |
| + $( | |
| + impl<F, R, $($A,)*> FnOnce<Hlist![$($A),*]> for F where F: StdFnOnce($($A),*) -> R { | |
| + type Output = R; | |
| + | |
| + #[inline(always)] | |
| + fn call_once(self, hlist_pat![$($a),*]: Hlist![$($A),*]) -> Self::Output | |
| + { self($($a),*) } | |
| + } | |
| + | |
| + impl<F, R, $($A,)*> FnMut<Hlist![$($A),*]> for F where F: StdFnMut($($A),*) -> R { | |
| + #[inline(always)] | |
| + fn call_mut(&mut self, hlist_pat![$($a),*]: Hlist![$($A),*]) -> Self::Output | |
| + { self($($a),*) } | |
| + } | |
| + | |
| + impl<F, R, $($A,)*> Fn<Hlist![$($A),*]> for F where F: StdFn($($A),*) -> R { | |
| + #[inline(always)] | |
| + fn call(&self, hlist_pat![$($a),*]: Hlist![$($A),*]) -> Self::Output | |
| + { self($($a),*) } | |
| + } | |
| + )* | |
| + } | |
| +} | |
| + | |
| +derive_fn_from_std!{ | |
| + [] | |
| + [[a0:A0]] | |
| + [[a0:A0][a1:A1]] | |
| + [[a0:A0][a1:A1][a2:A2]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5][a6:A6]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5][a6:A6][a7:A7]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5][a6:A6][a7:A7][a8:A8]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5][a6:A6][a7:A7][a8:A8][a9:A9]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5][a6:A6][a7:A7][a8:A8][a9:A9][a10:A10]] | |
| + [[a0:A0][a1:A1][a2:A2][a3:A3][a4:A4][a5:A5][a6:A6][a7:A7][a8:A8][a9:A9][a10:A10][a11:A11]] | |
| +} | |
| + | |
| +// --------------- | |
| + | |
| +pub trait Curry<A>: Sized { | |
| + // fn curry_ref(&self, a: A) -> Partial<Ref<Self>, A>; | |
| + // { self.by_ref().curry() } | |
| + // fn curry_mut(&mut self, a: A) -> Partial<RefMut<Self>, A> | |
| + // { self.by_ref_mut().curry() } | |
| + fn curry(self, a: A) -> Partial<Self, A>; | |
| +} | |
| + | |
| +// NOTE: Unable to constrain F here. | |
| +// You could write `F: FnOnce<HCons<A, Rest>>`, but where does Rest come from? | |
| +impl<A, F> Curry<A> for F | |
| +{ | |
| + #[inline(always)] | |
| + fn curry(self, a: A) -> Partial<Self, A> | |
| + { Partial { | |
| + function: self, | |
| + arg: a, | |
| + }} | |
| +} | |
| + | |
| +#[derive(Debug, Copy, Clone)] | |
| +pub struct Partial<F, A> { | |
| + function: F, | |
| + arg: A, | |
| +} | |
| + | |
| +impl<F, A, Rest: HList> FnOnce<Rest> for Partial<F, A> | |
| + where F: FnOnce<HCons<A, Rest>> | |
| +{ | |
| + type Output = F::Output; | |
| + | |
| + #[inline(always)] | |
| + fn call_once(self, list: Rest) -> Self::Output | |
| + { self.function.call_once(list.prepend(self.arg)) } | |
| +} | |
| + | |
| +// --------------- | |
| +// Can't have generic impls for &F and &mut F thanks to the blanket impl, | |
| +// so we'll work around it with newtypes. | |
| + | |
| +/// A borrowed form of an `alternate::Fn`. | |
| +#[derive(Debug, Copy, Clone)] | |
| +pub struct Ref<'a, F: ?Sized + 'a>(&'a F); | |
| + | |
| +/// A borrowed form of an `alternate::FnMut`. | |
| +#[derive(Debug)] | |
| +pub struct RefMut<'a, F: ?Sized + 'a>(&'a mut F); | |
| + | |
| +impl<'a, F: ?Sized> Deref for Ref<'a, F> { | |
| + type Target = F; | |
| + | |
| + fn deref(&self) -> &Self::Target { &*self.0 } | |
| +} | |
| + | |
| +impl<'a, F: ?Sized> Deref for RefMut<'a, F> { | |
| + type Target = F; | |
| + | |
| + fn deref(&self) -> &Self::Target { &*self.0 } | |
| } | |
| -impl<F, R, Args> FnMut<Args> for F where F: StdFnMut(Args) -> R { | |
| - fn call_mut(&mut self, args: Args) -> Self::Output { self(args) } | |
| +impl<'a, F: ?Sized> DerefMut for RefMut<'a, F> { | |
| + fn deref_mut(&mut self) -> &mut Self::Target { &mut *self.0 } | |
| +} | |
| + | |
| +impl<'a, F: ?Sized, Args: HList> FnOnce<Args> for Ref<'a, F> | |
| + where F: Fn<Args>, | |
| +{ | |
| + type Output = F::Output; | |
| + | |
| + fn call_once(self, args: Args) -> Self::Output | |
| + { self.0.call(args) } | |
| +} | |
| + | |
| +impl<'a, F: ?Sized, Args: HList> FnMut<Args> for Ref<'a, F> | |
| + where F: Fn<Args>, | |
| +{ | |
| + fn call_mut(&mut self, args: Args) -> Self::Output | |
| + { self.0.call(args) } | |
| +} | |
| + | |
| +impl<'a, F: ?Sized, Args: HList> Fn<Args> for Ref<'a, F> | |
| + where F: Fn<Args>, | |
| +{ | |
| + fn call(&self, args: Args) -> Self::Output | |
| + { self.0.call(args) } | |
| +} | |
| + | |
| +impl<'a, F: ?Sized, Args: HList> FnOnce<Args> for RefMut<'a, F> | |
| + where F: FnMut<Args>, | |
| +{ | |
| + type Output = F::Output; | |
| + | |
| + fn call_once(mut self, args: Args) -> Self::Output | |
| + { self.0.call_mut(args) } | |
| } | |
| -impl<F, R, Args> Fn<Args> for F where F: StdFn(Args) -> R { | |
| - fn call(&self, args: Args) -> Self::Output { self(args) } | |
| +impl<'a, F: ?Sized, Args: HList> FnMut<Args> for RefMut<'a, F> | |
| + where F: FnMut<Args>, | |
| +{ | |
| + fn call_mut(&mut self, args: Args) -> Self::Output | |
| + { self.0.call_mut(args) } | |
| } | |
| diff --git a/src/tasks/traits/macros.rs b/src/tasks/traits/macros.rs | |
| index 21086e6..94f6587 100644 | |
| --- a/src/tasks/traits/macros.rs | |
| +++ b/src/tasks/traits/macros.rs | |
| @@ -31,70 +31,81 @@ macro_rules! derive_filetype_wrapper { | |
| /// | |
| /// This macro will automatically generate the impls for the traits | |
| /// lower on the Fn hierarchy. | |
| +/// | |
| +/// This is unsuitable for HOFs, which generally need different bounds | |
| +/// (and *technically* different implementations) on each of the impls. | |
| #[macro_export] | |
| macro_rules! derive_alternate_fn { | |
| - // FnOnce | |
| - ( | |
| - impl[$($par:tt)*] FnOnce<$Arg:ty> for $Type:ty | |
| - $([where $($bnd:tt)*])* | |
| - { $($fn_once_body:tt)* } | |
| - ) | |
| + // multiple invocations - base case | |
| + () => {}; | |
| + | |
| + // enable Fn(A, B, C) sugar | |
| + (impl[$($par:tt)*] $Fn:ident($($Arg:ty),*) $($rest:tt)*) | |
| => { | |
| - impl<$($par)*> $crate::alternate::FnOnce<$Arg> for $Type $(where $($bnd)*)* | |
| - { $($fn_once_body)* } | |
| + derive_alternate_fn!{ | |
| + impl[$($par)*] $Fn<($($Arg,)*)> $($rest)* | |
| + } | |
| }; | |
| - // FnMut (+ FnOnce) | |
| + // multiple invocations - inductive case | |
| ( | |
| - impl[$($par:tt)*] FnMut<$Arg:ty> for $Type:ty | |
| + impl[$($par:tt)*] $Fn:ident<$Arg:ty> for $Type:ty | |
| $([where $($bnd:tt)*])* | |
| { | |
| - // explicitly captured so it can be moved to the FnOnce body | |
| type Output = $Output:ty; | |
| - $($fn_mut_body:tt)* | |
| + $($fn_def:tt)* | |
| } | |
| + $($rest:tt)* | |
| ) | |
| => { | |
| - impl<$($par)*> $crate::alternate::FnMut<$Arg> for $Type $(where $($bnd)*)* | |
| - { | |
| - $($fn_mut_body)* | |
| + derive_alternate_fn!{ | |
| + @one($Fn) [$($par)*] [$Arg] [$Type] [$Output] [$($($bnd)*)*] [$($fn_def)*] | |
| } | |
| + derive_alternate_fn!{ $($rest)* } | |
| + }; | |
| - impl<$($par)*> $crate::alternate::FnOnce<$Arg> for $Type $(where $($bnd)*)* | |
| - { | |
| + // FnOnce | |
| + (@one(FnOnce) [$($par:tt)*] [$Arg:ty] [$Type:ty] [$Output:ty] [$($bnd:tt)*] [$($fn_def:tt)*]) | |
| + => { | |
| + impl<$($par)*> $crate::traits::alternate::FnOnce<$Arg> for $Type where $($bnd)* { | |
| type Output = $Output; | |
| + | |
| + $($fn_def)* | |
| + } | |
| + }; | |
| + | |
| + // FnMut (+ FnOnce) | |
| + (@one(FnMut) [$($par:tt)*] [$Arg:ty] [$Type:ty] [$Output:ty] [$($bnd:tt)*] [$($fn_def:tt)*]) | |
| + => { | |
| + impl<$($par)*> $crate::traits::alternate::FnMut<$Arg> for $Type where $($bnd)* { | |
| + $($fn_def)* | |
| + } | |
| + | |
| + impl<$($par)*> $crate::traits::alternate::FnOnce<$Arg> for $Type where $($bnd)* { | |
| + type Output = $Output; | |
| + | |
| fn call_once(mut self, args: $Args) -> Self::Output | |
| - { $crate::alternate::FnMut::call(&mut self, args) } | |
| + { $crate::traits::alternate::FnMut::call_mut(&mut self, args) } | |
| } | |
| }; | |
| // Fn (+ FnMut + FnOnce) | |
| - ( | |
| - impl[$($par:tt)*] Fn<$Arg:ty> for $Type:ty | |
| - $([where $($bnd:tt)*])* | |
| - { | |
| - // explicitly captured so it can be moved to the FnOnce body | |
| - type Output = $Output:ty; | |
| - $($fn_body:tt)* | |
| - } | |
| - ) | |
| + (@one(Fn) [$($par:tt)*] [$Arg:ty] [$Type:ty] [$Output:ty] [$($bnd:tt)*] [$($fn_def:tt)*]) | |
| => { | |
| - impl<$($par)*> $crate::alternate::Fn<$Arg> for $Type $(where $($bnd)*)* | |
| - { | |
| - $($fn_body)* | |
| + impl<$($par)*> $crate::traits::alternate::Fn<$Arg> for $Type where $($bnd)* { | |
| + $($fn_def)* | |
| } | |
| - impl<$($par)*> $crate::alternate::FnMut<$Arg> for $Type $(where $($bnd)*)* | |
| - { | |
| + impl<$($par)*> $crate::traits::alternate::FnMut<$Arg> for $Type where $($bnd)* { | |
| fn call_mut(&mut self, args: $Arg) -> Self::Output | |
| - { $crate::alternate::Fn::call(self, args) } | |
| + { $crate::traits::alternate::Fn::call(&*self, args) } | |
| } | |
| - impl<$($par)*> $crate::alternate::FnOnce<$Arg> for $Type $(where $($bnd)*)* | |
| - { | |
| + impl<$($par)*> $crate::traits::alternate::FnOnce<$Arg> for $Type where $($bnd)* { | |
| type Output = $Output; | |
| + | |
| fn call_once(self, args: $Arg) -> Self::Output | |
| - { $crate::alternate::Fn::call(&self, args) } | |
| + { $crate::traits::alternate::Fn::call(&self, args) } | |
| } | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment