devone 0.3.0

In addition to /dev/zero, aka, a UNIX virtual device, it can simulate /dev/one.
use clap::Parser;
use std::{fs::*, io::*, os::unix::fs::FileExt};
#[derive(Parser)]
struct Cli {
    #[arg(default_value_t = 1)]
    ///specify 0 or 1 to output
    val: u8,
    #[arg(default_value_t = String::new(), short, long)]
    ///input file
    r#if: String,
    #[arg(default_value_t = String::new(), short, long)]
    ///output file
    of: String,
    #[arg(default_value_t = 1, short, long)]
    ///block size
    bs: u64,
    #[arg(default_value_t = 7, short, long)]
    ///append instead of overwrite. To prevent accidental overwriting, the DEFAULT value is to append.
    append: u8,
    #[arg(default_value_t = 0, short, long)]
    ///always outputing
    nonstop: u8,
}
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    let args = Cli::parse();
    let val: [u8; 1] = if args.val == 0 {
        [0b0000_0000]
    } else if args.val == 1 {
        [0b1111_1111]
    } else {
        [args.val]
    };

    let d = |mut f: File| f.flush();
    let append = if args.append > 0 { true } else { false };
    let of = || {
        OpenOptions::new()
            .create(true)
            .write(true)
            .append(append)
            .open(&args.of)
            .unwrap()
    };
    let w: Box<dyn Fn(&[u8], u64) -> Result<()>> = if args.of == String::new() {
        Box::new(|v, _| stdout().write_all(v))
    } else {
        Box::new(|v, p| {
            let mut f = of();
            let mut h = Ok(());
            if append {
                if let Err(e) = f.write_all(v) {
                    h = Err(e)
                } else {
                    if let Err(e) = d(f) {
                        h = Err(e)
                    }
                }
            } else {
                if let Err(e) = f.write_at(v, p) {
                    h = Err(e)
                } else {
                    if let Err(e) = d(f) {
                        h = Err(e)
                    }
                }
            }
            h
        })
    };

    let w: Box<dyn Fn() -> Result<()>> = if args.r#if == String::new() {
        Box::new(|| w(&val, 0))
    } else {
        Box::new(|| {
            let f = File::open(&args.r#if).unwrap();
            let mut b = vec![0u8; args.bs.try_into().unwrap()];
            let mut h = Ok(());
            for i in 0..=u64::MAX / args.bs {
                if let Ok(0) = f.read_at(&mut b, args.bs * i) {
                    break;
                } else if let Err(e) = f.read_at(&mut b, args.bs * i) {
                    h = Err(e);
                    break;
                } else if let Err(e) = w(&b, args.bs * i) {
                    h = Err(e);
                    break;
                } else {
                }
            }
            /*u64::MAX /args.bs = i + a / args.bs
            Easy to know the remainder a < args.bs
            u64::MAX = i * args.bs + a*/
            h
        })
    };
    if args.nonstop > 0 {
        loop {
            if let Err(e) = w() {
                break Err(Box::new(e));
            }
        }
    } else {
        if let Err(e) = w() {
            Err(Box::new(e))
        } else {
            Ok(())
        }
    }
}