diff --git a/core/src/lib.rs b/core/src/lib.rs index bc16035f..dafed617 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -73,5 +73,7 @@ pub mod path; pub mod traits; mod tuples; +pub mod utils; + #[cfg(test)] mod test_structs; diff --git a/core/src/utils.rs b/core/src/utils.rs new file mode 100644 index 00000000..fadc9304 --- /dev/null +++ b/core/src/utils.rs @@ -0,0 +1,147 @@ +use core::marker::PhantomData; + +use crate::{ + hlist::{HFoldRightable, HList}, + traits::{Func, Poly}, +}; + +pub struct ApplyN(PhantomData); + +type ApplyNAcc = (Option, usize, usize); // R, targetN, currN +impl Func<(ApplyNAcc<>::Output>, S)> for ApplyN +where + F: Func, +{ + type Output = ApplyNAcc<>::Output>; + + fn call(((r, tgt_n, curr_n), s): (ApplyNAcc<>::Output>, S)) -> Self::Output { + if tgt_n == curr_n { + (Some(F::call(s)), tgt_n, curr_n + 1) + } else { + (r, tgt_n, curr_n + 1) + } + } +} + +type ApplyNArgsAcc = (Option, FA, usize, usize); // R, FArgs, targetN, currN +impl Func<(ApplyNArgsAcc<>::Output,FA>, S)> for ApplyN +where + F: Func<(FA,S)>, + FA: Copy +{ + type Output = ApplyNArgsAcc<>::Output, FA>; + + fn call(((r, args, tgt_n, curr_n), s): (ApplyNArgsAcc<>::Output,FA>, S)) -> Self::Output { + if tgt_n == curr_n { + (Some(F::call((args, s))), args, tgt_n, curr_n + 1) + } else { + (r, args, tgt_n, curr_n + 1) + } + } +} + +pub fn applyr_at(hl: T, n: usize, _: F) -> Option +where + T: HFoldRightable>, ApplyNAcc, Output = ApplyNAcc> + HList, +{ + let len = hl.len(); + if n >= len { + return None; + } + let (r, _, _) = hl.foldr(Poly(ApplyN::(PhantomData)), (None, n, 0)); + r +} + +pub fn applyr_args_at(hl: T, n: usize, _: F, args: FA) -> Option +where + T: HFoldRightable>, ApplyNArgsAcc, Output = ApplyNArgsAcc> + HList, +{ + let len = hl.len(); + if n >= len { + return None; + } + let (r,_ , _, _) = hl.foldr(Poly(ApplyN::(PhantomData)), (None, args, n, 0)); + r +} + +pub fn applyl_at(hl: T, n: usize, f: F) -> Option +where + T: HFoldRightable>, ApplyNAcc, Output = ApplyNAcc> + HList, +{ + let len = hl.len(); + if n >= len { + return None; + } + applyr_at(hl, len - n - 1, f) +} + +pub fn applyl_args_at(hl: T, n: usize, f: F, args: FA) -> Option +where + T: HFoldRightable>, ApplyNArgsAcc, Output = ApplyNArgsAcc> + HList, +{ + let len = hl.len(); + if n >= len { + return None; + } + applyr_args_at(hl, len - n - 1, f, args) +} + +#[cfg(test)] +mod tests { + use super::*; + + struct IsDefault; + impl Func for IsDefault + where + T: Default + PartialEq, + { + type Output = bool; + + fn call(i: T) -> Self::Output { + let r = T::default() == i; + r + } + } + + #[test] + fn test_apply() { + let lst = hlist![10u32, "xyz", 0usize]; + + assert_eq!(applyr_at(lst.clone(), 0, IsDefault).unwrap(), true); + assert_eq!(applyr_at(lst.clone(), 1, IsDefault).unwrap(), false); + assert_eq!(applyr_at(lst.clone(), 2, IsDefault).unwrap(), false); + + // Couldn't figure out how to create Func impl for references :( + // assert_eq!(applyr_at(lst.clone().to_ref(), 1, IsDefault).unwrap(), false); + // assert_eq!(applyr_at(lst.clone().to_mut(), 2, IsDefault).unwrap(), false); + + assert_eq!(applyl_at(lst.clone(), 0, IsDefault).unwrap(), false); + assert_eq!(applyl_at(lst.clone(), 1, IsDefault).unwrap(), false); + assert_eq!(applyl_at(lst.clone(), 2, IsDefault).unwrap(), true); + } + + struct FomatPrefix; + impl Func<(&str,T)> for FomatPrefix + where T: std::fmt::Display + { + type Output = String; + + fn call((args,i): (&str, T)) -> Self::Output { + let prefix = args; + format!("{}: {}", prefix, i) + } + } + + #[test] + fn test_apply_args() { + let lst = hlist![10u32, "xyz", 0usize]; + + assert_eq!(&applyr_args_at(lst.clone(), 0, FomatPrefix, "usize").unwrap(), "usize: 0"); + assert_eq!(&applyr_args_at(lst.clone(), 1, FomatPrefix, "str").unwrap(), "str: xyz"); + assert_eq!(&applyr_args_at(lst.clone(), 2, FomatPrefix, "u32").unwrap(), "u32: 10"); + + assert_eq!(&applyl_args_at(lst.clone(), 0, FomatPrefix, "u32").unwrap(), "u32: 10"); + assert_eq!(&applyl_args_at(lst.clone(), 1, FomatPrefix, "str").unwrap(), "str: xyz"); + assert_eq!(&applyl_args_at(lst.clone(), 2, FomatPrefix, "usize").unwrap(), "usize: 0"); + } +}