Fri, 20 Oct 2023 14:59:04 -0500
Make ChainRules dependent on the Write
src/main.rs | file | annotate | diff | comparison | revisions |
--- a/src/main.rs Thu Oct 19 23:25:34 2023 -0500 +++ b/src/main.rs Fri Oct 20 14:59:04 2023 -0500 @@ -5,12 +5,12 @@ use std::io; use std::fs::File; -use std::io::{BufWriter, BufRead, BufReader}; -use std::io::Write; +use std::io::{BufWriter, BufRead, BufReader, Write, Read}; +use std::fmt::Debug; use clap::Parser; /// Command line parameters -#[derive(Parser, Debug)] +#[derive(Parser, Debug, Clone)] #[clap( about = env!("CARGO_PKG_DESCRIPTION"), author = env!("CARGO_PKG_AUTHORS"), @@ -28,7 +28,7 @@ config : Config } -#[derive(Parser, Debug)] +#[derive(Parser, Debug, Clone)] struct Config { #[arg(long, short = 'c')] /// Strip comments @@ -45,33 +45,34 @@ cli : Config } -type AnyChainRule = Box<dyn ChainRule>; -type AnyNestedRule = Box<dyn NestedRule>; +type AnyChainRule<W> = Box<dyn ChainRule<W>>; +type AnyNestedRule<W> = Box<dyn NestedRule<W>>; -trait ChainRule { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule; - fn flush(self : Box<Self>, ctx : &Context); +trait ChainRule<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W>; + fn flush(self : Box<Self>, ctx : &Context) -> W; } -trait NestedRule : ChainRule { +trait NestedRule<W : Write> : ChainRule<W> { fn produce(&mut self, c : char, ctx : &Context); - fn next(self : Box<Self>) -> AnyChainRule; + fn next(self : Box<Self>) -> AnyChainRule<W>; fn produce_string(&mut self, s : String, ctx : &Context) { s.chars().for_each(|c| self.produce(c, ctx)); } fn start_ignored_comment(&mut self, c : char); } -impl<W : Write + 'static> ChainRule for Out<W> { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Out<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { basic_consume(self, c, ctx, true) } - fn flush(mut self : Box<Self>, _ctx : &Context) { + fn flush(mut self : Box<Self>, _ctx : &Context) -> W { self.output.flush().unwrap(); + self.output } } -impl<W : Write + 'static> NestedRule for Out<W> { +impl<W : Write + 'static> NestedRule<W> for Out<W> { fn produce(&mut self, c : char, ctx : &Context) { if c == '\n' { self.line_end(ctx.cli.strip_whitespace, ctx.input_only_ws) @@ -86,7 +87,7 @@ } } - fn next(self : Box<Self>) -> AnyChainRule { + fn next(self : Box<Self>) -> AnyChainRule<W> { self } @@ -103,8 +104,12 @@ } } -fn basic_consume(mut s : AnyNestedRule, c : char, ctx : &Context, print_end : bool) --> AnyChainRule { +fn basic_consume<W : Write + 'static>( + mut s : AnyNestedRule<W>, + c : char, + ctx : &Context, + print_end : bool +) -> AnyChainRule<W> { match c { '{' => { s.produce(c, ctx); @@ -135,13 +140,13 @@ } } -struct CommandName { - parent : AnyNestedRule, +struct CommandName<W : Write> { + parent : AnyNestedRule<W>, command : String } -impl ChainRule for CommandName { - fn consume(mut self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for CommandName<W> { + fn consume(mut self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { match c { '}' | '{' | '\\' if self.command.len() <= 1 => { self.command.push(c); @@ -158,14 +163,14 @@ } } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.handle(ctx) .flush(ctx) } } -impl CommandName { - fn handle(mut self, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> CommandName<W> { + fn handle(mut self, ctx : &Context) -> AnyChainRule<W> { match self.command.as_str() { "\\added" => { Scan::new(Added(self.parent)) @@ -184,10 +189,10 @@ } } -struct Comment(AnyNestedRule); +struct Comment<W : Write>(AnyNestedRule<W>); -impl ChainRule for Comment { - fn consume(mut self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Comment<W> { + fn consume(mut self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { if c == '\n' { self.0.consume(c, ctx) } else { @@ -195,42 +200,42 @@ self } } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -struct IgnoreComment(AnyChainRule); +struct IgnoreComment<W : Write>(AnyChainRule<W>); -impl ChainRule for IgnoreComment { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write +'static> ChainRule<W> for IgnoreComment<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { if c == '\n' { self.0.consume(c, ctx) } else { self } } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -struct Group(AnyNestedRule); +struct Group<W : Write>(AnyNestedRule<W>); -impl ChainRule for Group { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Group<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { basic_consume(self, c, ctx, true) } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -impl NestedRule for Group { +impl<W : Write + 'static> NestedRule<W> for Group<W> { fn produce(&mut self, c : char, ctx : &Context) { self.0.produce(c, ctx) } - fn next(self : Box<Self>) -> AnyChainRule { + fn next(self : Box<Self>) -> AnyChainRule<W> { self.0 } fn start_ignored_comment(&mut self, c : char) { @@ -238,43 +243,43 @@ } } -struct Added(AnyNestedRule); +struct Added<W : Write>(AnyNestedRule<W>); -impl ChainRule for Added { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Added<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { basic_consume(self, c, ctx, false) } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -impl NestedRule for Added { +impl<W : Write + 'static> NestedRule<W> for Added<W> { fn produce(&mut self, c : char, ctx : &Context) { self.0.produce(c, ctx) } - fn next(self : Box<Self>) -> AnyChainRule { + fn next(self : Box<Self>) -> AnyChainRule<W> { self.0 } fn start_ignored_comment(&mut self, c : char) { self.0.start_ignored_comment(c) } } -struct Deleted(AnyNestedRule); +struct Deleted<W : Write>(AnyNestedRule<W>); -impl ChainRule for Deleted { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Deleted<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { basic_consume(self, c, ctx, false) } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -impl NestedRule for Deleted { +impl<W : Write + 'static> NestedRule<W> for Deleted<W> { fn produce(&mut self, _c : char, _ctx : &Context) { } - fn next(self : Box<Self>) -> AnyChainRule { + fn next(self : Box<Self>) -> AnyChainRule<W> { self.0 } fn start_ignored_comment(&mut self, c : char) { @@ -282,22 +287,22 @@ } } -struct Replaced(AnyNestedRule); +struct Replaced<W : Write>(AnyNestedRule<W>); -impl ChainRule for Replaced { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Replaced<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { basic_consume(self, c, ctx, false) } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -impl NestedRule for Replaced { +impl<W : Write + 'static> NestedRule<W> for Replaced<W> { fn produce(&mut self, c : char, ctx : &Context) { self.0.produce(c, ctx) } - fn next(self : Box<Self>) -> AnyChainRule { + fn next(self : Box<Self>) -> AnyChainRule<W> { Scan::new(Deleted(self.0)) } fn start_ignored_comment(&mut self, c : char) { @@ -305,10 +310,10 @@ } } -struct Scan(AnyNestedRule); +struct Scan<W : Write>(AnyNestedRule<W>); -impl ChainRule for Scan { - fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule { +impl<W : Write + 'static> ChainRule<W> for Scan<W> { + fn consume(self : Box<Self>, c : char, ctx : &Context) -> AnyChainRule<W> { if c.is_whitespace() || c == '\n' { self } else if c == '{' { @@ -320,13 +325,13 @@ line {lineno}", lineno = ctx.lineno) } } - fn flush(self : Box<Self>, ctx : &Context) { + fn flush(self : Box<Self>, ctx : &Context) -> W { self.0.flush(ctx) } } -impl Scan { - fn new<R : NestedRule + 'static>(r : R) -> Box<dyn ChainRule> { +impl<W : Write + 'static> Scan<W> { + fn new<R : NestedRule<W> + 'static>(r : R) -> Box<dyn ChainRule<W>> { Box::new(Scan(Box::new(r))) } } @@ -370,16 +375,34 @@ fn main() { let cli = CommandLineArgs::parse(); - let input = cli.input.map_or_else( - || Box::new(BufReader::new(io::stdin())) as Box<dyn BufRead>, - |f| Box::new(BufReader::new(File::open(f).unwrap())) as Box<dyn BufRead> - ); - let output = cli.output.map_or_else( - || Box::new(BufWriter::new(io::stdout())) as Box<dyn Write>, - |f| Box::new(BufWriter::new(File::create(f).unwrap())) as Box<dyn Write> - ); + + match (cli.input, cli.output) { + (None, None) => { + process_buffered(cli.config, io::stdin(), io::stdout()); + }, + (None, Some(o)) => { + process_buffered(cli.config, io::stdin(), File::create(o).unwrap()); + } + (Some(i), None) => { + process_buffered(cli.config, File::open(i).unwrap(), io::stdout()); + } + (Some(i), Some(o)) => { + process_buffered(cli.config, File::open(i).unwrap(), File::create(o).unwrap()); + } + } +} + +fn process_buffered<I : Read, O : Debug + Write + 'static>( + config : Config, + input : I, + output : O +) -> O { + process(config, BufReader::new(input), BufWriter::new(output)).into_inner().unwrap() +} + +fn process<I : BufRead, O : Write + 'static>(config : Config, input : I, output : O) -> O { - let mut rule : Box<dyn ChainRule> = Box::new(Out { + let mut rule : Box<dyn ChainRule<O>> = Box::new(Out { only_whitespace : true, stored_whitespace : String::new(), output, @@ -388,7 +411,7 @@ ignored_comment_only_line : false }); - let mut ctx = Context{ lineno : 0, cli : cli.config, input_only_ws : true}; + let mut ctx = Context{ lineno : 0, cli : config, input_only_ws : true}; for l in input.lines().map(|l| l.unwrap()) { ctx.lineno += 1; @@ -400,5 +423,5 @@ rule = rule.consume('\n', &ctx); } - rule.flush(&ctx); + rule.flush(&ctx) }