letter-sequence 2.1.0

A method to create sequence displayed as uppercase or lower letters, or digits
Documentation
#![allow(dead_code, warnings)]
use std::path::PathBuf;
use clap::Parser;

// PositionalArgs has logical names, from an awkwardly ordered syntax of `seq`
// seq [OPTION] [FIRST [INCREMENT]] LAST
#[derive(Debug, Default)]
struct PositionalArgs<'A> {
	start: Option<&'A str>,
	increment: Option<&'A str>,
	end: &'A str
}

use std::ffi::OsStr;
use std::fmt::Debug;
macro_rules! parse_u64 {
	($var:ident) => {
		Some(
			$var
			.as_ref()
			.parse::<u64>()
			.expect(  &format!("Could not parse '{:?}'", stringify!($var))  )
		)
	};
}

use std::convert::TryFrom;
impl<'A, T> TryFrom<&'A [T]> for PositionalArgs<'A>
where T: 'A + std::fmt::Display + Debug + AsRef<str>
{
	type Error = &'static str;
	fn try_from(mut vec: &'A [T]) -> Result<Self, Self::Error> {
		// println!("ARGUMENT: {:?}", vec);

		if vec.len() > 3 {
			panic!("Too many positional arguments")
		}

		let o = match (vec.get(0), vec.get(1), vec.get(2)) {
			( Some(end), None, None ) => {
				Self { end: end.as_ref(), .. Default::default() }
			},
			( Some(start), Some(end), None ) => {
				Self {
					end: end.as_ref(),
  				start: Some(start.as_ref()),
					..Default::default()
				}
			},
			( Some(start), Some(increment), Some(end) ) => {
				Self {
					end: end.as_ref(),
					start: Some(start.as_ref()),
					increment: Some(increment.as_ref()),
					..Default::default()
				}
			},
			_ => panic!("More than one positional argument is required")
		};
		Ok(o)
	}
}

impl TryFrom<&mut Args> for letter_sequence::SequenceBuilder {
	type Error = letter_sequence::SequenceError;

	fn try_from(args: &mut Args) -> Result<Self, Self::Error> {
		let positional_args: Vec<String> = std::mem::take(&mut args.args);
		let positional_args: Vec<&str> = positional_args.iter().map(AsRef::as_ref).collect();	
		let positional_args: &[&str] = positional_args.as_slice();
		let positional_args = PositionalArgs::try_from(positional_args).unwrap();

		use letter_sequence::SequenceBuilder;

		let step = positional_args
			.increment
			.map_or( Ok(1), |x| x.parse::<u32>() )?;

		let builder = match (positional_args.start, positional_args.end) {
			(Some(start), end) => SequenceBuilder::try_from( (start,end) ),
			(None, end) => SequenceBuilder::try_from( ("1", end) ),
		}.unwrap().inclusive().step(step);

		Ok(builder)
	}
}


/// Usage: seq [OPTION]... LAST
///   or:  seq [OPTION]... FIRST LAST
///   or:  seq [OPTION]... FIRST INCREMENT LAST
///
/// Print numbers from FIRST to LAST, in steps of INCREMENT.
///
/// If FIRST or INCREMENT is omitted, it defaults to 1.  That is, an
/// omitted INCREMENT defaults to 1 even when LAST is smaller than FIRST.
/// The sequence of numbers ends when the sum of the current number and
/// INCREMENT would become greater than LAST.
/// FIRST, INCREMENT, and LAST are interpreted as floating point values.
/// INCREMENT is usually positive if FIRST is smaller than LAST, and
/// INCREMENT is usually negative if FIRST is greater than LAST.
/// INCREMENT must not be 0; none of FIRST, INCREMENT and LAST may be NaN.
/// FORMAT must be suitable for printing one argument of type 'double';
/// it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point
/// decimal numbers with maximum precision PREC, and to %g otherwise.
#[derive(Parser, Debug)]
#[clap(author, version, about)]
struct Args {
  /// use printf style floating-point FORMAT
  #[clap(short, long)]
  format: Option<String>,

	/// use STRING to separate numbers (default: \n)
  #[clap(short, long)]
  seperator: Option<String>,

	/// equalize width by padding with leading zeroes
  #[clap(short = 'w', long)]
  equal_width: Option<bool>,
	
	#[clap(required=true)]
	args: Vec<String>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {	
	let mut opts = Args::from_args();

	let mut seq = letter_sequence::SequenceBuilder::try_from(&mut opts)?
		.build()?;


	let sep = opts
		.seperator
		.unwrap_or("\n".to_string());

	let mut first = true;
	for e in seq {
		if ( first ) {
			print!("{}", e);
			first = false;
		}
		else {
			print!("{}{}", sep, e);
		}
	}

	print!("\n");

	Ok(())
}