fmtparse 0.3.0

Parse format!-like strings
Documentation
use crate::*;

#[track_caller]
fn assert(input: &str, expected: &[Token]) {
	let tokens = parse(input).unwrap();
	assert_eq!(tokens, expected);
}

#[track_caller]
fn assert_relaxed(input: &str, expected: &[Token]) {
	let tokens = parse_relaxed(input).unwrap();
	assert_eq!(tokens, expected);
}

macro_rules! text {
	($text:literal) => {
		Token::Text(String::from($text))
	};
}

macro_rules! var_name {
	() => {
		VarName::None
	};
	($idx:literal) => {
		VarName::Index($idx)
	};
	($ident:ident) => {
		VarName::Ident(String::from(stringify!($ident)))
	};
}

macro_rules! align {
	(<) => {
		Align::Left
	};
	(^) => {
		Align::Center
	};
	(>) => {
		Align::Right
	};
}

macro_rules! var {
	($($var_name:tt)?) => {
		Token::Variable {
			name: var_name!($($var_name)?),
			padding: None,
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: false
		}
	};

	(: $width:literal) => {
		Token::Variable {
			name: VarName::None,
			padding: Some(Padding::TextPadding {
				ch: ' ',
				align: Align::Left,
				width: Param::Const($width)
			}),
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: false
		}
	};

	(: $width:tt $) => {
		Token::Variable {
			name: VarName::None,
			padding: Some(Padding::TextPadding {
				ch: ' ',
				align: Align::Left,
				width: Param::Dynamic(var_name!($width))
			}),
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: false
		}
	};

	(: $ch:literal $align:tt $width:literal) => {
		Token::Variable {
			name: VarName::None,
			padding: Some(Padding::TextPadding {
				ch: $ch,
				align: align!($align),
				width: Param::Const($width)
			}),
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: false
		}
	};

	($var_name:tt : $width:tt $) => {
		Token::Variable {
			name: var_name!($var_name),
			padding: Some(Padding::TextPadding {
				ch: ' ',
				align: Align::Left,
				width: Param::Dynamic(var_name!($width))
			}),
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: false
		}
	};

	(:+) => {
		Token::Variable {
			name: VarName::None,
			padding: None,
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: true
		}
	};

	(: ?) => {
		Token::Variable {
			name: VarName::None,
			padding: None,
			precision: None,
			style: Style::Debug,
			pretty: false,
			sign: false
		}
	};

	(: #?) => {
		Token::Variable {
			name: VarName::None,
			padding: None,
			precision: None,
			style: Style::Debug,
			pretty: true,
			sign: false
		}
	};

	(: #x) => {
		Token::Variable {
			name: VarName::None,
			padding: None,
			precision: None,
			style: Style::LowerHex,
			pretty: true,
			sign: false
		}
	};

	(: 0 $width:literal) => {
		Token::Variable {
			name: VarName::None,
			padding: Some(Padding::ZeroPadding {
				width: $width
			}),
			precision: None,
			style: Style::Display,
			pretty: false,
			sign: false
		}
	};

	(: # 0 $width:literal x) => {
		Token::Variable {
			name: VarName::None,
			padding: Some(Padding::ZeroPadding {
				width: $width
			}),
			precision: None,
			style: Style::LowerHex,
			pretty: true,
			sign: false
		}
	}
}

#[test]
fn mix_vars_and_escaping() {
	assert("{{{x}}}", &[text!("{"), var!(x), text!("}")]);
}

#[test]
fn test_relaxed_vars() {
	let mut var = var!();
	let Token::Variable { name, .. } = &mut var else {
		unreachable!()
	};
	*name = VarName::Ident("v'".into());

	assert_relaxed("{v'}", &[var]);
}

mod std_fmt;
mod subparsers;