The idea is taken from Equational Reasoning at Scale.
Hopefully this can be a stepping stone of mine to understand warp::Filter
.
In playground this code just outputs "I ACTUALLY DID IT" with a space in front of each letter, but if comment out the hardcoded cs
and the match to stop the loop, it accepts keyboard input and logs into two files as specified.
?play
#![feature(stdio_locked)]
trait Semigroup {
fn op(self, other: Self) -> Self;
}
impl Semigroup for () {
fn op(self, _other: Self) {}
}
impl<A, B> Semigroup for Box<dyn Fn(A) -> B + '_>
where
A: Clone + 'static,
B: Semigroup + 'static,
{
fn op(self, other: Self) -> Self {
Box::new(move |a| self(a.clone()).op(other(a)))
}
}
use std::io::{Read, Write};
type Plugin<'a> = Box<dyn Fn(u8) + 'a>;
fn log_to(file_path: &std::path::Path) -> Plugin<'_> {
Box::new(move |c: u8| {
let mut handle = std::fs::OpenOptions::new()
.append(true)
.create(true)
.open(file_path)
.unwrap();
handle.write_all(&[c]).unwrap();
})
}
fn main() {
let file_path1 = std::path::Path::new("file1.txt");
let file_path2 = std::path::PathBuf::from("file2.txt");
let handle_char = log_to(file_path1).op(log_to(file_path2.as_ref())).op(Box::new(|c| {
std::io::stdout_locked().write_all(&[b' ']).unwrap()
}));
let mut cs = "I ACTUALLY DID IT".bytes();
loop {
// let c = std::io::stdin_locked().bytes().next().unwrap().unwrap();
let c = match cs.next() {
Some(c) => c,
None => break,
};
handle_char(c);
std::io::stdout_locked().write_all(&[c]).unwrap();
}
}
I A C T U A L L Y D I D I T
Update 02/20/2022: Generalize the impl to non-static lifetimes
So that's how to name the lifetime of the capture! I feel enlightened.