rust-scan
                                
                                 rust-scan copied to clipboard
                                
                                    rust-scan copied to clipboard
                            
                            
                            
                        rust-scan
A pattern-based scanf alternative for Rust.
This is still a work-in-progress.
Usage
To use this, add the following to your project's Cargo.toml file:
[dependencies.scan]
git = "https://github.com/DanielKeep/rust-scan.git"
[dependencies.scan_util]
git = "https://github.com/DanielKeep/rust-scan-util.git"
Then, in your project's root module:
#![feature(phase)]
#[phase(plugin)] extern crate scan;
extern crate scan_util;
Note that although you can rename scan, you must not rename scan_util, or the macros won't work.
Example
The following shows how to process a line from standard input in various ways:
#![feature(phase)]
#[phase(plugin)] extern crate scan;
extern crate scan_util;
fn main() {
	loop {
		print!("input> ");
		let res = scanln! {
			// Match a single word.
			"hi" => "Hi!".into_string(),
			// Match a sequence of three tokens: "such", "input" and "!".
			"such input!" => "very syntax".into_string(),
			// Match *five* tokens: "and", "now", ".", "." and ".".
			"and now..." => "...for something completely different".into_string(),
			// Match "has" followed by an integer, captured into "value".
			"has" value:int => format!("ok has {}", value),
			// Alternative to the above.
			"has also" value => {
				let value: int = value;
				format!("ok has also {}", value)
			},
			// Match "v" followed by three numbers.
			"v" x:f64 y:f64 z:f64 => format!("({}, {}, {})", x, y, z),
			// Match "rgb" followed by three numbers.
			"rgb" r:u8 g:u8 b:u8 => format!("#{:02x}{:02x}{:02x}", r, g, b),
			// Match "rgb vec" followed by three or four numbers.
			"rgb vec" [rgb:u8],{3,4} => format!("rgba{}", rgb),
			// Match "vecs" followed by a comma-delimited vector of
			// comma-delimited vectors of floats.
			("vecs"|"vechs"|"vetches") [ "[" [vss:f64],* "]" ],* => format!("vss: {}", vss),
			// Match a vector of either an int or a word.
			"ints and words:" [is:int | ss:&str]* => format!("is: {}, ss: {}", is, ss),
			// Match a list of words separated by "and" or a comma.
			"words:" [words:&str]("and"|", and"|",")+ => format!("words: {}", words),
			// Match a list of numbers separated by words.
			"int words:" [is:int](ss:&str)* => format!("is: {}, ss: {}", is, ss),
			// Match "go" followed by a single word.
			"go" exit:&str => format!("Leaving by the {} exit.", exit),
			// Match "yes" or "no".
			"yes" | "no" => "maybe yup".into_string(),
			// Match an integer or a float.
			"i" i:int | "f" f:f64 => format!("i {} | f {}", i, f),
			// Match "identify", with the remainder of the input captured by "tail".
			"identify", ..tail => identify_banana(tail).into_string(),
			// Exit this loop.
			"exit" | "quit" => break,
			// If no other arm else matches, capture all the input into "tail".
			// You could also use `_` as the pattern, if you don't care about the
			// actual input.  Note that this will also swallow any errors caused
			// by previous arms not matching.
			//..tail => format!("wow {}", tail),
		};
		match res {
			Ok(value) => println!("Ok: {}", value),
			Err(err) => println!("Err: {}", err)
		}
	}
}
fn identify_banana<S: Str>(s: S) -> &'static str {
	(scan! {
		s,
		"banana" => "definitely a banana",
		"crowbar" => "giant metal banana",
		"human finger" => "tiny crunchy banana",
		_ => "probably not a banana"
	}).unwrap()
}