<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-s390x
// ignore-emscripten
// ignore-powerpc
// ignore-sparc

// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir -Z nll

#![feature(asm)]

#[cfg(any(target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64"))]
mod test_cases {
    fn is_move() {
        let y: &mut isize;
        let x = &mut 0isize;
        unsafe {
            asm!("nop" : : "r"(x));
        }
        let z = x;  //[ast]~ ERROR use of moved value: `x`
                    //[mir]~^ ERROR use of moved value: `x`
    }

    fn in_is_read() {
        let mut x = 3;
        let y = &mut x;
        unsafe {
            asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use
                                    //[mir]~^ ERROR cannot use
        }
        let z = y;
    }

    fn out_is_assign() {
        let x = 3;
        unsafe {
            asm!("nop" : "=r"(x));  //[ast]~ ERROR cannot assign twice
                                    //[mir]~^ ERROR cannot assign twice
        }
        let mut a = &mut 3;
        let b = &*a;
        unsafe {
            asm!("nop" : "=r"(a));  //[ast]~ ERROR cannot assign to `a` because it is borrowed
                                    // No MIR error, this is a shallow write.
        }
        let c = b;
        let d = *a;
    }

    fn rw_is_assign() {
        let x = 3;
        unsafe {
            asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign twice
                                    //[mir]~^ ERROR cannot assign twice
        }
    }

    fn indirect_is_not_init() {
        let x: i32;
        unsafe {
            asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable
                                    //[mir]~^ ERROR use of possibly uninitialized variable
        }
    }

    fn rw_is_read() {
        let mut x = &mut 3;
        let y = &*x;
        unsafe {
            asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign to `x` because it is borrowed
                                    //[mir]~^ ERROR cannot assign to `x` because it is borrowed
        }
        let z = y;
    }

    fn two_moves() {
        let x = &mut 2;
        unsafe {
            asm!("nop" : : "r"(x), "r"(x) );    //[ast]~ ERROR use of moved value
                                                //[mir]~^ ERROR use of moved value
        }
    }
}

fn main() {}
<commit_msg>borrowck-asm: enable on mips<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-s390x
// ignore-emscripten
// ignore-powerpc
// ignore-sparc

// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir -Z nll

#![feature(asm)]

#[cfg(any(target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "mips",
            target_arch = "mips64"))]
mod test_cases {
    fn is_move() {
        let y: &mut isize;
        let x = &mut 0isize;
        unsafe {
            asm!("nop" : : "r"(x));
        }
        let z = x;  //[ast]~ ERROR use of moved value: `x`
                    //[mir]~^ ERROR use of moved value: `x`
    }

    fn in_is_read() {
        let mut x = 3;
        let y = &mut x;
        unsafe {
            asm!("nop" : : "r"(x)); //[ast]~ ERROR cannot use
                                    //[mir]~^ ERROR cannot use
        }
        let z = y;
    }

    fn out_is_assign() {
        let x = 3;
        unsafe {
            asm!("nop" : "=r"(x));  //[ast]~ ERROR cannot assign twice
                                    //[mir]~^ ERROR cannot assign twice
        }
        let mut a = &mut 3;
        let b = &*a;
        unsafe {
            asm!("nop" : "=r"(a));  //[ast]~ ERROR cannot assign to `a` because it is borrowed
                                    // No MIR error, this is a shallow write.
        }
        let c = b;
        let d = *a;
    }

    fn rw_is_assign() {
        let x = 3;
        unsafe {
            asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign twice
                                    //[mir]~^ ERROR cannot assign twice
        }
    }

    fn indirect_is_not_init() {
        let x: i32;
        unsafe {
            asm!("nop" : "=*r"(x)); //[ast]~ ERROR use of possibly uninitialized variable
                                    //[mir]~^ ERROR use of possibly uninitialized variable
        }
    }

    fn rw_is_read() {
        let mut x = &mut 3;
        let y = &*x;
        unsafe {
            asm!("nop" : "+r"(x));  //[ast]~ ERROR cannot assign to `x` because it is borrowed
                                    //[mir]~^ ERROR cannot assign to `x` because it is borrowed
        }
        let z = y;
    }

    fn two_moves() {
        let x = &mut 2;
        unsafe {
            asm!("nop" : : "r"(x), "r"(x) );    //[ast]~ ERROR use of moved value
                                                //[mir]~^ ERROR use of moved value
        }
    }
}

fn main() {}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Use_another_language_to_call_a_function
extern crate use_another_language_to_call_a_function;

use use_another_language_to_call_a_function::*;

#[test]
fn buffer_too_small() {
    unsafe {
        const BUF_SIZE: usize = 3;
        let mut buffer = [0; BUF_SIZE];
        assert_eq!(0, Query(buffer.as_mut_ptr(), &mut BUF_SIZE));
    }
}

#[test]
fn buffer_contains_data() {
    use std::ffi::{CStr, CString};

    unsafe {
        const BUF_SIZE: usize = 1024;
        let mut buffer = [0; BUF_SIZE];
        assert_eq!(1, Query(buffer.as_mut_ptr(), &mut BUF_SIZE));
        assert_eq!(CString::new("Here am I").unwrap(),
                   CStr::from_ptr(buffer.as_ptr()).to_owned());
    }
}

fn main() {
    println!("This task is not a binary.");
    println!("Please see the comment at the top of \
              src/use_another_language_to_call_a_function/src/lib.rs.");
}
<commit_msg>remove unused import warning<commit_after>// http://rosettacode.org/wiki/Use_another_language_to_call_a_function
extern crate use_another_language_to_call_a_function;

#[test]
fn buffer_too_small() {
    unsafe {
        const BUF_SIZE: usize = 3;
        let mut buffer = [0; BUF_SIZE];
        assert_eq!(0,
                   use_another_language_to_call_a_function::Query(buffer.as_mut_ptr(),
                                                                  &mut BUF_SIZE));
    }
}

#[test]
fn buffer_contains_data() {
    use std::ffi::{CStr, CString};

    unsafe {
        const BUF_SIZE: usize = 1024;
        let mut buffer = [0; BUF_SIZE];
        assert_eq!(1,
                   use_another_language_to_call_a_function::Query(buffer.as_mut_ptr(),
                                                                  &mut BUF_SIZE));
        assert_eq!(CString::new("Here am I").unwrap(),
                   CStr::from_ptr(buffer.as_ptr()).to_owned());
    }
}

fn main() {
    println!("This task is not a binary.");
    println!("Please see the comment at the top of \
              src/use_another_language_to_call_a_function/src/lib.rs.");
}
<|endoftext|>


<commit_before>use std::env;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

extern crate toml;

#[macro_use]
extern crate serde_derive;

// error in rust compiler.  Bugfix requested in Sept. 2017
// these are used, but the compiler is not seeing it for
// some reason
#[allow(unused_imports)]
#[macro_use]
extern crate serde_json;
// error in rust compiler.  Bugfix has been submitted in Sept. 2017
#[allow(unused_imports)]
#[macro_use]
extern crate serde;

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Tomlfile {
    contents: Contents,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Metadata {
    deb: Deb,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Deb {
    revision: Option<String>,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Package {
    name: String,
    version: Option<String>,
    metadata: Metadata,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Contents {
    package: Package,
    dependencies: Option<toml::Value>,
}

fn main() {
    let target = env::var("TARGET").unwrap();
    println!("target={}", target);

    if let Ok(_mode) = env::var("LIBINDY_STATIC") {
        let libindy_lib_path = env::var("LIBINDY_DIR").unwrap();
        println!("cargo:rustc-link-search=native={}",libindy_lib_path);
        println!("cargo:rustc-link-lib=static=indy");
    }else if target.contains("aarch64-linux-android") || target.contains("armv7-linux-androideabi") ||
        target.contains("arm-linux-androideabi") || target.contains("i686-linux-android") ||
        target.contains("x86_64-linux-android") || target.contains("aarch64-apple-ios") ||
        target.contains("armv7-apple-ios") || target.contains("armv7s-apple-ios") ||
        target.contains("i386-apple-ios") || target.contains("x86_64-apple-ios") {

        let libindy_lib_path = match env::var("LIBINDY_DIR"){
            Ok(val) => val,
            Err(..) => panic!("Missing required environment variable LIBINDY_DIR")
        };

        let openssl = match env::var("OPENSSL_LIB_DIR") {
            Ok(val) => val,
            Err(..) => match env::var("OPENSSL_DIR") {
                Ok(dir) => Path::new(&dir[..]).join("/lib").to_string_lossy().into_owned(),
                Err(..) => panic!("Missing required environment variables OPENSSL_DIR or OPENSSL_LIB_DIR")
            }
        };

        println!("cargo:rustc-link-search=native={}",libindy_lib_path);
        println!("cargo:rustc-link-lib=static=indy");
        println!("cargo:rustc-link-search=native={}", openssl);
        println!("cargo:rustc-link-lib=static=crypto");
        println!("cargo:rustc-link-lib=static=ssl");

    }else if target.contains("darwin"){
        //OSX specific logic
        println!("cargo:rustc-link-lib=indy");
        //OSX does not allow 3rd party libs to be installed in /usr/lib. Instead install it in /usr/local/lib
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }else if target.contains("-linux-"){
        //Linux specific logic
        println!("cargo:rustc-link-lib=indy");
        println!("cargo:rustc-link-search=native=/usr/lib");
    }else if target.contains("-windows-") {
        println!("cargo:rustc-link-lib=indy.dll");

        let profile = env::var("PROFILE").unwrap();
        println!("profile={}", profile);

        let indy_dir = env::var("INDY_DIR").unwrap_or(format!("..\\..\\libindy\\target\\{}", profile));
        println!("indy_dir={}", indy_dir);
        let indy_dir = Path::new(indy_dir.as_str());

        println!("cargo:rustc-flags=-L {}", indy_dir.as_os_str().to_str().unwrap());
    }

    match env::var("CARGO_FEATURE_CI") {
        Ok(_) => {
            println!("injecting version information");
            // Leaving as unwrap, this is in the build script.
            let revision = get_revision().unwrap();
            write_variables(&revision);
        },
        Err(_) => {println!("NOT injecting version information"); },
    };
}

// Writes to the file 'src/utils/version_constants.rs' for use
// in outputing the version dynamically.
fn write_variables(revision:&str) {
    let out_dir = "src/utils/";
    let dest_path = Path::new(&out_dir).join("version_constants.rs");
    let mut f = File::create(&dest_path).unwrap();
    let s = format!("pub const VERSION: &'static str = env!(\"CARGO_PKG_VERSION\");\npub const REVISION: &'static str = \"{}\";\n", revision);
    if let Err(e) = f.write_all(s.as_bytes()) {
       panic!("Error creating version_constants.rs: {}", e);
    };

}

// Gets the revision number from the Cargo.toml file.
pub fn get_revision() -> Option<String> {
    let dir = match  env::var("CARGO_MANIFEST_DIR"){
        Ok(d) => d,
        Err(_) => panic!("Couldn't Manifest Directory"),
    };
    let filename = "Cargo.toml";
    let p = format!("{}/{}",dir,filename);
    let mut input = String::new();
    File::open(p).and_then(|mut f| {
        f.read_to_string(&mut input)}).unwrap();
    let tomlfile:Contents = toml::from_str(&input).unwrap();
    let revision:String = match tomlfile.package.metadata.deb.revision {
        Some(v) => v,
        None => String::from(""),
    };
    Some(format!("+{}", revision))
}

<commit_msg>Updated Libvcx build.rs to copy dependencies<commit_after>use std::env;
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

extern crate toml;

#[macro_use]
extern crate serde_derive;

// error in rust compiler.  Bugfix requested in Sept. 2017
// these are used, but the compiler is not seeing it for
// some reason
#[allow(unused_imports)]
#[macro_use]
extern crate serde_json;
// error in rust compiler.  Bugfix has been submitted in Sept. 2017
#[allow(unused_imports)]
#[macro_use]
extern crate serde;

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Tomlfile {
    contents: Contents,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Metadata {
    deb: Deb,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Deb {
    revision: Option<String>,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Package {
    name: String,
    version: Option<String>,
    metadata: Metadata,
}

// used in formatting the Cargo.toml file
#[derive(Deserialize, Debug)]
struct Contents {
    package: Package,
    dependencies: Option<toml::Value>,
}

fn main() {
    let target = env::var("TARGET").unwrap();
    println!("target={}", target);

    if let Ok(_mode) = env::var("LIBINDY_STATIC") {
        let libindy_lib_path = env::var("LIBINDY_DIR").unwrap();
        println!("cargo:rustc-link-search=native={}",libindy_lib_path);
        println!("cargo:rustc-link-lib=static=indy");
    }else if target.contains("aarch64-linux-android") || target.contains("armv7-linux-androideabi") ||
        target.contains("arm-linux-androideabi") || target.contains("i686-linux-android") ||
        target.contains("x86_64-linux-android") || target.contains("aarch64-apple-ios") ||
        target.contains("armv7-apple-ios") || target.contains("armv7s-apple-ios") ||
        target.contains("i386-apple-ios") || target.contains("x86_64-apple-ios") {

        let libindy_lib_path = match env::var("LIBINDY_DIR"){
            Ok(val) => val,
            Err(..) => panic!("Missing required environment variable LIBINDY_DIR")
        };

        let openssl = match env::var("OPENSSL_LIB_DIR") {
            Ok(val) => val,
            Err(..) => match env::var("OPENSSL_DIR") {
                Ok(dir) => Path::new(&dir[..]).join("/lib").to_string_lossy().into_owned(),
                Err(..) => panic!("Missing required environment variables OPENSSL_DIR or OPENSSL_LIB_DIR")
            }
        };

        println!("cargo:rustc-link-search=native={}",libindy_lib_path);
        println!("cargo:rustc-link-lib=static=indy");
        println!("cargo:rustc-link-search=native={}", openssl);
        println!("cargo:rustc-link-lib=static=crypto");
        println!("cargo:rustc-link-lib=static=ssl");

    }else if target.contains("darwin"){
        //OSX specific logic
        println!("cargo:rustc-link-lib=indy");
        //OSX does not allow 3rd party libs to be installed in /usr/lib. Instead install it in /usr/local/lib
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }else if target.contains("-linux-"){
        //Linux specific logic
        println!("cargo:rustc-link-lib=indy");
        println!("cargo:rustc-link-search=native=/usr/lib");
    }else if target.contains("-windows-") {
        println!("cargo:rustc-link-lib=indy.dll");

        let profile = env::var("PROFILE").unwrap();
        println!("profile={}", profile);

        let output_dir = env::var("OUT_DIR").unwrap();
        println!("output_dir={}", output_dir);
        let output_dir = Path::new(output_dir.as_str());

        let indy_dir = env::var("INDY_DIR").unwrap_or(format!("..\\..\\libindy\\target\\{}", profile));
        println!("indy_dir={}", indy_dir);
        let indy_dir = Path::new(indy_dir.as_str());

        let dst = output_dir.join("..\\..\\..\\..");
        println!("cargo:rustc-flags=-L {}", indy_dir.as_os_str().to_str().unwrap());

        let files = vec!["indy.dll", "libeay32md.dll", "libsodium.dll", "libzmq.dll", "ssleay32md.dll"];
        for f in files.iter() {
            if let Ok(_) = fs::copy(&indy_dir.join(f), &dst.join(f)) {
                println!("copy {} -> {}", &indy_dir.join(f).display(), &dst.join(f).display());
            }
        }
    }

    match env::var("CARGO_FEATURE_CI") {
        Ok(_) => {
            println!("injecting version information");
            // Leaving as unwrap, this is in the build script.
            let revision = get_revision().unwrap();
            write_variables(&revision);
        },
        Err(_) => {println!("NOT injecting version information"); },
    };
}

// Writes to the file 'src/utils/version_constants.rs' for use
// in outputing the version dynamically.
fn write_variables(revision:&str) {
    let out_dir = "src/utils/";
    let dest_path = Path::new(&out_dir).join("version_constants.rs");
    let mut f = File::create(&dest_path).unwrap();
    let s = format!("pub const VERSION: &'static str = env!(\"CARGO_PKG_VERSION\");\npub const REVISION: &'static str = \"{}\";\n", revision);
    if let Err(e) = f.write_all(s.as_bytes()) {
       panic!("Error creating version_constants.rs: {}", e);
    };

}

// Gets the revision number from the Cargo.toml file.
pub fn get_revision() -> Option<String> {
    let dir = match  env::var("CARGO_MANIFEST_DIR"){
        Ok(d) => d,
        Err(_) => panic!("Couldn't Manifest Directory"),
    };
    let filename = "Cargo.toml";
    let p = format!("{}/{}",dir,filename);
    let mut input = String::new();
    File::open(p).and_then(|mut f| {
        f.read_to_string(&mut input)}).unwrap();
    let tomlfile:Contents = toml::from_str(&input).unwrap();
    let revision:String = match tomlfile.package.metadata.deb.revision {
        Some(v) => v,
        None => String::from(""),
    };
    Some(format!("+{}", revision))
}

<|endoftext|>


<commit_before><commit_msg>Use path instead of &str<commit_after><|endoftext|>


<commit_before>#![deny(warnings)]
#[macro_use]
extern crate clap;

extern crate svgbob;
extern crate svg;

use svgbob::Grid;
use svgbob::Settings;

use clap::ArgMatches;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error::Error;
use std::io::Read;
use std::process::exit;

fn main() {
    use clap::{Arg, App, SubCommand};

    let args = App::new("svgbob")
        .version(crate_version!())
        .about("SvgBobRus is an ascii to svg converter")
        .arg(Arg::with_name("inline").short("s").help("parse an inline string"))
        .arg(Arg::with_name("input").index(1).help("svgbob text file or inline string to parse [default: STDIN]"))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("where to write svg output [default: STDOUT]"))
        .subcommand(SubCommand::with_name("build")
            .about("Batch convert files to svg.")
            .version("0.0.1")
            .arg(Arg::with_name("input")
                .short("i")
                .long("input")
                .takes_value(true)
                .help("set input file pattern like: *.bob or dir/*.bob"))
            .arg(Arg::with_name("outdir")
                .short("o")
                .long("outdir")
                .takes_value(true)
                .help("set dir of svg files")))
        .get_matches();

    if let Some(sub_build) = args.subcommand_matches("build") {
        match build(sub_build) {
            Ok(_) => {}
            Err(e) => println!("{}", e),
        };
        exit(1);
    }

    let mut bob = String::new();

    if args.is_present("inline") {
        bob = args.value_of("input").unwrap().replace("\\n","\n").to_string();
    } else {
        if let Some(file) = args.value_of("input") {
            match File::open(file) {
                Ok(mut f) => {
                    f.read_to_string(&mut bob).unwrap();
                }
                Err(e) => {
                    use std::io::Write;
                    use std::process::exit;

                    writeln!(&mut std::io::stderr(),
                            "Failed to open input file {}: {}",
                            file,
                            e)
                        .unwrap();
                    exit(1);
                }
            }
        } else {
            use std::io;
            io::stdin().read_to_string(&mut bob).unwrap();
        }
    }

    let g = Grid::from_str(&*bob, &Settings::compact());
    let svg = g.get_svg();

    if let Some(file) = args.value_of("output") {
        if let Err(e) = svg::save(file, &svg) {
            use std::io::Write;
            use std::process::exit;

            writeln!(&mut std::io::stderr(),
                     "Failed to write to output file {}: {}",
                     file,
                     e)
                .unwrap();
            exit(2);
        }
    } else {
        println!("{}", svg);
    }
}

// Batch convert files to svg
// use svgbob build -i inputdir/*.bob -o outdir/
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {

    let files_pattern = args.value_of("input").unwrap_or("*.bob");
    let outdir = args.value_of("outdir").unwrap_or("");
    let input_path = Path::new(files_pattern);
    let ext = input_path.extension().unwrap_or(&"bob".as_ref()).to_str().unwrap();

    let input_dir = if input_path.is_dir() {
        input_path.clone()
    } else {
        input_path.parent().unwrap()
    };

    if !input_dir.is_dir() {
        return Err(Box::from(format!("[Error]: No such dir name is {} !",
                                     input_dir.to_string_lossy())));
    }

    let mut out_path = PathBuf::new();
    if outdir == "" {
        out_path = input_dir.to_path_buf();
    } else {
        out_path.push(outdir)
    }

    if !out_path.is_dir() {
        try!(fs::create_dir_all(out_path.clone()));
    }

    let paths = fs::read_dir(input_dir).unwrap();
    for path in paths {
        let tmp_path = path.unwrap().path();
        if tmp_path.is_file() {
            let tmp_ext = tmp_path.extension().unwrap_or(&"".as_ref()).to_str().unwrap();
            if tmp_ext == ext {
                let name = tmp_path.file_stem().unwrap().to_str().unwrap();
                let mut tmp = out_path.clone();
                tmp.push(format!("{}.svg", name));
                println!("{} => {}", tmp_path.display(), tmp.display());
                match convert_file(tmp_path.clone(), tmp) {
                    Ok(_) => {}
                    Err(e) => {
                        println!("{}", e);
                    }
                }
            }
        }
    }

    Ok(())
}

fn convert_file(input: PathBuf, output: PathBuf) -> Result<(), Box<Error>> {
    let mut bob = String::new();
    let mut f = try!(File::open(&input));
    f.read_to_string(&mut bob).unwrap();
    let g = Grid::from_str(&*bob,&Settings::compact());
    let svg = g.get_svg();
    try!(svg::save(&output, &svg));
    Ok(())
}
<commit_msg>Add command line arguments for font-size and font-family<commit_after>#![deny(warnings)]
#[macro_use]
extern crate clap;

extern crate svgbob;
extern crate svg;

use svgbob::Grid;
use svgbob::Settings;

use clap::ArgMatches;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error::Error;
use std::io::Read;
use std::process::exit;

fn main() {
    use clap::{Arg, App, SubCommand};

    let args = App::new("svgbob")
        .version(crate_version!())
        .about("SvgBobRus is an ascii to svg converter")
        .arg(Arg::with_name("inline").short("s").help("parse an inline string"))
        .arg(Arg::with_name("input").index(1).help("svgbob text file or inline string to parse [default: STDIN]"))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("where to write svg output [default: STDOUT]"))
        .arg(Arg::with_name("font-family")
             .long("font-family")
             .takes_value(true)
             .help("text will be rendered with this font"))
        .arg(Arg::with_name("font-size")
             .long("font-size")
             .takes_value(true)
             .help("text will be rendered with this font size"))
        .subcommand(SubCommand::with_name("build")
            .about("Batch convert files to svg.")
            .version("0.0.1")
            .arg(Arg::with_name("input")
                .short("i")
                .long("input")
                .takes_value(true)
                .help("set input file pattern like: *.bob or dir/*.bob"))
            .arg(Arg::with_name("outdir")
                .short("o")
                .long("outdir")
                .takes_value(true)
                .help("set dir of svg files")))
        .get_matches();

    if let Some(sub_build) = args.subcommand_matches("build") {
        match build(sub_build) {
            Ok(_) => {}
            Err(e) => println!("{}", e),
        };
        exit(1);
    }

    let mut bob = String::new();

    if args.is_present("inline") {
        bob = args.value_of("input").unwrap().replace("\\n","\n").to_string();
    } else {
        if let Some(file) = args.value_of("input") {
            match File::open(file) {
                Ok(mut f) => {
                    f.read_to_string(&mut bob).unwrap();
                }
                Err(e) => {
                    use std::io::Write;
                    use std::process::exit;

                    writeln!(&mut std::io::stderr(),
                            "Failed to open input file {}: {}",
                            file,
                            e)
                        .unwrap();
                    exit(1);
                }
            }
        } else {
            use std::io;
            io::stdin().read_to_string(&mut bob).unwrap();
        }
    }

    let mut settings = Settings::compact();

    if let Some(font_family) = args.value_of("font-family") {
        settings.font_family = font_family.to_string();
    }

    if let Some(font_size) = args.value_of("font-size") {
        match font_size.parse() {
            Ok(fs) => {
                settings.font_size = fs;
            }
            Err(e) => {
                use std::io::Write;
                use std::process::exit;

                writeln!(&mut std::io::stderr(),
                         "Wrong font size: {}",
                         e)
                    .unwrap();
                exit(1);
            }
        }
    }

    let g = Grid::from_str(&*bob, &settings);
    let svg = g.get_svg();

    if let Some(file) = args.value_of("output") {
        if let Err(e) = svg::save(file, &svg) {
            use std::io::Write;
            use std::process::exit;

            writeln!(&mut std::io::stderr(),
                     "Failed to write to output file {}: {}",
                     file,
                     e)
                .unwrap();
            exit(2);
        }
    } else {
        println!("{}", svg);
    }
}

// Batch convert files to svg
// use svgbob build -i inputdir/*.bob -o outdir/
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {

    let files_pattern = args.value_of("input").unwrap_or("*.bob");
    let outdir = args.value_of("outdir").unwrap_or("");
    let input_path = Path::new(files_pattern);
    let ext = input_path.extension().unwrap_or(&"bob".as_ref()).to_str().unwrap();

    let input_dir = if input_path.is_dir() {
        input_path.clone()
    } else {
        input_path.parent().unwrap()
    };

    if !input_dir.is_dir() {
        return Err(Box::from(format!("[Error]: No such dir name is {} !",
                                     input_dir.to_string_lossy())));
    }

    let mut out_path = PathBuf::new();
    if outdir == "" {
        out_path = input_dir.to_path_buf();
    } else {
        out_path.push(outdir)
    }

    if !out_path.is_dir() {
        try!(fs::create_dir_all(out_path.clone()));
    }

    let paths = fs::read_dir(input_dir).unwrap();
    for path in paths {
        let tmp_path = path.unwrap().path();
        if tmp_path.is_file() {
            let tmp_ext = tmp_path.extension().unwrap_or(&"".as_ref()).to_str().unwrap();
            if tmp_ext == ext {
                let name = tmp_path.file_stem().unwrap().to_str().unwrap();
                let mut tmp = out_path.clone();
                tmp.push(format!("{}.svg", name));
                println!("{} => {}", tmp_path.display(), tmp.display());
                match convert_file(tmp_path.clone(), tmp) {
                    Ok(_) => {}
                    Err(e) => {
                        println!("{}", e);
                    }
                }
            }
        }
    }

    Ok(())
}

fn convert_file(input: PathBuf, output: PathBuf) -> Result<(), Box<Error>> {
    let mut bob = String::new();
    let mut f = try!(File::open(&input));
    f.read_to_string(&mut bob).unwrap();
    let g = Grid::from_str(&*bob,&Settings::compact());
    let svg = g.get_svg();
    try!(svg::save(&output, &svg));
    Ok(())
}
<|endoftext|>


<commit_before>use super::Scratchpad;
use crate::StrError;
use russell_lab::mat_mat_mul;

impl Scratchpad {
    /// Calculates the gradient of the interpolation functions
    ///
    /// **Note:** This function works with `geo_ndim == space_ndim` only.
    ///
    /// The gradient is given by:
    ///
    /// ```text
    ///             →
    /// →  →    dNᵐ(ξ)
    /// Gᵐ(ξ) = ——————
    ///            →
    ///           dx
    /// ```
    ///
    /// which can be organized in an (nnode,space_ndim) matrix `G` as follows
    ///
    /// ```text
    /// G = L · J⁻¹
    /// ```
    ///
    /// # Output
    ///
    /// * `deriv` -- interpolation functions (nnode)
    /// * `jacobian` -- Jacobian matrix (space_ndim,geo_ndim)
    /// * `inv_jacobian` -- inverse Jacobian matrix (space_ndim,space_ndim)
    /// * `gradient` -- gradient matrix (nnode,space_ndim)
    /// * Returns the determinant of the Jacobian matrix
    ///
    /// # Input
    ///
    /// * `ksi` -- reference coordinates ξ with len ≥ geo_ndim
    ///
    /// # Example
    ///
    /// ```
    /// use gemlab::shapes::{GeoKind, Scratchpad};
    /// use gemlab::StrError;
    /// use russell_chk::assert_vec_approx_eq;
    /// use russell_lab::Matrix;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     //  3-------------2         ξ₀   ξ₁
    ///     //  |      ξ₁     |  node    r    s
    ///     //  |      |      |     0 -1.0 -1.0
    ///     //  |      +--ξ₀  |     1  1.0 -1.0
    ///     //  |             |     2  1.0  1.0
    ///     //  |             |     3 -1.0  1.0
    ///     //  0-------------1
    ///
    ///     let a = 3.0;
    ///     let space_ndim = 2;
    ///     let mut pad = Scratchpad::new(space_ndim, GeoKind::Qua4)?;
    ///     pad.set_xx(0, 0, 0.0);
    ///     pad.set_xx(0, 1, 0.0);
    ///     pad.set_xx(1, 0, 2.0 * a);
    ///     pad.set_xx(1, 1, 0.0);
    ///     pad.set_xx(2, 0, 2.0 * a);
    ///     pad.set_xx(2, 1, a);
    ///     pad.set_xx(3, 0, 0.0);
    ///     pad.set_xx(3, 1, a);
    ///
    ///     pad.calc_gradient(&[0.0, 0.0])?;
    ///
    ///     let correct_gg = Matrix::from(&[
    ///         [-1.0 / (4.0 * a), -1.0 / (2.0 * a)],
    ///         [1.0 / (4.0 * a), -1.0 / (2.0 * a)],
    ///         [1.0 / (4.0 * a), 1.0 / (2.0 * a)],
    ///         [-1.0 / (4.0 * a), 1.0 / (2.0 * a)],
    ///     ]);
    ///     assert_vec_approx_eq!(pad.gradient.as_data(), correct_gg.as_data(), 1e-15);
    ///     Ok(())
    /// }
    /// ```
    pub fn calc_gradient(&mut self, ksi: &[f64]) -> Result<f64, StrError> {
        // check
        let (space_ndim, geo_ndim) = self.jacobian.dims();
        if geo_ndim != space_ndim {
            return Err("calc_gradient requires that geo_ndim = space_ndim");
        }

        // Jacobian matrix J: dx/dξ
        let det_jac = self.calc_jacobian(ksi)?;

        // gradient: G = L · J⁻¹
        mat_mat_mul(&mut self.gradient, 1.0, &self.deriv, &self.inv_jacobian).unwrap(); // cannot fail because the dims are checked
        Ok(det_jac)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::shapes::scratchpad_testing::aux;
    use crate::shapes::{GeoKind, Scratchpad};
    use crate::util::ONE_BY_3;
    use russell_chk::assert_deriv_approx_eq;
    use russell_lab::{copy_vector, Vector};

    #[test]
    fn calc_gradient_handles_errors() {
        let mut pad = Scratchpad::new(2, GeoKind::Lin2).unwrap();
        assert_eq!(
            pad.calc_gradient(&[0.0, 0.0]).err(),
            Some("calc_gradient requires that geo_ndim = space_ndim")
        );

        let mut pad = Scratchpad::new(2, GeoKind::Tri3).unwrap();
        assert_eq!(
            pad.calc_gradient(&[0.0, 0.0]).err(),
            Some("all components of the coordinates matrix must be set first")
        );
    }

    // Holds arguments for numerical differentiation of N with respect to x => G (gradient) matrix
    struct ArgsNumGrad {
        pad: Scratchpad, // scratchpad to send to calc_coords
        at_x: Vector,    // at x coord value
        x: Vector,       // temporary x coord
        ksi: Vec<f64>,   // temporary reference coord
        m: usize,        // node index from 0 to nnode
        j: usize,        // dimension index from 0 to space_ndim
    }

    // Computes Nᵐ(ξ(x)) with variable v := xⱼ
    fn nn_given_x(v: f64, args: &mut ArgsNumGrad) -> f64 {
        copy_vector(&mut args.x, &args.at_x).unwrap();
        args.x[args.j] = v;
        args.pad.approximate_ksi(&mut args.ksi, &args.x, 10, 1e-14).unwrap();
        (args.pad.fn_interp)(&mut args.pad.interp, &args.ksi);
        args.pad.interp[args.m]
    }

    #[test]
    fn calc_gradient_works() {
        // kind (except Lin) and tolerances
        let problem = vec![
            // Tri
            (GeoKind::Tri3, 1e-12),
            (GeoKind::Tri6, 1e-10),
            (GeoKind::Tri10, 1e-9),
            (GeoKind::Tri15, 1e-9),
            // Qua
            (GeoKind::Qua4, 1e-11),
            (GeoKind::Qua8, 1e-10),
            (GeoKind::Qua9, 1e-10),
            (GeoKind::Qua12, 1e-10),
            (GeoKind::Qua16, 1e-10),
            (GeoKind::Qua17, 1e-9),
            // Tet
            (GeoKind::Tet4, 1e-12),
            (GeoKind::Tet10, 1e-9),
            (GeoKind::Tet20, 1e-9),
            // Hex
            (GeoKind::Hex8, 1e-11),
            (GeoKind::Hex20, 1e-10),
            (GeoKind::Hex32, 1e-9),
        ];

        // loop over shapes
        for (kind, tol) in problem {
            // scratchpad with coordinates
            let geo_ndim = kind.ndim();
            let space_ndim = usize::max(2, geo_ndim);
            let mut pad = aux::gen_scratchpad_with_coords(space_ndim, kind);

            // set ξ within reference space
            let at_ksi = vec![ONE_BY_3; geo_ndim];

            // compute x corresponding to ξ using the isoparametric formula
            let mut at_x = Vector::new(space_ndim);
            pad.calc_coords(&mut at_x, &at_ksi).unwrap();

            // compute gradient
            let det_jac = pad.calc_gradient(&at_ksi).unwrap();
            assert!(det_jac > 0.0);

            // set arguments for numerical integration
            let args = &mut ArgsNumGrad {
                pad: pad.clone(),
                at_x,
                x: Vector::new(space_ndim),
                ksi: vec![0.0; geo_ndim],
                m: 0,
                j: 0,
            };

            // check Gᵐ(ξ(x)) = dNᵐ(ξ(x))/dx
            for m in 0..kind.nnode() {
                args.m = m;
                for j in 0..geo_ndim {
                    args.j = j;
                    // Gᵐⱼ := dNᵐ/dxⱼ
                    assert_deriv_approx_eq!(pad.gradient[m][j], args.at_x[j], nn_given_x, args, tol);
                }
            }
        }
    }
}
<commit_msg>Increase tol of gradient test for notebook<commit_after>use super::Scratchpad;
use crate::StrError;
use russell_lab::mat_mat_mul;

impl Scratchpad {
    /// Calculates the gradient of the interpolation functions
    ///
    /// **Note:** This function works with `geo_ndim == space_ndim` only.
    ///
    /// The gradient is given by:
    ///
    /// ```text
    ///             →
    /// →  →    dNᵐ(ξ)
    /// Gᵐ(ξ) = ——————
    ///            →
    ///           dx
    /// ```
    ///
    /// which can be organized in an (nnode,space_ndim) matrix `G` as follows
    ///
    /// ```text
    /// G = L · J⁻¹
    /// ```
    ///
    /// # Output
    ///
    /// * `deriv` -- interpolation functions (nnode)
    /// * `jacobian` -- Jacobian matrix (space_ndim,geo_ndim)
    /// * `inv_jacobian` -- inverse Jacobian matrix (space_ndim,space_ndim)
    /// * `gradient` -- gradient matrix (nnode,space_ndim)
    /// * Returns the determinant of the Jacobian matrix
    ///
    /// # Input
    ///
    /// * `ksi` -- reference coordinates ξ with len ≥ geo_ndim
    ///
    /// # Example
    ///
    /// ```
    /// use gemlab::shapes::{GeoKind, Scratchpad};
    /// use gemlab::StrError;
    /// use russell_chk::assert_vec_approx_eq;
    /// use russell_lab::Matrix;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     //  3-------------2         ξ₀   ξ₁
    ///     //  |      ξ₁     |  node    r    s
    ///     //  |      |      |     0 -1.0 -1.0
    ///     //  |      +--ξ₀  |     1  1.0 -1.0
    ///     //  |             |     2  1.0  1.0
    ///     //  |             |     3 -1.0  1.0
    ///     //  0-------------1
    ///
    ///     let a = 3.0;
    ///     let space_ndim = 2;
    ///     let mut pad = Scratchpad::new(space_ndim, GeoKind::Qua4)?;
    ///     pad.set_xx(0, 0, 0.0);
    ///     pad.set_xx(0, 1, 0.0);
    ///     pad.set_xx(1, 0, 2.0 * a);
    ///     pad.set_xx(1, 1, 0.0);
    ///     pad.set_xx(2, 0, 2.0 * a);
    ///     pad.set_xx(2, 1, a);
    ///     pad.set_xx(3, 0, 0.0);
    ///     pad.set_xx(3, 1, a);
    ///
    ///     pad.calc_gradient(&[0.0, 0.0])?;
    ///
    ///     let correct_gg = Matrix::from(&[
    ///         [-1.0 / (4.0 * a), -1.0 / (2.0 * a)],
    ///         [1.0 / (4.0 * a), -1.0 / (2.0 * a)],
    ///         [1.0 / (4.0 * a), 1.0 / (2.0 * a)],
    ///         [-1.0 / (4.0 * a), 1.0 / (2.0 * a)],
    ///     ]);
    ///     assert_vec_approx_eq!(pad.gradient.as_data(), correct_gg.as_data(), 1e-15);
    ///     Ok(())
    /// }
    /// ```
    pub fn calc_gradient(&mut self, ksi: &[f64]) -> Result<f64, StrError> {
        // check
        let (space_ndim, geo_ndim) = self.jacobian.dims();
        if geo_ndim != space_ndim {
            return Err("calc_gradient requires that geo_ndim = space_ndim");
        }

        // Jacobian matrix J: dx/dξ
        let det_jac = self.calc_jacobian(ksi)?;

        // gradient: G = L · J⁻¹
        mat_mat_mul(&mut self.gradient, 1.0, &self.deriv, &self.inv_jacobian).unwrap(); // cannot fail because the dims are checked
        Ok(det_jac)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::shapes::scratchpad_testing::aux;
    use crate::shapes::{GeoKind, Scratchpad};
    use crate::util::ONE_BY_3;
    use russell_chk::assert_deriv_approx_eq;
    use russell_lab::{copy_vector, Vector};

    #[test]
    fn calc_gradient_handles_errors() {
        let mut pad = Scratchpad::new(2, GeoKind::Lin2).unwrap();
        assert_eq!(
            pad.calc_gradient(&[0.0, 0.0]).err(),
            Some("calc_gradient requires that geo_ndim = space_ndim")
        );

        let mut pad = Scratchpad::new(2, GeoKind::Tri3).unwrap();
        assert_eq!(
            pad.calc_gradient(&[0.0, 0.0]).err(),
            Some("all components of the coordinates matrix must be set first")
        );
    }

    // Holds arguments for numerical differentiation of N with respect to x => G (gradient) matrix
    struct ArgsNumGrad {
        pad: Scratchpad, // scratchpad to send to calc_coords
        at_x: Vector,    // at x coord value
        x: Vector,       // temporary x coord
        ksi: Vec<f64>,   // temporary reference coord
        m: usize,        // node index from 0 to nnode
        j: usize,        // dimension index from 0 to space_ndim
    }

    // Computes Nᵐ(ξ(x)) with variable v := xⱼ
    fn nn_given_x(v: f64, args: &mut ArgsNumGrad) -> f64 {
        copy_vector(&mut args.x, &args.at_x).unwrap();
        args.x[args.j] = v;
        args.pad.approximate_ksi(&mut args.ksi, &args.x, 10, 1e-14).unwrap();
        (args.pad.fn_interp)(&mut args.pad.interp, &args.ksi);
        args.pad.interp[args.m]
    }

    #[test]
    fn calc_gradient_works() {
        // kind (except Lin) and tolerances
        let problem = vec![
            // Tri
            (GeoKind::Tri3, 1e-12),
            (GeoKind::Tri6, 1e-10),
            (GeoKind::Tri10, 1e-9),
            (GeoKind::Tri15, 1e-9),
            // Qua
            (GeoKind::Qua4, 1e-11),
            (GeoKind::Qua8, 1e-10),
            (GeoKind::Qua9, 1e-10),
            (GeoKind::Qua12, 1e-10),
            (GeoKind::Qua16, 1e-9),
            (GeoKind::Qua17, 1e-9),
            // Tet
            (GeoKind::Tet4, 1e-12),
            (GeoKind::Tet10, 1e-9),
            (GeoKind::Tet20, 1e-9),
            // Hex
            (GeoKind::Hex8, 1e-11),
            (GeoKind::Hex20, 1e-10),
            (GeoKind::Hex32, 1e-9),
        ];

        // loop over shapes
        for (kind, tol) in problem {
            // scratchpad with coordinates
            let geo_ndim = kind.ndim();
            let space_ndim = usize::max(2, geo_ndim);
            let mut pad = aux::gen_scratchpad_with_coords(space_ndim, kind);

            // set ξ within reference space
            let at_ksi = vec![ONE_BY_3; geo_ndim];

            // compute x corresponding to ξ using the isoparametric formula
            let mut at_x = Vector::new(space_ndim);
            pad.calc_coords(&mut at_x, &at_ksi).unwrap();

            // compute gradient
            let det_jac = pad.calc_gradient(&at_ksi).unwrap();
            assert!(det_jac > 0.0);

            // set arguments for numerical integration
            let args = &mut ArgsNumGrad {
                pad: pad.clone(),
                at_x,
                x: Vector::new(space_ndim),
                ksi: vec![0.0; geo_ndim],
                m: 0,
                j: 0,
            };

            // check Gᵐ(ξ(x)) = dNᵐ(ξ(x))/dx
            for m in 0..kind.nnode() {
                args.m = m;
                for j in 0..geo_ndim {
                    args.j = j;
                    // Gᵐⱼ := dNᵐ/dxⱼ
                    assert_deriv_approx_eq!(pad.gradient[m][j], args.at_x[j], nn_given_x, args, tol);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate scroll;
extern crate goblin;
use goblin::archive::*;
use scroll::Pread;
use std::path::Path;
use std::fs::File;

#[test]
fn parse_file_header() {
    let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38,
                                            0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x60, 0x0a];
    let buffer = &file_header[..];
    match buffer.pread::<MemberHeader>(0) {
        Err(_) => assert!(false),
        Ok(file_header2) => {
            let file_header = MemberHeader {
                identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,],
                timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32],
                owner_id: [48, 32, 32, 32, 32, 32],
                group_id: [48, 32, 32, 32, 32, 32],
                mode: [48, 32, 32, 32, 32, 32, 32, 32],
                file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32],
                terminator: [96, 10] };
            assert_eq!(file_header, file_header2)
        }
    }
}

#[test]
fn parse_archive() {
    let crt1a: Vec<u8> = include!("../etc/crt1a.rs");
    const START: &'static str = "_start";
    match Archive::parse(&crt1a) {
        Ok(archive) => {
            assert_eq!(archive.member_of_symbol(START), Some("crt1.o"));
            if let Some(member) = archive.get("crt1.o") {
                assert_eq!(member.offset, 194);
                assert_eq!(member.size(), 1928)
            } else {
                println!("could not get crt1.o");
                assert!(false)
            }
        },
        Err(err) => {println!("could not parse archive: {:?}", err); assert!(false)}
    };
}

#[test]
fn parse_self() {
    use std::io::Read;
    let path = Path::new("target").join("debug").join("libgoblin.rlib");
    let buffer = {
        let mut fd = File::open(path).expect("open file");
        let mut v = Vec::new();
        fd.read_to_end(&mut v).expect("read file");
        v
    };

    let archive = Archive::parse(&buffer).expect("parse rlib");

    // check that the archive has a useful symbol table by counting the total number of symbols
    let symbol_count = archive.summarize().into_iter()
        .map(|(_member_name, _member_index, ref symbols)| symbols.len())
        .fold(0, |sum,symbol_count| sum + symbol_count);
    assert!(symbol_count > 500);

    let goblin_object_name = archive.members()
        .into_iter()
        .filter(|member| {
            println!("member: {:?}", member);
            member.ends_with("goblin-archive.o")    // < 1.18
                || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18 && < 1.22
                || (member.starts_with("goblin") && member.ends_with("rust-cgu.o")) // = 1.22
                || (member.starts_with("goblin") && member.ends_with("rcgu.o")) // >= nightly 1.23
        })
        .next()
        .expect("goblin-<hash>.0.o not found");

    let bytes = archive.extract(goblin_object_name, &buffer).expect("extract goblin object");
    match goblin::Object::parse(&bytes).expect("parse object") {
        goblin::Object::Elf(elf) => {
            assert!(elf.entry == 0);
            assert!(elf.bias == 0);
        }
        goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
            assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT);
            assert_eq!(macho.entry, 0);
        }
        other => {
            println!("unexpected Object::parse result: {:?}", other);
            assert!(false);
        }
    }
}
<commit_msg>tests: use release directory if debug is missing. fixes #63<commit_after>extern crate scroll;
extern crate goblin;
use goblin::archive::*;
use scroll::Pread;
use std::path::Path;
use std::fs::File;

#[test]
fn parse_file_header() {
    let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
                                            0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
                                            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38,
                                            0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20,
                                            0x20, 0x20, 0x60, 0x0a];
    let buffer = &file_header[..];
    match buffer.pread::<MemberHeader>(0) {
        Err(_) => assert!(false),
        Ok(file_header2) => {
            let file_header = MemberHeader {
                identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,],
                timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32],
                owner_id: [48, 32, 32, 32, 32, 32],
                group_id: [48, 32, 32, 32, 32, 32],
                mode: [48, 32, 32, 32, 32, 32, 32, 32],
                file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32],
                terminator: [96, 10] };
            assert_eq!(file_header, file_header2)
        }
    }
}

#[test]
fn parse_archive() {
    let crt1a: Vec<u8> = include!("../etc/crt1a.rs");
    const START: &'static str = "_start";
    match Archive::parse(&crt1a) {
        Ok(archive) => {
            assert_eq!(archive.member_of_symbol(START), Some("crt1.o"));
            if let Some(member) = archive.get("crt1.o") {
                assert_eq!(member.offset, 194);
                assert_eq!(member.size(), 1928)
            } else {
                println!("could not get crt1.o");
                assert!(false)
            }
        },
        Err(err) => {println!("could not parse archive: {:?}", err); assert!(false)}
    };
}

#[test]
fn parse_self() {
    use std::fs;
    use std::io::Read;
    let mut path = Path::new("target").join("debug").join("libgoblin.rlib");
    // https://github.com/m4b/goblin/issues/63
    if !fs::metadata(&path).is_ok() {
        path = Path::new("target").join("release").join("libgoblin.rlib");
    }
    let buffer = {
        let mut fd = File::open(path).expect("open file");
        let mut v = Vec::new();
        fd.read_to_end(&mut v).expect("read file");
        v
    };

    let archive = Archive::parse(&buffer).expect("parse rlib");

    // check that the archive has a useful symbol table by counting the total number of symbols
    let symbol_count = archive.summarize().into_iter()
        .map(|(_member_name, _member_index, ref symbols)| symbols.len())
        .fold(0, |sum,symbol_count| sum + symbol_count);
    assert!(symbol_count > 500);

    let goblin_object_name = archive.members()
        .into_iter()
        .filter(|member| {
            println!("member: {:?}", member);
            member.ends_with("goblin-archive.o")    // < 1.18
                || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18 && < 1.22
                || (member.starts_with("goblin") && member.ends_with("rust-cgu.o")) // = 1.22
                || (member.starts_with("goblin") && member.ends_with("rcgu.o")) // >= nightly 1.23
        })
        .next()
        .expect("goblin-<hash>.0.o not found");

    let bytes = archive.extract(goblin_object_name, &buffer).expect("extract goblin object");
    match goblin::Object::parse(&bytes).expect("parse object") {
        goblin::Object::Elf(elf) => {
            assert!(elf.entry == 0);
            assert!(elf.bias == 0);
        }
        goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
            assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT);
            assert_eq!(macho.entry, 0);
        }
        other => {
            println!("unexpected Object::parse result: {:?}", other);
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>use either::Either;
use ide_db::syntax_helpers::node_ext::walk_ty;
use itertools::Itertools;
use syntax::{
    ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName},
    match_ast,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: extract_type_alias
//
// Extracts the selected type as a type alias.
//
// ```
// struct S {
//     field: $0(u8, u8, u8)$0,
// }
// ```
// ->
// ```
// type $0Type = (u8, u8, u8);
//
// struct S {
//     field: Type,
// }
// ```
pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    if ctx.has_empty_selection() {
        return None;
    }

    let ty = ctx.find_node_at_range::<ast::Type>()?;
    let item = ty.syntax().ancestors().find_map(ast::Item::cast)?;
    let assoc_owner = item.syntax().ancestors().nth(2).and_then(|it| {
        match_ast! {
            match it {
                ast::Trait(tr) => Some(Either::Left(tr)),
                ast::Impl(impl_) => Some(Either::Right(impl_)),
                _ => None,
            }
        }
    });
    let node = assoc_owner.as_ref().map_or_else(
        || item.syntax(),
        |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax),
    );
    let insert_pos = node.text_range().start();
    let target = ty.syntax().text_range();

    acc.add(
        AssistId("extract_type_alias", AssistKind::RefactorExtract),
        "Extract type as type alias",
        target,
        |builder| {
            let mut known_generics = match item.generic_param_list() {
                Some(it) => it.generic_params().collect(),
                None => Vec::new(),
            };
            if let Some(it) = assoc_owner.as_ref().and_then(|it| match it {
                Either::Left(it) => it.generic_param_list(),
                Either::Right(it) => it.generic_param_list(),
            }) {
                known_generics.extend(it.generic_params());
            }
            let generics = collect_used_generics(&ty, &known_generics);

            let replacement = if !generics.is_empty() {
                format!(
                    "Type<{}>",
                    generics.iter().format_with(", ", |generic, f| {
                        match generic {
                            ast::GenericParam::ConstParam(cp) => f(&cp.name().unwrap()),
                            ast::GenericParam::LifetimeParam(lp) => f(&lp.lifetime().unwrap()),
                            ast::GenericParam::TypeParam(tp) => f(&tp.name().unwrap()),
                        }
                    })
                )
            } else {
                String::from("Type")
            };
            builder.replace(target, replacement);

            let indent = IndentLevel::from_node(node);
            let generics = if !generics.is_empty() {
                format!("<{}>", generics.iter().format(", "))
            } else {
                String::new()
            };
            match ctx.config.snippet_cap {
                Some(cap) => {
                    builder.insert_snippet(
                        cap,
                        insert_pos,
                        format!("type $0Type{} = {};\n\n{}", generics, ty, indent),
                    );
                }
                None => {
                    builder.insert(
                        insert_pos,
                        format!("type Type{} = {};\n\n{}", generics, ty, indent),
                    );
                }
            }
        },
    )
}

fn collect_used_generics<'gp>(
    ty: &ast::Type,
    known_generics: &'gp [ast::GenericParam],
) -> Vec<&'gp ast::GenericParam> {
    // can't use a closure -> closure here cause lifetime inference fails for that
    fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
        move |gp: &&ast::GenericParam| match gp {
            ast::GenericParam::LifetimeParam(lp) => {
                lp.lifetime().map_or(false, |lt| lt.text() == text)
            }
            _ => false,
        }
    }

    let mut generics = Vec::new();
    walk_ty(ty, &mut |ty| match ty {
        ast::Type::PathType(ty) => {
            if let Some(path) = ty.path() {
                if let Some(name_ref) = path.as_single_name_ref() {
                    if let Some(param) = known_generics.iter().find(|gp| {
                        match gp {
                            ast::GenericParam::ConstParam(cp) => cp.name(),
                            ast::GenericParam::TypeParam(tp) => tp.name(),
                            _ => None,
                        }
                        .map_or(false, |n| n.text() == name_ref.text())
                    }) {
                        generics.push(param);
                    }
                }
                generics.extend(
                    path.segments()
                        .filter_map(|seg| seg.generic_arg_list())
                        .flat_map(|it| it.generic_args())
                        .filter_map(|it| match it {
                            ast::GenericArg::LifetimeArg(lt) => {
                                let lt = lt.lifetime()?;
                                known_generics.iter().find(find_lifetime(&lt.text()))
                            }
                            _ => None,
                        }),
                );
            }
        }
        ast::Type::ImplTraitType(impl_ty) => {
            if let Some(it) = impl_ty.type_bound_list() {
                generics.extend(
                    it.bounds()
                        .filter_map(|it| it.lifetime())
                        .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
                );
            }
        }
        ast::Type::DynTraitType(dyn_ty) => {
            if let Some(it) = dyn_ty.type_bound_list() {
                generics.extend(
                    it.bounds()
                        .filter_map(|it| it.lifetime())
                        .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
                );
            }
        }
        ast::Type::RefType(ref_) => generics.extend(
            ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
        ),
        _ => (),
    });
    // stable resort to lifetime, type, const
    generics.sort_by_key(|gp| match gp {
        ast::GenericParam::ConstParam(_) => 2,
        ast::GenericParam::LifetimeParam(_) => 0,
        ast::GenericParam::TypeParam(_) => 1,
    });
    generics
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn test_not_applicable_without_selection() {
        check_assist_not_applicable(
            extract_type_alias,
            r"
struct S {
    field: $0(u8, u8, u8),
}
            ",
        );
    }

    #[test]
    fn test_simple_types() {
        check_assist(
            extract_type_alias,
            r"
struct S {
    field: $0u8$0,
}
            ",
            r#"
type $0Type = u8;

struct S {
    field: Type,
}
            "#,
        );
    }

    #[test]
    fn test_generic_type_arg() {
        check_assist(
            extract_type_alias,
            r"
fn generic<T>() {}

fn f() {
    generic::<$0()$0>();
}
            ",
            r#"
fn generic<T>() {}

type $0Type = ();

fn f() {
    generic::<Type>();
}
            "#,
        );
    }

    #[test]
    fn test_inner_type_arg() {
        check_assist(
            extract_type_alias,
            r"
struct Vec<T> {}
struct S {
    v: Vec<Vec<$0Vec<u8>$0>>,
}
            ",
            r#"
struct Vec<T> {}
type $0Type = Vec<u8>;

struct S {
    v: Vec<Vec<Type>>,
}
            "#,
        );
    }

    #[test]
    fn test_extract_inner_type() {
        check_assist(
            extract_type_alias,
            r"
struct S {
    field: ($0u8$0,),
}
            ",
            r#"
type $0Type = u8;

struct S {
    field: (Type,),
}
            "#,
        );
    }

    #[test]
    fn extract_from_impl_or_trait() {
        // When invoked in an impl/trait, extracted type alias should be placed next to the
        // impl/trait, not inside.
        check_assist(
            extract_type_alias,
            r#"
impl S {
    fn f() -> $0(u8, u8)$0 {}
}
            "#,
            r#"
type $0Type = (u8, u8);

impl S {
    fn f() -> Type {}
}
            "#,
        );
        check_assist(
            extract_type_alias,
            r#"
trait Tr {
    fn f() -> $0(u8, u8)$0 {}
}
            "#,
            r#"
type $0Type = (u8, u8);

trait Tr {
    fn f() -> Type {}
}
            "#,
        );
    }

    #[test]
    fn indentation() {
        check_assist(
            extract_type_alias,
            r#"
mod m {
    fn f() -> $0u8$0 {}
}
            "#,
            r#"
mod m {
    type $0Type = u8;

    fn f() -> Type {}
}
            "#,
        );
    }

    #[test]
    fn generics() {
        check_assist(
            extract_type_alias,
            r#"
struct Struct<const C: usize>;
impl<'outer, Outer, const OUTER: usize> () {
    fn func<'inner, Inner, const INNER: usize>(_: $0&(Struct<INNER>, Struct<OUTER>, Outer, &'inner (), Inner, &'outer ())$0) {}
}
"#,
            r#"
struct Struct<const C: usize>;
type $0Type<'inner, 'outer, Outer, Inner, const INNER: usize, const OUTER: usize> = &(Struct<INNER>, Struct<OUTER>, Outer, &'inner (), Inner, &'outer ());

impl<'outer, Outer, const OUTER: usize> () {
    fn func<'inner, Inner, const INNER: usize>(_: Type<'inner, 'outer, Outer, Inner, INNER, OUTER>) {}
}
"#,
        );
    }

    #[test]
    fn issue_11197 () {
        check_assist(extract_type_alias,
            r#"
struct Foo<T, const N: usize>
where
    [T; N]: Sized,
{
    arr: $0[T; N]$0,
}
            "#,
            r#"
type $0Type<T, const N: usize> = [T; N];

struct Foo<T, const N: usize>
where
    [T; N]: Sized,
{
    arr: Type<T, N>,
}
            "#);
    }
}
<commit_msg>extract const generic in ArrayType<commit_after>use either::Either;
use ide_db::syntax_helpers::node_ext::walk_ty;
use itertools::Itertools;
use syntax::{
    ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName},
    match_ast,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: extract_type_alias
//
// Extracts the selected type as a type alias.
//
// ```
// struct S {
//     field: $0(u8, u8, u8)$0,
// }
// ```
// ->
// ```
// type $0Type = (u8, u8, u8);
//
// struct S {
//     field: Type,
// }
// ```
pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    if ctx.has_empty_selection() {
        return None;
    }

    let ty = ctx.find_node_at_range::<ast::Type>()?;
    let item = ty.syntax().ancestors().find_map(ast::Item::cast)?;
    let assoc_owner = item.syntax().ancestors().nth(2).and_then(|it| {
        match_ast! {
            match it {
                ast::Trait(tr) => Some(Either::Left(tr)),
                ast::Impl(impl_) => Some(Either::Right(impl_)),
                _ => None,
            }
        }
    });
    let node = assoc_owner.as_ref().map_or_else(
        || item.syntax(),
        |impl_| impl_.as_ref().either(AstNode::syntax, AstNode::syntax),
    );
    let insert_pos = node.text_range().start();
    let target = ty.syntax().text_range();

    acc.add(
        AssistId("extract_type_alias", AssistKind::RefactorExtract),
        "Extract type as type alias",
        target,
        |builder| {
            let mut known_generics = match item.generic_param_list() {
                Some(it) => it.generic_params().collect(),
                None => Vec::new(),
            };
            if let Some(it) = assoc_owner.as_ref().and_then(|it| match it {
                Either::Left(it) => it.generic_param_list(),
                Either::Right(it) => it.generic_param_list(),
            }) {
                known_generics.extend(it.generic_params());
            }
            let generics = collect_used_generics(&ty, &known_generics);

            let replacement = if !generics.is_empty() {
                format!(
                    "Type<{}>",
                    generics.iter().format_with(", ", |generic, f| {
                        match generic {
                            ast::GenericParam::ConstParam(cp) => f(&cp.name().unwrap()),
                            ast::GenericParam::LifetimeParam(lp) => f(&lp.lifetime().unwrap()),
                            ast::GenericParam::TypeParam(tp) => f(&tp.name().unwrap()),
                        }
                    })
                )
            } else {
                String::from("Type")
            };
            builder.replace(target, replacement);

            let indent = IndentLevel::from_node(node);
            let generics = if !generics.is_empty() {
                format!("<{}>", generics.iter().format(", "))
            } else {
                String::new()
            };
            match ctx.config.snippet_cap {
                Some(cap) => {
                    builder.insert_snippet(
                        cap,
                        insert_pos,
                        format!("type $0Type{} = {};\n\n{}", generics, ty, indent),
                    );
                }
                None => {
                    builder.insert(
                        insert_pos,
                        format!("type Type{} = {};\n\n{}", generics, ty, indent),
                    );
                }
            }
        },
    )
}

fn collect_used_generics<'gp>(
    ty: &ast::Type,
    known_generics: &'gp [ast::GenericParam],
) -> Vec<&'gp ast::GenericParam> {
    // can't use a closure -> closure here cause lifetime inference fails for that
    fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
        move |gp: &&ast::GenericParam| match gp {
            ast::GenericParam::LifetimeParam(lp) => {
                lp.lifetime().map_or(false, |lt| lt.text() == text)
            }
            _ => false,
        }
    }

    let mut generics = Vec::new();
    walk_ty(ty, &mut |ty| match ty {
        ast::Type::PathType(ty) => {
            if let Some(path) = ty.path() {
                if let Some(name_ref) = path.as_single_name_ref() {
                    if let Some(param) = known_generics.iter().find(|gp| {
                        match gp {
                            ast::GenericParam::ConstParam(cp) => cp.name(),
                            ast::GenericParam::TypeParam(tp) => tp.name(),
                            _ => None,
                        }
                        .map_or(false, |n| n.text() == name_ref.text())
                    }) {
                        generics.push(param);
                    }
                }
                generics.extend(
                    path.segments()
                        .filter_map(|seg| seg.generic_arg_list())
                        .flat_map(|it| it.generic_args())
                        .filter_map(|it| match it {
                            ast::GenericArg::LifetimeArg(lt) => {
                                let lt = lt.lifetime()?;
                                known_generics.iter().find(find_lifetime(&lt.text()))
                            }
                            _ => None,
                        }),
                );
            }
        }
        ast::Type::ImplTraitType(impl_ty) => {
            if let Some(it) = impl_ty.type_bound_list() {
                generics.extend(
                    it.bounds()
                        .filter_map(|it| it.lifetime())
                        .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
                );
            }
        }
        ast::Type::DynTraitType(dyn_ty) => {
            if let Some(it) = dyn_ty.type_bound_list() {
                generics.extend(
                    it.bounds()
                        .filter_map(|it| it.lifetime())
                        .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
                );
            }
        }
        ast::Type::RefType(ref_) => generics.extend(
            ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
        ),
        ast::Type::ArrayType(ar) => {
            if let Some(expr) = ar.expr() {
                if let ast::Expr::PathExpr(p) = expr {
                    if let Some(path) = p.path() {
                        if let Some(name_ref) = path.as_single_name_ref() {
                            if let Some(param) = known_generics.iter().find(|gp| {
                                if let ast::GenericParam::ConstParam(cp) = gp {
                                    cp.name().map_or(false, |n| n.text() == name_ref.text())
                                } else {
                                    false
                                }
                            }) {
                                generics.push(param);
                            }
                        }
                    }
                }
            }
        },
        _ => (),
    });
    // stable resort to lifetime, type, const
    generics.sort_by_key(|gp| match gp {
        ast::GenericParam::ConstParam(_) => 2,
        ast::GenericParam::LifetimeParam(_) => 0,
        ast::GenericParam::TypeParam(_) => 1,
    });
    generics
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn test_not_applicable_without_selection() {
        check_assist_not_applicable(
            extract_type_alias,
            r"
struct S {
    field: $0(u8, u8, u8),
}
            ",
        );
    }

    #[test]
    fn test_simple_types() {
        check_assist(
            extract_type_alias,
            r"
struct S {
    field: $0u8$0,
}
            ",
            r#"
type $0Type = u8;

struct S {
    field: Type,
}
            "#,
        );
    }

    #[test]
    fn test_generic_type_arg() {
        check_assist(
            extract_type_alias,
            r"
fn generic<T>() {}

fn f() {
    generic::<$0()$0>();
}
            ",
            r#"
fn generic<T>() {}

type $0Type = ();

fn f() {
    generic::<Type>();
}
            "#,
        );
    }

    #[test]
    fn test_inner_type_arg() {
        check_assist(
            extract_type_alias,
            r"
struct Vec<T> {}
struct S {
    v: Vec<Vec<$0Vec<u8>$0>>,
}
            ",
            r#"
struct Vec<T> {}
type $0Type = Vec<u8>;

struct S {
    v: Vec<Vec<Type>>,
}
            "#,
        );
    }

    #[test]
    fn test_extract_inner_type() {
        check_assist(
            extract_type_alias,
            r"
struct S {
    field: ($0u8$0,),
}
            ",
            r#"
type $0Type = u8;

struct S {
    field: (Type,),
}
            "#,
        );
    }

    #[test]
    fn extract_from_impl_or_trait() {
        // When invoked in an impl/trait, extracted type alias should be placed next to the
        // impl/trait, not inside.
        check_assist(
            extract_type_alias,
            r#"
impl S {
    fn f() -> $0(u8, u8)$0 {}
}
            "#,
            r#"
type $0Type = (u8, u8);

impl S {
    fn f() -> Type {}
}
            "#,
        );
        check_assist(
            extract_type_alias,
            r#"
trait Tr {
    fn f() -> $0(u8, u8)$0 {}
}
            "#,
            r#"
type $0Type = (u8, u8);

trait Tr {
    fn f() -> Type {}
}
            "#,
        );
    }

    #[test]
    fn indentation() {
        check_assist(
            extract_type_alias,
            r#"
mod m {
    fn f() -> $0u8$0 {}
}
            "#,
            r#"
mod m {
    type $0Type = u8;

    fn f() -> Type {}
}
            "#,
        );
    }

    #[test]
    fn generics() {
        check_assist(
            extract_type_alias,
            r#"
struct Struct<const C: usize>;
impl<'outer, Outer, const OUTER: usize> () {
    fn func<'inner, Inner, const INNER: usize>(_: $0&(Struct<INNER>, Struct<OUTER>, Outer, &'inner (), Inner, &'outer ())$0) {}
}
"#,
            r#"
struct Struct<const C: usize>;
type $0Type<'inner, 'outer, Outer, Inner, const INNER: usize, const OUTER: usize> = &(Struct<INNER>, Struct<OUTER>, Outer, &'inner (), Inner, &'outer ());

impl<'outer, Outer, const OUTER: usize> () {
    fn func<'inner, Inner, const INNER: usize>(_: Type<'inner, 'outer, Outer, Inner, INNER, OUTER>) {}
}
"#,
        );
    }

    #[test]
    fn issue_11197 () {
        check_assist(extract_type_alias,
            r#"
struct Foo<T, const N: usize>
where
    [T; N]: Sized,
{
    arr: $0[T; N]$0,
}
            "#,
            r#"
type $0Type<T, const N: usize> = [T; N];

struct Foo<T, const N: usize>
where
    [T; N]: Sized,
{
    arr: Type<T, N>,
}
            "#);
    }
}
<|endoftext|>


<commit_before><commit_msg>refactor: cargo format ./tests<commit_after><|endoftext|>


<commit_before>extern crate bnf;

use bnf::Grammar;

#[test]
fn validate_terminated_display() {
    let input = "<postal-address> ::= <name-part> <street-address> <zip-part>;

            <name-part> ::= <personal-part> <last-name> <opt-suffix-part> <EOL>
                            | <personal-part> <name-part>;

        <personal-part> ::= <initial> \".\" | <first-name>;

        <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>;

            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>;

        <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\";
            <opt-apt-num> ::= <apt-num> | \"\";";

    let display_output = "<postal-address> ::= <name-part> <street-address> <zip-part>\n\
                            <name-part> ::= <personal-part> <last-name> \
                            <opt-suffix-part> <EOL> | <personal-part> <name-part>\n\
                            <personal-part> ::= <initial> \".\" | <first-name>\n\
                            <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>\n\
                            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>\n\
                            <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\"\n\
                            <opt-apt-num> ::= <apt-num> | \"\"\n";

    let grammar = Grammar::from_str(input).unwrap();

    assert_eq!(grammar.to_string(), display_output);
}

#[test]
fn validate_nonterminated_display() {
    let input = "<postal-address> ::= <name-part> <street-address> <zip-part>

            <name-part> ::= <personal-part> <last-name> <opt-suffix-part> <EOL>
                            | <personal-part> <name-part>

        <personal-part> ::= <initial> \".\" | <first-name>

        <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>

            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>

        <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\"
            <opt-apt-num> ::= <apt-num> | \"\"";

    let display_output = "<postal-address> ::= <name-part> <street-address> <zip-part>\n\
                            <name-part> ::= <personal-part> <last-name> \
                            <opt-suffix-part> <EOL> | <personal-part> <name-part>\n\
                            <personal-part> ::= <initial> \".\" | <first-name>\n\
                            <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>\n\
                            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>\n\
                            <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\"\n\
                            <opt-apt-num> ::= <apt-num> | \"\"\n";

    let grammar = Grammar::from_str(input).unwrap();

    assert_eq!(grammar.to_string(), display_output);
}
<commit_msg>Add display test using quotes<commit_after>extern crate bnf;

use bnf::Grammar;

#[test]
fn validate_terminated_display() {
    let input = "<postal-address> ::= <name-part> <street-address> <zip-part>;

            <name-part> ::= <personal-part> <last-name> <opt-suffix-part> <EOL>
                            | <personal-part> <name-part>;

        <personal-part> ::= <initial> \".\" | <first-name>;

        <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>;

            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>;

        <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\";
            <opt-apt-num> ::= <apt-num> | \"\";";

    let display_output = "<postal-address> ::= <name-part> <street-address> <zip-part>\n\
                            <name-part> ::= <personal-part> <last-name> \
                            <opt-suffix-part> <EOL> | <personal-part> <name-part>\n\
                            <personal-part> ::= <initial> \".\" | <first-name>\n\
                            <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>\n\
                            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>\n\
                            <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\"\n\
                            <opt-apt-num> ::= <apt-num> | \"\"\n";

    let grammar = Grammar::from_str(input).unwrap();

    assert_eq!(grammar.to_string(), display_output);
}

#[test]
fn validate_nonterminated_display() {
    let input = "<postal-address> ::= <name-part> <street-address> <zip-part>

            <name-part> ::= <personal-part> <last-name> <opt-suffix-part> <EOL>
                            | <personal-part> <name-part>

        <personal-part> ::= <initial> \".\" | <first-name>

        <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>

            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>

        <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\"
            <opt-apt-num> ::= <apt-num> | \"\"";

    let display_output = "<postal-address> ::= <name-part> <street-address> <zip-part>\n\
                            <name-part> ::= <personal-part> <last-name> \
                            <opt-suffix-part> <EOL> | <personal-part> <name-part>\n\
                            <personal-part> ::= <initial> \".\" | <first-name>\n\
                            <street-address> ::= <house-num> <street-name> <opt-apt-num> <EOL>\n\
                            <zip-part> ::= <town-name> \",\" <state-code> <ZIP-code> <EOL>\n\
                            <opt-suffix-part> ::= \"Sr.\" | \"Jr.\" | <roman-numeral> | \"\"\n\
                            <opt-apt-num> ::= <apt-num> | \"\"\n";

    let grammar = Grammar::from_str(input).unwrap();

    assert_eq!(grammar.to_string(), display_output);
}

#[test]
fn grammar_with_quotes() {
    let input = "
        <permissive-string-definition>
            ::= <single-quote> <message> <single-quote>
            | <double-quote> <messag> <double-quote>

        <double-quote>
            ::= '\"'

        <single-quote>
            ::= \"'\"

        <message>
            ::= \"Hello, world!\"
    ";

    let display_output = "\
        <permissive-string-definition> \
            ::= <single-quote> <message> <single-quote> \
            | <double-quote> <messag> <double-quote>\n\
        <double-quote> \
            ::= \'\"\'\n\
        <single-quote> \
            ::= \"\'\"\n\
        <message> \
            ::= \"Hello, world!\"\n\
    ";

    let grammar = Grammar::from_str(input).expect("Grammar with quotes should parse");
    assert_eq!(grammar.to_string(), display_output);
}
<|endoftext|>