<commit_before>// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
#[macro_use]
extern crate clap;
extern crate ucglib;

use std::cell::RefCell;
use std::error::Error;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
use std::process;
use std::rc::Rc;

use ucglib::build;
use ucglib::build::assets::{Cache, MemoryCache};
use ucglib::build::Val;
use ucglib::convert::traits;
use ucglib::convert::ConverterRegistry;

// TODO(jwall): List the target output types automatically.
fn do_flags<'a, 'b>() -> clap::App<'a, 'b> {
    clap_app!(
        ucg =>
            (version: crate_version!())
            (author: crate_authors!())
            (about: "Universal Configuration Grammar compiler.")
            (@arg nostrict: --("no-strict") "Turn off strict checking.")
            (@subcommand inspect =>
             (about: "Inspect a specific symbol in a ucg file.")
             (@arg sym: --sym +takes_value +required "Specify a specific binding in the ucg file to output.")
             (@arg target: --format +required +takes_value "Inspect output type. (flags, json, env, exec)")
             (@arg INPUT: +required "Input ucg file to inspect symbol from.")
            )
            (@subcommand build =>
             (about: "Build a list of ucg files.")
             (@arg recurse: -r +required "Whether we should recurse in directories or not.")
             (@arg INPUT: ... "Input ucg files or directories to build. If not provided then build the contents of the current directory.")
            )
            (@subcommand test =>
             (about: "Check a list of ucg files for errors and run test assertions.")
             (@arg recurse: -r +required "Whether we should recurse or not.")
             (@arg INPUT: ... "Input ucg files or directories to run test assertions for. If not provided it will scan the current directory for files with _test.ucg")
            )
            (@subcommand converters =>
             (about: "list the available converters")
            )
    )
}

fn run_converter(c: &traits::Converter, v: Rc<Val>, f: Option<&str>) -> traits::Result {
    let mut file: Box<std::io::Write> = match f {
        Some(f) => {
            let mut path_buf = PathBuf::from(f);
            path_buf.set_extension(c.file_ext());
            let new_path = path_buf.to_str().unwrap();
            Box::new(try!(File::create(&new_path)))
        }
        None => Box::new(io::stdout()),
    };
    c.convert(v, file.as_mut())
}

fn build_file(
    file: &str,
    validate: bool,
    strict: bool,
    cache: Rc<RefCell<Cache>>,
) -> Result<build::Builder, Box<Error>> {
    let mut file_path_buf = PathBuf::from(file);
    if file_path_buf.is_relative() {
        file_path_buf = std::env::current_dir().unwrap().join(file_path_buf);
    }
    let mut builder = build::Builder::new(file_path_buf, cache);
    builder.set_strict(strict);
    if validate {
        builder.enable_validate_mode();
    }
    try!(builder.build());
    if validate {
        println!("{}", builder.assert_collector.summary);
    }
    Ok(builder)
}

fn do_validate(file: &str, strict: bool, cache: Rc<RefCell<Cache>>) -> bool {
    println!("Validating {}", file);
    match build_file(file, true, strict, cache) {
        Ok(b) => {
            if b.assert_collector.success {
                println!("File {} Pass\n", file);
            } else {
                println!("File {} Fail\n", file);
                return false;
            }
        }
        Err(msg) => {
            eprintln!("Err: {}", msg);
            return false;
        }
    }
    return true;
}

fn do_compile(
    file: &str,
    strict: bool,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
) -> bool {
    println!("Building {}", file);
    let builder = match build_file(file, false, strict, cache.clone()) {
        Ok(builder) => builder,
        Err(err) => {
            eprintln!("{}", err);
            return false;
        }
    };
    let (typ, val) = match builder.out_lock {
        Some((ref typ, ref val)) => (typ, val.clone()),
        None => {
            eprintln!("Build results in no artifacts.");
            return false;
        }
    };
    match registry.get_converter(typ) {
        Some(converter) => {
            run_converter(converter, val, Some(file)).unwrap();
            eprintln!("Build successful");
            return true;
        }
        None => {
            eprintln!("No such converter {}", typ);
            return false;
        }
    }
}

fn visit_ucg_files(
    path: &Path,
    recurse: bool,
    validate: bool,
    strict: bool,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
) -> Result<bool, Box<Error>> {
    let our_path = String::from(path.to_string_lossy());
    let mut result = true;
    // TODO(jwall): Report the failing files at the bottom.
    let mut summary = String::new();
    if path.is_dir() {
        let mut dir_iter = try!(std::fs::read_dir(path)).peekable();
        loop {
            let entry = match dir_iter.next() {
                Some(e) => e,
                None => {
                    break;
                }
            };
            let next_item = try!(entry);
            let next_path = next_item.path();
            let path_as_string = String::from(next_path.to_string_lossy());
            if next_path.is_dir() && recurse {
                if let Err(e) = visit_ucg_files(
                    &next_path,
                    recurse,
                    validate,
                    strict,
                    cache.clone(),
                    registry,
                ) {
                    eprintln!("{}", e);
                    result = false;
                }
            } else {
                if validate && path_as_string.ends_with("_test.ucg") {
                    if !do_validate(&path_as_string, strict, cache.clone()) {
                        result = false;
                        summary.push_str(format!("{} - FAIL\n", path_as_string).as_str())
                    } else {
                        summary.push_str(format!("{} - PASS\n", path_as_string).as_str())
                    }
                } else if !validate && path_as_string.ends_with(".ucg") {
                    if !do_compile(&path_as_string, strict, cache.clone(), registry) {
                        result = false;
                    }
                }
            }
        }
    } else if validate && our_path.ends_with("_test.ucg") {
        if !do_validate(&our_path, strict, cache) {
            result = false;
            summary.push_str(format!("{} - FAIL\n", our_path).as_str());
        } else {
            summary.push_str(format!("{} - PASS\n", &our_path).as_str());
        }
    } else if !validate {
        if !do_compile(&our_path, strict, cache, registry) {
            result = false;
        }
    }
    if validate && !summary.is_empty() {
        println!("RESULTS:");
        println!("{}", summary);
    }
    Ok(result)
}

fn inspect_command(
    matches: &clap::ArgMatches,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
    strict: bool,
) {
    let file = matches.value_of("INPUT").unwrap();
    let sym = matches.value_of("sym");
    let target = matches.value_of("target").unwrap();
    let mut builder = build::Builder::new(file, cache);
    builder.set_strict(strict);
    match registry.get_converter(target) {
        Some(converter) => {
            // TODO(jwall): We should warn if this is a test file.
            let result = builder.build();
            if !result.is_ok() {
                eprintln!("{:?}", result.err().unwrap());
                process::exit(1);
            }
            let val = match sym {
                Some(sym_name) => builder.get_out_by_name(sym_name),
                None => builder.last,
            };
            match val {
                Some(value) => {
                    // We use None here because we always output to stdout for an inspect.
                    run_converter(converter, value, None).unwrap();
                    eprintln!("Build successful");
                    process::exit(0);
                }
                None => {
                    eprintln!("Build results in no value.");
                    process::exit(1);
                }
            }
        }
        None => {
            eprintln!("No such converter {}", target);
            process::exit(1);
        }
    }
}

fn build_command(
    matches: &clap::ArgMatches,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
    strict: bool,
) {
    let files = matches.values_of("INPUT");
    let recurse = matches.is_present("recurse");
    let mut ok = true;
    if files.is_none() {
        let curr_dir = std::env::current_dir().unwrap();
        let ok = visit_ucg_files(
            curr_dir.as_path(),
            recurse,
            false,
            strict,
            cache.clone(),
            &registry,
        );
        if let Ok(false) = ok {
            process::exit(1)
        }
        process::exit(0);
    }
    for file in files.unwrap() {
        let pb = PathBuf::from(file);
        if let Ok(false) = visit_ucg_files(&pb, recurse, false, strict, cache.clone(), &registry) {
            ok = false;
        }
    }
    if !ok {
        process::exit(1)
    }
}

fn test_command(
    matches: &clap::ArgMatches,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
    strict: bool,
) {
    let files = matches.values_of("INPUT");
    let recurse = matches.is_present("recurse");
    if files.is_none() {
        let curr_dir = std::env::current_dir().unwrap();
        let ok = visit_ucg_files(
            curr_dir.as_path(),
            recurse,
            true,
            strict,
            cache.clone(),
            &registry,
        );
        if let Ok(false) = ok {
            process::exit(1)
        }
    } else {
        let mut ok = true;
        for file in files.unwrap() {
            let pb = PathBuf::from(file);
            //if pb.is_dir() {
            if let Ok(false) = visit_ucg_files(
                pb.as_path(),
                recurse,
                true,
                strict,
                cache.clone(),
                &registry,
            ) {
                ok = false;
            }
        }
        if !ok {
            process::exit(1)
        }
    }
    process::exit(0);
}

fn converters_command(registry: &ConverterRegistry) {
    println!("Available converters:");
    println!("");
    for (name, c) in registry.get_converter_list().iter() {
        println!("- {}", name);
        println!("  Description: {}", c.description());
        println!("  Output Extension: `.{}`", c.file_ext());
        println!("");
    }
}

fn main() {
    let mut app = do_flags();
    let app_matches = app.clone().get_matches();
    let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new()));
    let registry = ConverterRegistry::make_registry();
    let strict = if app_matches.is_present("nostrict") {
        false
    } else {
        true
    };
    if let Some(matches) = app_matches.subcommand_matches("inspect") {
        inspect_command(matches, cache, &registry, strict);
    } else if let Some(matches) = app_matches.subcommand_matches("build") {
        build_command(matches, cache, &registry, strict);
    } else if let Some(matches) = app_matches.subcommand_matches("test") {
        test_command(matches, cache, &registry, strict);
    } else if let Some(_) = app_matches.subcommand_matches("converters") {
        converters_command(&registry)
    } else {
        app.print_help().unwrap();
        println!("");
    }
}
<commit_msg>Fix -r arg argument.<commit_after>// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
#[macro_use]
extern crate clap;
extern crate ucglib;

use std::cell::RefCell;
use std::error::Error;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
use std::process;
use std::rc::Rc;

use ucglib::build;
use ucglib::build::assets::{Cache, MemoryCache};
use ucglib::build::Val;
use ucglib::convert::traits;
use ucglib::convert::ConverterRegistry;

// TODO(jwall): List the target output types automatically.
fn do_flags<'a, 'b>() -> clap::App<'a, 'b> {
    clap_app!(
        ucg =>
            (version: crate_version!())
            (author: crate_authors!())
            (about: "Universal Configuration Grammar compiler.")
            (@arg nostrict: --("no-strict") "Turn off strict checking.")
            (@subcommand inspect =>
             (about: "Inspect a specific symbol in a ucg file.")
             (@arg sym: --sym +takes_value +required "Specify a specific binding in the ucg file to output.")
             (@arg target: --format +required +takes_value "Inspect output type. (flags, json, env, exec)")
             (@arg INPUT: +required "Input ucg file to inspect symbol from.")
            )
            (@subcommand build =>
             (about: "Build a list of ucg files.")
             (@arg recurse: -r "Whether we should recurse in directories or not.")
             (@arg INPUT: ... "Input ucg files or directories to build. If not provided then build the contents of the current directory.")
            )
            (@subcommand test =>
             (about: "Check a list of ucg files for errors and run test assertions.")
             (@arg recurse: -r "Whether we should recurse or not.")
             (@arg INPUT: ... "Input ucg files or directories to run test assertions for. If not provided it will scan the current directory for files with _test.ucg")
            )
            (@subcommand converters =>
             (about: "list the available converters")
            )
    )
}

fn run_converter(c: &traits::Converter, v: Rc<Val>, f: Option<&str>) -> traits::Result {
    let mut file: Box<std::io::Write> = match f {
        Some(f) => {
            let mut path_buf = PathBuf::from(f);
            path_buf.set_extension(c.file_ext());
            let new_path = path_buf.to_str().unwrap();
            Box::new(try!(File::create(&new_path)))
        }
        None => Box::new(io::stdout()),
    };
    c.convert(v, file.as_mut())
}

fn build_file(
    file: &str,
    validate: bool,
    strict: bool,
    cache: Rc<RefCell<Cache>>,
) -> Result<build::Builder, Box<Error>> {
    let mut file_path_buf = PathBuf::from(file);
    if file_path_buf.is_relative() {
        file_path_buf = std::env::current_dir().unwrap().join(file_path_buf);
    }
    let mut builder = build::Builder::new(file_path_buf, cache);
    builder.set_strict(strict);
    if validate {
        builder.enable_validate_mode();
    }
    try!(builder.build());
    if validate {
        println!("{}", builder.assert_collector.summary);
    }
    Ok(builder)
}

fn do_validate(file: &str, strict: bool, cache: Rc<RefCell<Cache>>) -> bool {
    println!("Validating {}", file);
    match build_file(file, true, strict, cache) {
        Ok(b) => {
            if b.assert_collector.success {
                println!("File {} Pass\n", file);
            } else {
                println!("File {} Fail\n", file);
                return false;
            }
        }
        Err(msg) => {
            eprintln!("Err: {}", msg);
            return false;
        }
    }
    return true;
}

fn do_compile(
    file: &str,
    strict: bool,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
) -> bool {
    println!("Building {}", file);
    let builder = match build_file(file, false, strict, cache.clone()) {
        Ok(builder) => builder,
        Err(err) => {
            eprintln!("{}", err);
            return false;
        }
    };
    let (typ, val) = match builder.out_lock {
        Some((ref typ, ref val)) => (typ, val.clone()),
        None => {
            eprintln!("Build results in no artifacts.");
            return false;
        }
    };
    match registry.get_converter(typ) {
        Some(converter) => {
            run_converter(converter, val, Some(file)).unwrap();
            eprintln!("Build successful");
            return true;
        }
        None => {
            eprintln!("No such converter {}", typ);
            return false;
        }
    }
}

fn visit_ucg_files(
    path: &Path,
    recurse: bool,
    validate: bool,
    strict: bool,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
) -> Result<bool, Box<Error>> {
    let our_path = String::from(path.to_string_lossy());
    let mut result = true;
    // TODO(jwall): Report the failing files at the bottom.
    let mut summary = String::new();
    if path.is_dir() {
        let mut dir_iter = try!(std::fs::read_dir(path)).peekable();
        loop {
            let entry = match dir_iter.next() {
                Some(e) => e,
                None => {
                    break;
                }
            };
            let next_item = try!(entry);
            let next_path = next_item.path();
            let path_as_string = String::from(next_path.to_string_lossy());
            if next_path.is_dir() && recurse {
                if let Err(e) = visit_ucg_files(
                    &next_path,
                    recurse,
                    validate,
                    strict,
                    cache.clone(),
                    registry,
                ) {
                    eprintln!("{}", e);
                    result = false;
                }
            } else {
                if validate && path_as_string.ends_with("_test.ucg") {
                    if !do_validate(&path_as_string, strict, cache.clone()) {
                        result = false;
                        summary.push_str(format!("{} - FAIL\n", path_as_string).as_str())
                    } else {
                        summary.push_str(format!("{} - PASS\n", path_as_string).as_str())
                    }
                } else if !validate && path_as_string.ends_with(".ucg") {
                    if !do_compile(&path_as_string, strict, cache.clone(), registry) {
                        result = false;
                    }
                }
            }
        }
    } else if validate && our_path.ends_with("_test.ucg") {
        if !do_validate(&our_path, strict, cache) {
            result = false;
            summary.push_str(format!("{} - FAIL\n", our_path).as_str());
        } else {
            summary.push_str(format!("{} - PASS\n", &our_path).as_str());
        }
    } else if !validate {
        if !do_compile(&our_path, strict, cache, registry) {
            result = false;
        }
    }
    if validate && !summary.is_empty() {
        println!("RESULTS:");
        println!("{}", summary);
    }
    Ok(result)
}

fn inspect_command(
    matches: &clap::ArgMatches,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
    strict: bool,
) {
    let file = matches.value_of("INPUT").unwrap();
    let sym = matches.value_of("sym");
    let target = matches.value_of("target").unwrap();
    let mut builder = build::Builder::new(file, cache);
    builder.set_strict(strict);
    match registry.get_converter(target) {
        Some(converter) => {
            // TODO(jwall): We should warn if this is a test file.
            let result = builder.build();
            if !result.is_ok() {
                eprintln!("{:?}", result.err().unwrap());
                process::exit(1);
            }
            let val = match sym {
                Some(sym_name) => builder.get_out_by_name(sym_name),
                None => builder.last,
            };
            match val {
                Some(value) => {
                    // We use None here because we always output to stdout for an inspect.
                    run_converter(converter, value, None).unwrap();
                    eprintln!("Build successful");
                    process::exit(0);
                }
                None => {
                    eprintln!("Build results in no value.");
                    process::exit(1);
                }
            }
        }
        None => {
            eprintln!("No such converter {}", target);
            process::exit(1);
        }
    }
}

fn build_command(
    matches: &clap::ArgMatches,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
    strict: bool,
) {
    let files = matches.values_of("INPUT");
    let recurse = matches.is_present("recurse");
    let mut ok = true;
    if files.is_none() {
        let curr_dir = std::env::current_dir().unwrap();
        let ok = visit_ucg_files(
            curr_dir.as_path(),
            recurse,
            false,
            strict,
            cache.clone(),
            &registry,
        );
        if let Ok(false) = ok {
            process::exit(1)
        }
        process::exit(0);
    }
    for file in files.unwrap() {
        let pb = PathBuf::from(file);
        if let Ok(false) = visit_ucg_files(&pb, recurse, false, strict, cache.clone(), &registry) {
            ok = false;
        }
    }
    if !ok {
        process::exit(1)
    }
}

fn test_command(
    matches: &clap::ArgMatches,
    cache: Rc<RefCell<Cache>>,
    registry: &ConverterRegistry,
    strict: bool,
) {
    let files = matches.values_of("INPUT");
    let recurse = matches.is_present("recurse");
    if files.is_none() {
        let curr_dir = std::env::current_dir().unwrap();
        let ok = visit_ucg_files(
            curr_dir.as_path(),
            recurse,
            true,
            strict,
            cache.clone(),
            &registry,
        );
        if let Ok(false) = ok {
            process::exit(1)
        }
    } else {
        let mut ok = true;
        for file in files.unwrap() {
            let pb = PathBuf::from(file);
            //if pb.is_dir() {
            if let Ok(false) = visit_ucg_files(
                pb.as_path(),
                recurse,
                true,
                strict,
                cache.clone(),
                &registry,
            ) {
                ok = false;
            }
        }
        if !ok {
            process::exit(1)
        }
    }
    process::exit(0);
}

fn converters_command(registry: &ConverterRegistry) {
    println!("Available converters:");
    println!("");
    for (name, c) in registry.get_converter_list().iter() {
        println!("- {}", name);
        println!("  Description: {}", c.description());
        println!("  Output Extension: `.{}`", c.file_ext());
        println!("");
    }
}

fn main() {
    let mut app = do_flags();
    let app_matches = app.clone().get_matches();
    let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new()));
    let registry = ConverterRegistry::make_registry();
    let strict = if app_matches.is_present("nostrict") {
        false
    } else {
        true
    };
    if let Some(matches) = app_matches.subcommand_matches("inspect") {
        inspect_command(matches, cache, &registry, strict);
    } else if let Some(matches) = app_matches.subcommand_matches("build") {
        build_command(matches, cache, &registry, strict);
    } else if let Some(matches) = app_matches.subcommand_matches("test") {
        test_command(matches, cache, &registry, strict);
    } else if let Some(_) = app_matches.subcommand_matches("converters") {
        converters_command(&registry)
    } else {
        app.print_help().unwrap();
        println!("");
    }
}
<|endoftext|>


<commit_before>use std::io::{self, stdin, stdout, Write};
use std::iter::Peekable;
use std::str::CharIndices;

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    let current_dir = try!(std::env::current_dir());
    print!("{}> ", current_dir.display());
    try!(stdout().flush());
    stdin().read_line(line)
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Ast {
    Empty,
    Call { command: String, args: Vec<String> }
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Token {
    Newline,
    Whitespace,
    Text(String),
}

#[derive(Clone)]
struct Lexer<'a> {
    input: &'a str,
    iter: Peekable<CharIndices<'a>>,
}

impl<'a> Lexer<'a> {
    fn new(input: &str) -> Lexer {
        Lexer {
            input: input,
            iter: input.char_indices().peekable(),
        }
    }

    fn pos(&mut self) -> usize {
        self.iter.peek().map(|p| p.0).unwrap_or(self.input.len())
    }

    fn peek_char(&mut self) -> Option<char> {
        self.iter.peek().map(|p| p.1)
    }

    fn is_whitespace(c: char) -> bool {
        c == ' ' || c == '\t'
    }

    fn lex_whitespace(&mut self) -> Token {
        while let Some(c) = self.peek_char() {
            if !Lexer::is_whitespace(c) { break; }
            self.iter.next();
        }

        Token::Whitespace
    }

    fn lex_unquoted_text(&mut self) -> Token {
        let start = self.pos();

        while let Some(c) = self.peek_char() {
            if Lexer::is_whitespace(c) || c == '\r' || c == '\n' { break; }
            self.iter.next();
        }

        let end = self.pos();

        // TODO(tsion): Do this without allocation.
        Token::Text(String::from(&self.input[start..end]))
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.peek_char().map(|peek_char| {
            match peek_char {
                '\r' | '\n'                  => Token::Newline,
                c if Lexer::is_whitespace(c) => self.lex_whitespace(),
                _                            => self.lex_unquoted_text(),
            }
        })
    }
}

#[derive(Clone)]
struct Parser<'a> {
    lexer: Lexer<'a>,
}

impl<'a> Parser<'a> {
    fn new(input: &str) -> Parser {
        Parser { lexer: Lexer::new(input) }
    }

    fn parse(&mut self) -> Ast {
        match self.lexer.next() {
            Some(Token::Whitespace) | Some(Token::Newline) => self.parse(),
            Some(Token::Text(command)) => self.parse_call(command),
            None => Ast::Empty,
        }
    }

    fn parse_call(&mut self, command: String) -> Ast {
        let mut args = vec![];

        for token in &mut self.lexer {
            match token {
                Token::Newline    => break,
                Token::Whitespace => {},
                Token::Text(arg)  => { args.push(arg); },
            }
        }

        Ast::Call { command: command, args: args }
    }
}

fn execute(ast: &Ast) -> io::Result<()> {
    match *ast {
        Ast::Empty => Ok(()),
        Ast::Call { ref command, ref args } => {
            match &**command {
                "cd" => {
                    if args.len() > 1 {
                        return Err(io::Error::new(io::ErrorKind::Other, "cd: too many arguments"));
                    }

                    if let Some(path) = args.get(0) {
                        std::env::set_current_dir(path)
                    } else if let Some(home) = std::env::home_dir() {
                        std::env::set_current_dir(home)
                    } else {
                        Err(io::Error::new(io::ErrorKind::Other, "cd: couldn't find home dir"))
                    }
                },

                "exit" => {
                    if args.len() > 1 {
                        return Err(io::Error::new(io::ErrorKind::Other,
                                                  "exit: too many arguments"));
                    }

                    if let Some(exit_code_str) = args.get(0) {
                        if let Ok(exit_code) = exit_code_str.parse() {
                            std::process::exit(exit_code);
                        } else {
                            Err(io::Error::new(io::ErrorKind::Other,
                                               "exit: couldn't parse exit code as integer"))
                        }
                    } else {
                        std::process::exit(0);
                    }
                }

                _ => {
                    std::process::Command::new(command).args(args).status().map(|_| ())
                },
            }
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();
        let ast = Parser::new(&line).parse();
        if let Err(e) = execute(&ast) {
            println!("shroom: error: {}", e);
        }
        line.clear();
    }
}
<commit_msg>Use more idiomatic &String -> &str conversion.<commit_after>use std::io::{self, stdin, stdout, Write};
use std::iter::Peekable;
use std::str::CharIndices;

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    let current_dir = try!(std::env::current_dir());
    print!("{}> ", current_dir.display());
    try!(stdout().flush());
    stdin().read_line(line)
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Ast {
    Empty,
    Call { command: String, args: Vec<String> }
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Token {
    Newline,
    Whitespace,
    Text(String),
}

#[derive(Clone)]
struct Lexer<'a> {
    input: &'a str,
    iter: Peekable<CharIndices<'a>>,
}

impl<'a> Lexer<'a> {
    fn new(input: &str) -> Lexer {
        Lexer {
            input: input,
            iter: input.char_indices().peekable(),
        }
    }

    fn pos(&mut self) -> usize {
        self.iter.peek().map(|p| p.0).unwrap_or(self.input.len())
    }

    fn peek_char(&mut self) -> Option<char> {
        self.iter.peek().map(|p| p.1)
    }

    fn is_whitespace(c: char) -> bool {
        c == ' ' || c == '\t'
    }

    fn lex_whitespace(&mut self) -> Token {
        while let Some(c) = self.peek_char() {
            if !Lexer::is_whitespace(c) { break; }
            self.iter.next();
        }

        Token::Whitespace
    }

    fn lex_unquoted_text(&mut self) -> Token {
        let start = self.pos();

        while let Some(c) = self.peek_char() {
            if Lexer::is_whitespace(c) || c == '\r' || c == '\n' { break; }
            self.iter.next();
        }

        let end = self.pos();

        // TODO(tsion): Do this without allocation.
        Token::Text(String::from(&self.input[start..end]))
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        self.peek_char().map(|peek_char| {
            match peek_char {
                '\r' | '\n'                  => Token::Newline,
                c if Lexer::is_whitespace(c) => self.lex_whitespace(),
                _                            => self.lex_unquoted_text(),
            }
        })
    }
}

#[derive(Clone)]
struct Parser<'a> {
    lexer: Lexer<'a>,
}

impl<'a> Parser<'a> {
    fn new(input: &str) -> Parser {
        Parser { lexer: Lexer::new(input) }
    }

    fn parse(&mut self) -> Ast {
        match self.lexer.next() {
            Some(Token::Whitespace) | Some(Token::Newline) => self.parse(),
            Some(Token::Text(command)) => self.parse_call(command),
            None => Ast::Empty,
        }
    }

    fn parse_call(&mut self, command: String) -> Ast {
        let mut args = vec![];

        for token in &mut self.lexer {
            match token {
                Token::Newline    => break,
                Token::Whitespace => {},
                Token::Text(arg)  => { args.push(arg); },
            }
        }

        Ast::Call { command: command, args: args }
    }
}

fn execute(ast: &Ast) -> io::Result<()> {
    match *ast {
        Ast::Empty => Ok(()),
        Ast::Call { ref command, ref args } => {
            match &command[..] {
                "cd" => {
                    if args.len() > 1 {
                        return Err(io::Error::new(io::ErrorKind::Other, "cd: too many arguments"));
                    }

                    if let Some(path) = args.get(0) {
                        std::env::set_current_dir(path)
                    } else if let Some(home) = std::env::home_dir() {
                        std::env::set_current_dir(home)
                    } else {
                        Err(io::Error::new(io::ErrorKind::Other, "cd: couldn't find home dir"))
                    }
                },

                "exit" => {
                    if args.len() > 1 {
                        return Err(io::Error::new(io::ErrorKind::Other,
                                                  "exit: too many arguments"));
                    }

                    if let Some(exit_code_str) = args.get(0) {
                        if let Ok(exit_code) = exit_code_str.parse() {
                            std::process::exit(exit_code);
                        } else {
                            Err(io::Error::new(io::ErrorKind::Other,
                                               "exit: couldn't parse exit code as integer"))
                        }
                    } else {
                        std::process::exit(0);
                    }
                }

                _ => {
                    std::process::Command::new(command).args(args).status().map(|_| ())
                },
            }
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();
        let ast = Parser::new(&line).parse();
        if let Err(e) = execute(&ast) {
            println!("shroom: error: {}", e);
        }
        line.clear();
    }
}
<|endoftext|>


<commit_before>// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

extern crate argparse;
extern crate base64;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{thread_rng, Rng};

use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::errors as e;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  let sr = SerialRequest::List {};
  info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = format!(include_str!("websockets.html"), ws_port = ws_port);

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<(String, SerialRequest)>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  thread::spawn(move || {
                  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).
                  expect(&format!("Failed to create http server on port {}",port));
                  http_server
                    .handle(http_handler)
                    .expect(&"Failed to listen");
                });

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).
  expect(&format!("Failed bind on websocket port {}",ws_port));

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_tx_clone, sreq_tx_clone, connection);
  }
}

fn spawn_ws_handler(sub_tx_clone: Sender<SubscriptionRequest>,
                    sreq_tx_clone: Sender<(String, SerialRequest)>,
                    connection: WsUpgrade<TcpStream>) {
  thread::spawn(move || ws_handler(&sub_tx_clone, &sreq_tx_clone, connection));
}

fn ws_handler(sub_tx: &Sender<SubscriptionRequest>,
              sreq_tx: &Sender<(String, SerialRequest)>,
              connection: WsUpgrade<TcpStream>) {

  // Set up subscription id
  // let ts = SystemTime::now() - UNIX_EPOCH
  let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
  let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
  debug!("Spawned thread with subId '{}'", sub_id);

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(SubscriptionRequest {
            sub_id: sub_id.clone(),
            subscriber: sub_resp_tx,
          })
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  //   let message = Message::text("Hello".to_string());
  //   client.send_message(&message).unwrap();

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  // TODO Check thread cleanup
  // The new WS Client thread msg loop
  let mut exit = false;

  let sleep_dur = Duration::from_millis(33);

  while !exit {
    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(|e| {
                                warn!("Client exit cleanup failed for sub_id '{}', cause '{}'",
                                      sub_id,
                                      e)
                              });
            info!("{}: Client {} disconnected", sub_id, ip);
            exit = true;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send((sub_id.clone(), req)) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            // Weird, but message sending dose work
            // Do I misunderstand unwrap_or?
            sender
              .send_message(&reply)
              .unwrap_or_else(|e| {
                                info!("{}: Could not send message '{}' to client '{}', cause '{}'",
                                      sub_id,
                                      json,
                                      ip,
                                      e)
                              });
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };
    thread::sleep(sleep_dur);
  }

  info!("Thread {} exiting!", sub_id);

  fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
    let error = e::to_serial_response_error(error);
    serde_json::to_string(&error)
      .map_err(|err| e::ErrorKind::Json(err))
      .map(|json| Message::text(json))
      .map(|msg| {
             sender
               .send_message::<Message, _>(&msg)
               .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
           })
      .unwrap_or_else(|_| {
                        warn!("{}: Problem sending bad json error response", sub_id);
                        Ok(())
                      })
      .is_ok(); // This shouldn't be needed?

  }

}
<commit_msg>Moved function<commit_after>// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

extern crate argparse;
extern crate base64;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{thread_rng, Rng};

use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::errors as e;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  let sr = SerialRequest::List {};
  info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = format!(include_str!("websockets.html"), ws_port = ws_port);

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<(String, SerialRequest)>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  thread::spawn(move || {
                  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).
                  expect(&format!("Failed to create http server on port {}",port));
                  http_server
                    .handle(http_handler)
                    .expect(&"Failed to listen");
                });

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).
  expect(&format!("Failed bind on websocket port {}",ws_port));

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_tx_clone, sreq_tx_clone, connection);
  }
}

fn spawn_ws_handler(sub_tx_clone: Sender<SubscriptionRequest>,
                    sreq_tx_clone: Sender<(String, SerialRequest)>,
                    connection: WsUpgrade<TcpStream>) {
  thread::spawn(move || ws_handler(&sub_tx_clone, &sreq_tx_clone, connection));
}

fn ws_handler(sub_tx: &Sender<SubscriptionRequest>,
              sreq_tx: &Sender<(String, SerialRequest)>,
              connection: WsUpgrade<TcpStream>) {

  // Set up subscription id
  // let ts = SystemTime::now() - UNIX_EPOCH
  let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
  let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
  debug!("Spawned thread with subId '{}'", sub_id);

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(SubscriptionRequest {
            sub_id: sub_id.clone(),
            subscriber: sub_resp_tx,
          })
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  //   let message = Message::text("Hello".to_string());
  //   client.send_message(&message).unwrap();

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  // TODO Check thread cleanup
  // The new WS Client thread msg loop
  let mut exit = false;

  let sleep_dur = Duration::from_millis(33);

  while !exit {
    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(|e| {
                                warn!("Client exit cleanup failed for sub_id '{}', cause '{}'",
                                      sub_id,
                                      e)
                              });
            info!("{}: Client {} disconnected", sub_id, ip);
            exit = true;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send((sub_id.clone(), req)) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            // Weird, but message sending dose work
            // Do I misunderstand unwrap_or?
            sender
              .send_message(&reply)
              .unwrap_or_else(|e| {
                                info!("{}: Could not send message '{}' to client '{}', cause '{}'",
                                      sub_id,
                                      json,
                                      ip,
                                      e)
                              });
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };
    thread::sleep(sleep_dur);
  }

  info!("Thread {} exiting!", sub_id);

}

  fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
    let error = e::to_serial_response_error(error);
    serde_json::to_string(&error)
      .map_err(|err| e::ErrorKind::Json(err))
      .map(|json| Message::text(json))
      .map(|msg| {
             sender
               .send_message::<Message, _>(&msg)
               .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
           })
      .unwrap_or_else(|_| {
                        warn!("{}: Problem sending bad json error response", sub_id);
                        Ok(())
                      })
      .is_ok(); // This shouldn't be needed?

  }
<|endoftext|>


<commit_before>#![feature(custom_derive, proc_macro)]

extern crate docopt;
extern crate glob;
extern crate rustc_serialize;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate zip;

use docopt::Docopt;

mod zip_info;
mod flat_writer;
mod json_writer;

use zip_info::WriteZipInfo;

/// The Docopt usage string
const USAGE: &'static str = "
Usage: zi [--exclude=<glob>] <path> ...
       zi --help

zi presents information about Zip archives.

Common options:
    -h, --help        Show this usage message.
    --exclude=<glob>  Ignore objects in the archives whose name
                      is like this glob pattern.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_path: Vec<String>,
    flag_exclude: String
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let mut multiwriter = flat_writer::MultiArchiveFlatWriter::new(
        args.arg_path.as_slice()
    );

    println!("{}", multiwriter.write_zip_info(args.flag_exclude.as_str()));
}
<commit_msg>Make json output accessible in the CLI<commit_after>#![feature(custom_derive, proc_macro)]

extern crate docopt;
extern crate glob;
extern crate rustc_serialize;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate zip;

use docopt::Docopt;

mod zip_info;
mod flat_writer;
mod json_writer;

use zip_info::WriteZipInfo;

/// The Docopt usage string
const USAGE: &'static str = "
Usage: zi [-j | -p] [--exclude=<glob>] <path> ...
       zi --help

zi presents information about Zip archives.

Common options:
    -h, --help         Show this usage message.
    -j, --json         Structure the output in JSON
    -p, --pretty-json  Structure the output in easy-to-read JSON
    --exclude=<glob>   Ignore objects in the archives whose name
                       is like this glob pattern.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_path: Vec<String>,
    flag_json: bool,
    flag_pretty_json: bool,
    flag_exclude: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    // XXX We divide up the display functionality here since
    // the original flat writer works differently than the JSON
    // writer. Ultimately, the JSON writer should be a generic
    // serializer for different output modes, so this will be a
    // lot cleaner.
    if !(args.flag_json || args.flag_pretty_json) {
        let mut multiwriter = flat_writer::MultiArchiveFlatWriter::new(
            args.arg_path.as_slice()
        );

        println!("{}", multiwriter.write_zip_info(args.flag_exclude.as_str()));
    } else {
        // Convert String to &str for json printing since
        // Docopt appears not to be able to handle Vec<&str>:
        let mut path_names: Vec<&str> = Vec::new();

        for path in &args.arg_path {
            path_names.push(path.as_str());
        }

        let s = match args.flag_json {
            true => json_writer::zips_to_json,
            _ => json_writer::zips_to_json_pretty,
        };

        println!("{}", s(path_names.as_slice(), args.flag_exclude.as_str()));
    }
}
<|endoftext|>


<commit_before>//! A 2D toy game written in Rust, using the ggez library.
#![deny(missing_docs)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![feature(nll)]
#![feature(slice_patterns)]

extern crate ggez;
extern crate itertools_num;
extern crate rand;
extern crate structopt;

// Note: we need to load `geometry` first so the macro is available for
// the modules that come afterwards
#[macro_use]
mod geometry;
mod controllers;
mod view;
mod game_state;
mod models;
mod util;

use ggez::event::{self, Keycode, Mod};
use ggez::{Context, GameResult};
use rand::ThreadRng;
use structopt::StructOpt;

use controllers::{CollisionsController, Event, InputController, TimeController};
use game_state::GameState;
use geometry::Size;
use view::Resources;

/// This struct contains the application's state
pub struct ApplicationState {
    // Keep track of window focus to play/pause the game
    has_focus: bool,
    // Resources holds our loaded font, images and sounds
    resources: Resources,
    // The game state contains all information needed to run the game
    game_state: GameState,
    // The time controller modifies the game state as time passes
    time_controller: TimeController,
    // The input controller keeps track of the actions that are triggered by the player
    input_controller: InputController,
    // The event buffer keeps track of events that trigger sounds, so we can separate
    // sound playing from the game logic
    event_buffer: Vec<Event>,
    // A source of randomness
    rng: ThreadRng,
}

impl ApplicationState {
    /// Simply creates a new application state
    fn new(ctx: &mut Context, game_size: Size) -> GameResult<ApplicationState> {
        let mut rng = rand::thread_rng();
        let app_state = ApplicationState {
            has_focus: true,
            resources: Resources::new(ctx),
            game_state: GameState::new(game_size, &mut rng),
            time_controller: TimeController::new(),
            input_controller: InputController::new(),
            event_buffer: Vec::new(),
            rng,
        };
        Ok(app_state)
    }

    /// This will be called when the game needs to be reset
    fn reset(&mut self) {
        // Reset time controller
        self.time_controller.reset();

        // Reset game state
        self.game_state.reset(&mut self.rng);

        self.event_buffer.push(Event::GameStart);
    }
}

// We implement `ggez::event::EventHandler` trait on our application state - this is where we can
// listen for input and other events
impl event::EventHandler for ApplicationState {
    // This is called each time the game loop updates so we can update the game state
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        // Pause the game if the window has no focus
        if !self.has_focus {
            return Ok(())
        }

        // Update game state, and check for collisions
        let duration = ggez::timer::get_delta(ctx);
        self.time_controller.update_seconds(
            duration,
            self.input_controller.actions(),
            &mut self.game_state,
            &mut self.event_buffer,
            &mut self.rng
        );

        CollisionsController::handle_collisions(&mut self.game_state, &mut self.time_controller, &mut self.event_buffer);

        Ok(())
    }

    // This is called when ggez wants us to draw our game
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        view::play_sounds(&mut self.event_buffer, &mut self.resources)?;
        view::render_game(self, ctx)
    }

    // Listen for keyboard events
    fn key_down_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        // If we're displaying a message (waiting for user input) then hide it and reset the game
        if let Some(_) = self.game_state.message {
            self.reset();
        }
        self.input_controller.key_press(keycode, keymod);
    }
    fn key_up_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        self.input_controller.key_release(keycode, keymod);
    }

    // Listen for window focus to pause the game's execution
    fn focus_event(&mut self, _ctx: &mut Context, has_focus: bool) {
        self.has_focus = has_focus;
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "Rocket")]
struct Opt {
    /// Window width
    #[structopt(long = "width", default_value = "1024")]
    width: usize,

    /// Window height
    #[structopt(long = "height", default_value = "600")]
    height: usize,
}

fn main() {
    let opt = Opt::from_args();
    let game_size = Size::new(opt.width as f32, opt.height as f32);

    // Create the rendering context and set the background color to black
    let ctx = &mut view::init_rendering_ctx(game_size).unwrap();

    // Load the application state and start the event loop
    let state = &mut ApplicationState::new(ctx, game_size).unwrap();
    if let Err(err) = event::run(ctx, state) {
        println!("Error encountered: {}", err);
    } else {
        println!("Exited cleanly, thanks for playing Rocket!");
    }
}
<commit_msg>Remove unused feature section<commit_after>//! A 2D toy game written in Rust, using the ggez library.
#![deny(missing_docs)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#![feature(nll)]

extern crate ggez;
extern crate itertools_num;
extern crate rand;
extern crate structopt;

// Note: we need to load `geometry` first so the macro is available for
// the modules that come afterwards
#[macro_use]
mod geometry;
mod controllers;
mod view;
mod game_state;
mod models;
mod util;

use ggez::event::{self, Keycode, Mod};
use ggez::{Context, GameResult};
use rand::ThreadRng;
use structopt::StructOpt;

use controllers::{CollisionsController, Event, InputController, TimeController};
use game_state::GameState;
use geometry::Size;
use view::Resources;

/// This struct contains the application's state
pub struct ApplicationState {
    // Keep track of window focus to play/pause the game
    has_focus: bool,
    // Resources holds our loaded font, images and sounds
    resources: Resources,
    // The game state contains all information needed to run the game
    game_state: GameState,
    // The time controller modifies the game state as time passes
    time_controller: TimeController,
    // The input controller keeps track of the actions that are triggered by the player
    input_controller: InputController,
    // The event buffer keeps track of events that trigger sounds, so we can separate
    // sound playing from the game logic
    event_buffer: Vec<Event>,
    // A source of randomness
    rng: ThreadRng,
}

impl ApplicationState {
    /// Simply creates a new application state
    fn new(ctx: &mut Context, game_size: Size) -> GameResult<ApplicationState> {
        let mut rng = rand::thread_rng();
        let app_state = ApplicationState {
            has_focus: true,
            resources: Resources::new(ctx),
            game_state: GameState::new(game_size, &mut rng),
            time_controller: TimeController::new(),
            input_controller: InputController::new(),
            event_buffer: Vec::new(),
            rng,
        };
        Ok(app_state)
    }

    /// This will be called when the game needs to be reset
    fn reset(&mut self) {
        // Reset time controller
        self.time_controller.reset();

        // Reset game state
        self.game_state.reset(&mut self.rng);

        self.event_buffer.push(Event::GameStart);
    }
}

// We implement `ggez::event::EventHandler` trait on our application state - this is where we can
// listen for input and other events
impl event::EventHandler for ApplicationState {
    // This is called each time the game loop updates so we can update the game state
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        // Pause the game if the window has no focus
        if !self.has_focus {
            return Ok(())
        }

        // Update game state, and check for collisions
        let duration = ggez::timer::get_delta(ctx);
        self.time_controller.update_seconds(
            duration,
            self.input_controller.actions(),
            &mut self.game_state,
            &mut self.event_buffer,
            &mut self.rng
        );

        CollisionsController::handle_collisions(&mut self.game_state, &mut self.time_controller, &mut self.event_buffer);

        Ok(())
    }

    // This is called when ggez wants us to draw our game
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        view::play_sounds(&mut self.event_buffer, &mut self.resources)?;
        view::render_game(self, ctx)
    }

    // Listen for keyboard events
    fn key_down_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        // If we're displaying a message (waiting for user input) then hide it and reset the game
        if let Some(_) = self.game_state.message {
            self.reset();
        }
        self.input_controller.key_press(keycode, keymod);
    }
    fn key_up_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        self.input_controller.key_release(keycode, keymod);
    }

    // Listen for window focus to pause the game's execution
    fn focus_event(&mut self, _ctx: &mut Context, has_focus: bool) {
        self.has_focus = has_focus;
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "Rocket")]
struct Opt {
    /// Window width
    #[structopt(long = "width", default_value = "1024")]
    width: usize,

    /// Window height
    #[structopt(long = "height", default_value = "600")]
    height: usize,
}

fn main() {
    let opt = Opt::from_args();
    let game_size = Size::new(opt.width as f32, opt.height as f32);

    // Create the rendering context and set the background color to black
    let ctx = &mut view::init_rendering_ctx(game_size).unwrap();

    // Load the application state and start the event loop
    let state = &mut ApplicationState::new(ctx, game_size).unwrap();
    if let Err(err) = event::run(ctx, state) {
        println!("Error encountered: {}", err);
    } else {
        println!("Exited cleanly, thanks for playing Rocket!");
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate notify;
extern crate term;

use clap::App;
use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;

use std::io::Write;
use std::thread;
use std::string::String;
use std::path::Path;
use std::process::Command;
use std::convert::Into;

fn out<S:Into<String>>(label: &str, msg: S, color: term::color::Color) -> std::io::Result<()> {
  let mut out = term::stdout().unwrap();
  try!(out.reset());
  try!(out.fg(color));
  try!(write!(&mut std::io::stdout(), "{:>12}", label.to_owned()));
  try!(out.reset());
  try!(write!(&mut std::io::stdout(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn err<S:Into<String>>(label: &str, msg: S) -> std::io::Result<()> {
  let mut out = term::stderr().unwrap();
  try!(out.reset());
  try!(out.fg(term::color::RED));
  try!(write!(&mut std::io::stderr(), "{:>12}", label.to_owned()));
  try!(out.reset());
  try!(write!(&mut std::io::stderr(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn main() {
  let matches = App::new("capgun")
    .about("fires off commands when files change")
    .args_from_usage(
      "-c, --command=<CMD> 'cmd to run when files under <INPUT> change'
       <INPUT> 'Sets the directory to watch'"
    )
    .get_matches();

  let cmd = matches.value_of("CMD").unwrap();
  let input = matches.value_of("INPUT").unwrap();

  let _ = out("Watching", input, term::color::BRIGHT_CYAN);

  let (tx, rx) = channel();
  let watch: Result<RecommendedWatcher, Error> = Watcher::new(tx);

  match watch {
    Ok(mut watcher) =>  {
      match watcher.watch(&Path::new(input)) {
        Ok(_) => {},
        Err(e) => {
          let _ = err("Error", format!("Failed to load gun {:?}", e));
          return
        },
      }

      loop {
        thread::sleep_ms(5000);
        match rx.recv() {
          Ok(e) => fire(e, cmd),
          Err(e) => {
            let _ = err("Missfire", &(format!("{:?}", e)[..]));
            return
          }
        }
      }
    },
    Err(_) => println!("Couldn't generate directory watcher")
  }
}

fn fire(e: notify::Event, cmd:  &str) {
  match e.op {
    Ok(_) => {
      let mut split = cmd.split(" ");
      let mut task = Command::new(split.next().unwrap());
      for s in split {
        task.arg(s);
      }
      let output = task.output()
        .unwrap_or_else(|e| { panic!("Failed to execute cargo: {}", e) });

      println!("{}", String::from_utf8_lossy(&output.stdout));
      match writeln!(&mut std::io::stderr(), "{}", String::from_utf8_lossy(&output.stderr)) {
        Err(x) => panic!("Unable to write to stderr: {}", x),
        Ok(_) => {}
      }
      if output.status.success() {
        let _ = out("Hit", cmd, term::color::BRIGHT_GREEN);
      } else {
        let _ = err("Miss", cmd);
      }
    },
    Err(e) => println!("{:?}", e),
  }
}
<commit_msg>more info<commit_after>extern crate clap;
extern crate notify;
extern crate term;

use clap::App;
use notify::{RecommendedWatcher, Error, Watcher};
use std::sync::mpsc::channel;

use std::io::Write;
use std::thread;
use std::string::String;
use std::path::Path;
use std::process::Command;
use std::convert::Into;

fn out<S:Into<String>>(label: &str, msg: S, color: term::color::Color) -> std::io::Result<()> {
  let mut out = term::stdout().unwrap();
  try!(out.reset());
  try!(out.fg(color));
  try!(write!(&mut std::io::stdout(), "{:>12}", label.to_owned()));
  try!(out.reset());
  try!(write!(&mut std::io::stdout(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn err<S:Into<String>>(label: &str, msg: S) -> std::io::Result<()> {
  let mut out = term::stderr().unwrap();
  try!(out.reset());
  try!(out.fg(term::color::RED));
  try!(write!(&mut std::io::stderr(), "{:>12}", label.to_owned()));
  try!(out.reset());
  try!(write!(&mut std::io::stderr(), " {}\n", msg.into()));
  try!(out.flush());
  Ok(())
}

fn main() {
  let matches = App::new("capgun")
    .about("fires off commands when files change")
    .args_from_usage(
      "-c, --command=<CMD> 'cmd to run when files under <INPUT> change'
       <INPUT> 'Sets the directory to watch'"
    )
    .get_matches();

  let cmd = matches.value_of("CMD").unwrap();
  let input = matches.value_of("INPUT").unwrap();

  let _ = out("Watching", input, term::color::BRIGHT_CYAN);

  let (tx, rx) = channel();
  let watch: Result<RecommendedWatcher, Error> = Watcher::new(tx);

  match watch {
    Ok(mut watcher) =>  {
      match watcher.watch(&Path::new(input)) {
        Ok(_) => {},
        Err(e) => {
          let _ = err("Error", format!("Failed to load gun {:?}", e));
          return
        },
      }

      loop {
        thread::sleep_ms(5000);
        match rx.recv() {
          Ok(e) => fire(e, cmd),
          Err(e) => {
            let _ = err("Missfire", &(format!("{:?}", e)[..]));
            return
          }
        }
      }
    },
    Err(_) => println!("Couldn't generate directory watcher")
  }
}

fn fire(e: notify::Event, cmd:  &str) {
  match e.op {
    Ok(_) => {
      let mut split = cmd.split(" ");
      let mut task = Command::new(split.next().unwrap());
      for s in split {
        task.arg(s);
      }
      let output = task.output()
        .unwrap_or_else(|e| panic!("Failed to fire: {} {}", cmd, e));

      println!("{}", String::from_utf8_lossy(&output.stdout));
      match writeln!(&mut std::io::stderr(), "{}", String::from_utf8_lossy(&output.stderr)) {
        Err(x) => panic!("Unable to write to stderr: {}", x),
        Ok(_) => {}
      }
      if output.status.success() {
        let _ = out("Hit", cmd, term::color::BRIGHT_GREEN);
      } else {
        let _ = err("Miss", cmd);
      }
    },
    Err(e) => println!("{:?}", e),
  }
}
<|endoftext|>


<commit_before>// TODO: write a description.
//! Ferrum is a ...

#![deny(non_camel_case_types)]
#![feature(phase)]

extern crate getopts;
#[phase(plugin, link)] extern crate log;
extern crate mustache;
#[phase(plugin)]extern crate peg_syntax_ext;
extern crate rustdoc;

use std::os;

use getopts::{getopts, optopt, optflag, short_usage, usage};

mod error;
mod ferrum;
mod parser;
mod document;
mod template;
mod util;

fn main() {
    // Setup the possible opts.
    let opts = &[
        optopt("s", "source", "set source directory", "NAME"),
        optopt("d", "destination", "set destination directory", "NAME"),
        optflag("h", "help", "print this help menu")
    ];

    let instructions = "Usage: ferrum [command]";

    // Get the arguments and program name.
    let args: Vec<String> = os::args();
    let program = args[0].clone();

    // Match the opts.
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    // Check if the help opt is present.
    if matches.opt_present("h") {
        println!("{}", usage(program.as_slice(), opts));
        return;
    }

    // Retrieve the command.
    let command = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        println!("{}", short_usage(instructions, opts));
        return;
    };

    match command.as_slice() {
        "build" => ferrum::build(matches),
        _ => {
            println!("{}", short_usage(instructions, opts));
            return;
        }
    }
}
<commit_msg>Remove unused crate<commit_after>// TODO: write a description.
//! Ferrum is a ...

#![deny(non_camel_case_types)]
#![feature(phase)]

extern crate getopts;
#[phase(plugin, link)] extern crate log;
extern crate mustache;
#[phase(plugin)]extern crate peg_syntax_ext;

use std::os;

use getopts::{getopts, optopt, optflag, short_usage, usage};

mod error;
mod ferrum;
mod parser;
mod document;
mod template;
mod util;

fn main() {
    // Setup the possible opts.
    let opts = &[
        optopt("s", "source", "set source directory", "NAME"),
        optopt("d", "destination", "set destination directory", "NAME"),
        optflag("h", "help", "print this help menu")
    ];

    let instructions = "Usage: ferrum [command]";

    // Get the arguments and program name.
    let args: Vec<String> = os::args();
    let program = args[0].clone();

    // Match the opts.
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    // Check if the help opt is present.
    if matches.opt_present("h") {
        println!("{}", usage(program.as_slice(), opts));
        return;
    }

    // Retrieve the command.
    let command = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        println!("{}", short_usage(instructions, opts));
        return;
    };

    match command.as_slice() {
        "build" => ferrum::build(matches),
        _ => {
            println!("{}", short_usage(instructions, opts));
            return;
        }
    }
}
<|endoftext|>


<commit_before>extern crate iron;
#[macro_use]
extern crate mime;
#[macro_use]
extern crate router;
extern crate hyper_native_tls;

use iron::{Iron, Request, Response, status, IronResult};
use router::{Router};

fn main() {
    let router = router!(root: get "/" => handle_root,
                         query: get "/:query" => handle_query);
    Iron::new(router).http("127.0.0.1:8080").unwrap();
}

fn handle_root(_: &mut Request) -> IronResult<Response> {
    let content_type = mime!(Text / Html);
    Ok(Response::with((content_type,
                       status::Ok,
                       "
Hello world!

meeemes

:)")))
}

fn handle_query(req: &mut Request) -> IronResult<Response> {
    let ref query = req.extensions.get::<Router>()
        .unwrap().find("query").unwrap_or("/");
    Ok(Response::with((status::Ok, *query)))
}<commit_msg>Remove ref<commit_after>extern crate iron;
#[macro_use]
extern crate mime;
#[macro_use]
extern crate router;
extern crate hyper_native_tls;

use iron::{Iron, Request, Response, status, IronResult};
use router::{Router};

fn main() {
    let router = router!(root: get "/" => handle_root,
                         query: get "/:query" => handle_query);
    Iron::new(router).http("127.0.0.1:8080").unwrap();
}

fn handle_root(_: &mut Request) -> IronResult<Response> {
    let content_type = mime!(Text / Html);
    Ok(Response::with((content_type,
                       status::Ok,
                       "
Hello world!

meeemes

:)")))
}

fn handle_query(req: &mut Request) -> IronResult<Response> {
    let query = req.extensions.get::<Router>()
        .unwrap().find("query").unwrap_or("/");
    Ok(Response::with((status::Ok, query)))
}<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate sha1;
extern crate serde_json;

//TODO not hardcoded path
const KITAMAN_HOME: &str = "/home/kirillvr/.kitaman/";

#[derive(Serialize)]
enum Requirement {
    Binary(&'static str),
}

#[derive(Serialize)]
struct Requirements {
    requirements: Vec<Requirement>,
}

impl Requirements {
    pub fn new() -> Requirements {
        Requirements {
            requirements: Vec::new(),
        }
    }
    pub fn add(&mut self, requirement: Requirement) {
        self.requirements.push(requirement)
    }
}

fn main() {
    let mut requirements = Requirements::new();
    requirements.add(Requirement::Binary("ruby"));
    let json = serde_json::to_string(&requirements).unwrap();
    let mut hasher = sha1::Sha1::new();
    hasher.update(json.as_bytes());
    println!("{}", hasher.digest())
}
<commit_msg>Digest as string<commit_after>#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate sha1;
extern crate serde_json;

//TODO not hardcoded path
const KITAMAN_HOME: &str = "/home/kirillvr/.kitaman/";

#[derive(Serialize)]
enum Requirement {
    Binary(&'static str),
}

#[derive(Serialize)]
struct Requirements {
    requirements: Vec<Requirement>,
}

impl Requirements {
    pub fn new() -> Requirements {
        Requirements {
            requirements: Vec::new(),
        }
    }
    pub fn add(&mut self, requirement: Requirement) {
        self.requirements.push(requirement)
    }
}

fn main() {
    let mut requirements = Requirements::new();
    requirements.add(Requirement::Binary("ruby"));
    let json = serde_json::to_string(&requirements).unwrap();
    let mut hasher = sha1::Sha1::new();
    hasher.update(json.as_bytes());
    let digest = format!("{}", hasher.digest());
    println!("{}", digest)
}
<|endoftext|>


<commit_before>enum Cell {
    Empty,
    Wall,
    Player
}

fn get_symbol( cell: &Cell ) -> char {
    match cell {
        Empty => '_',
        Wall =>  '#',
        Player => '@'
    }
}

fn main() {
    let mut game_field = [ [ Cell::Empty, Cell::Wall ],
                           [ Cell::Empty, Cell::Empty ] ];

    // let tmp_char = get_symbol( &game_field[0][0] );

    for row in game_field.into_iter() {
        for cell in row.into_iter() {
            let tmp = get_symbol( &cell );
            println!("{}", tmp );
        }

        println!( "\r\n" );
    }
}
<commit_msg>Add dynamic array (Vec); fix printing different symbols<commit_after>enum Cell {
    Empty,
    Wall,
    Player,
}

fn get_symbol( cell: Cell ) -> char {
    match cell {
        Cell::Empty => '_',
        Cell::Wall =>  '#',
        Cell::Player => '@'
    }
}

fn initialize_field( ) -> Vec<Vec<Cell>>{
    //ToDo: parse from file

    let mut result_field: Vec<Vec<Cell>> = Vec::new();

    let mut row: Vec<Cell> = Vec::new();
    row.push(Cell::Empty);
    row.push(Cell::Wall);
    result_field.push(row);

    let mut row: Vec<Cell> = Vec::new();
    row.push(Cell::Player);
    row.push(Cell::Wall);
    result_field.push(row);

    return result_field;
}

fn main() {
    let game_field = initialize_field();

    // let tmp_char = get_symbol( &game_field[0][0] );

    for row in game_field.into_iter() {
        for cell in row.into_iter() {
            let tmp = get_symbol( cell );
            print!("{}", tmp );
        }

        println!( "" );
    }
}
<|endoftext|>