<commit_before>//! Provides functions for maintaining database schema.
//!
//! A database migration always provides procedures to update the schema, as well as to revert
//! itself. Diesel's migrations are versioned, and run in order. Diesel also takes care of tracking
//! which migrations have already been run automatically. Your migrations don't need to be
//! idempotent, as Diesel will ensure no migration is run twice unless it has been reverted.
//!
//! Migrations should be placed in a `/migrations` directory at the root of your project (the same
//! directory as `Cargo.toml`). When any of these functions are run, Diesel will search for the
//! migrations directory in the current directory and its parents, stopping when it finds the
//! directory containing `Cargo.toml`.
//!
//! Individual migrations should be a folder containing exactly two files, `up.sql` and `down.sql`.
//! `up.sql` will be used to run the migration, while `down.sql` will be used for reverting it. The
//! folder itself should have the structure `{version}_{migration_name}`. It is recommended that
//! you use the timestamp of creation for the version.
//!
//! ## Example
//!
//! ```text
//! # Directory Structure
//! - 20151219180527_create_users
//!     - up.sql
//!     - down.sql
//! - 20160107082941_create_posts
//!     - up.sql
//!     - down.sql
//! ```
//!
//! ```sql
//! -- 20151219180527_create_users/up.sql
//! CREATE TABLE users (
//!   id SERIAL PRIMARY KEY,
//!   name VARCHAR NOT NULL,
//!   hair_color VARCHAR
//! );
//! ```
//!
//! ```sql
//! -- 20151219180527_create_users/down.sql
//! DROP TABLE users;
//! ```
//!
//! ```sql
//! -- 20160107082941_create_posts/up.sql
//! CREATE TABLE posts (
//!   id SERIAL PRIMARY KEY,
//!   user_id INTEGER NOT NULL,
//!   title VARCHAR NOT NULL,
//!   body TEXT
//! );
//! ```
//!
//! ```sql
//! -- 20160107082941_create_posts/down.sql
//! DROP TABLE posts;
//! ```
mod migration;
#[doc(hidden)]
pub mod connection;
mod migration_error;
#[doc(hidden)]
pub mod schema;

#[doc(inline)]
pub use self::connection::MigrationConnection;
#[doc(inline)]
pub use self::migration::*;
pub use self::migration_error::*;

use std::fs::DirEntry;
use std::io::{stdout, Write};

use expression::expression_methods::*;
use query_dsl::*;
use self::schema::__diesel_schema_migrations::dsl::*;
use {Connection, QueryResult};

use std::env;
use std::path::{PathBuf, Path};

pub static TIMESTAMP_FORMAT: &'static str ="%Y%m%d%H%M%S";

/// Runs all migrations that have not yet been run. This function will print all progress to
/// stdout. This function will return an `Err` if some error occurs reading the migrations, or if
/// any migration fails to run. Each migration is run in its own transaction, so some migrations
/// may be committed, even if a later migration fails to run.
///
/// It should be noted that this runs all migrations that have not already been run, regardless of
/// whether or not their version is later than the latest run migration. This is generally not a
/// problem, and eases the more common case of two developers generating independent migrations on
/// a branch. Whoever created the second one will eventually need to run the first when both
/// branches are merged.
///
/// See the [module level documentation](index.html) for information on how migrations should be
/// structured, and where Diesel will look for them by default.
pub fn run_pending_migrations<Conn>(conn: &Conn) -> Result<(), RunMigrationsError> where
    Conn: MigrationConnection,
{
    let migrations_dir = try!(find_migrations_directory());
    run_pending_migrations_in_directory(conn, &migrations_dir, &mut stdout())
}

#[doc(hidden)]
pub fn run_pending_migrations_in_directory<Conn>(conn: &Conn, migrations_dir: &Path, output: &mut Write)
    -> Result<(), RunMigrationsError> where
        Conn: MigrationConnection,
{
    let all_migrations = try!(migrations_in_directory(migrations_dir));
    run_migrations(conn, all_migrations, output)
}

/// Compares migrations found in `migrations_dir` to those that have been applied.
/// Returns a list of pathbufs and whether they have been applied.
pub fn mark_migrations_in_directory<Conn>(conn: &Conn, migrations_dir: &Path)
    -> Result<Vec<(Option<PathBuf>, bool)>, RunMigrationsError> where
        Conn: MigrationConnection,
{
    let migrations = migrations_in_directory(migrations_dir)?;
    setup_database(conn)?;
    let already_run = conn.previously_run_migration_versions()?;
    let migrations = migrations.into_iter().map(|m| {
        let applied = already_run.contains(&m.version().to_string());
        (m.file_path().map(|p| p.to_path_buf()), applied)
    }).collect();
    Ok(migrations)
}

/// Reverts the last migration that was run. Returns the version that was reverted. Returns an
/// `Err` if no migrations have ever been run.
///
/// See the [module level documentation](index.html) for information on how migrations should be
/// structured, and where Diesel will look for them by default.
pub fn revert_latest_migration<Conn>(conn: &Conn) -> Result<String, RunMigrationsError> where
    Conn: MigrationConnection,
{
    try!(setup_database(conn));
    let latest_migration_version = conn.latest_run_migration_version()?
        .ok_or_else(|| RunMigrationsError::MigrationError(MigrationError::NoMigrationRun))?;
    revert_migration_with_version(conn, &latest_migration_version, &mut stdout())
        .map(|_| latest_migration_version)
}

#[doc(hidden)]
pub fn revert_migration_with_version<Conn: Connection>(conn: &Conn, ver: &str, output: &mut Write)
    -> Result<(), RunMigrationsError>
{
    migration_with_version(ver)
        .map_err(|e| e.into())
        .and_then(|m| revert_migration(conn, m, output))
}

#[doc(hidden)]
pub fn run_migration_with_version<Conn>(conn: &Conn, ver: &str, output: &mut Write)
    -> Result<(), RunMigrationsError> where
        Conn: MigrationConnection,
{
    migration_with_version(ver)
        .map_err(|e| e.into())
        .and_then(|m| run_migration(conn, &*m, output))
}

fn migration_with_version(ver: &str) -> Result<Box<Migration>, MigrationError> {
    let migrations_dir = try!(find_migrations_directory());
    let all_migrations = try!(migrations_in_directory(&migrations_dir));
    let migration = all_migrations.into_iter().find(|m| {
        m.version() == ver
    });
    match migration {
        Some(m) => Ok(m),
        None => Err(MigrationError::UnknownMigrationVersion(ver.into())),
    }
}

#[doc(hidden)]
pub fn setup_database<Conn: Connection>(conn: &Conn) -> QueryResult<usize> {
    conn.setup_helper_functions();
    create_schema_migrations_table_if_needed(conn)
}

fn create_schema_migrations_table_if_needed<Conn: Connection>(conn: &Conn) -> QueryResult<usize> {
    conn.silence_notices(|| {
        conn.execute("CREATE TABLE IF NOT EXISTS __diesel_schema_migrations (
            version VARCHAR(50) PRIMARY KEY NOT NULL,
            run_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
        )")
    })
}

#[doc(hidden)]
pub fn migration_paths_in_directory(path: &Path) -> Result<Vec<DirEntry>, MigrationError> {
    try!(path.read_dir())
        .filter_map(|entry| {
            let entry = match entry {
                Ok(e) => e,
                Err(e) => return Some(Err(e.into())),
            };
            if entry.file_name().to_string_lossy().starts_with('.') {
                None
            } else {
                Some(Ok(entry))
            }
        }).collect()
}

fn migrations_in_directory(path: &Path) -> Result<Vec<Box<Migration>>, MigrationError> {
    use self::migration::migration_from;

    try!(migration_paths_in_directory(path)).iter().map(|e| {
        migration_from(e.path())
    }).collect()
}

/// Run all pending migrations in the given list. Apps should likely be calling
/// `run_pending_migrations` or `run_pending_migrations_in_directory` instead.
pub fn run_migrations<Conn, List>(
    conn: &Conn,
    migrations: List,
    output: &mut Write,
) -> Result<(), RunMigrationsError> where
    Conn: MigrationConnection,
    List: IntoIterator,
    List::Item: Migration,
{
    try!(setup_database(conn));
    let already_run = try!(conn.previously_run_migration_versions());
    let mut pending_migrations: Vec<_> = migrations.into_iter()
        .filter(|m| {
            !already_run.contains(&m.version().to_string())
        }).collect();

    pending_migrations.sort_by(|a, b| a.version().cmp(b.version()));
    for migration in pending_migrations {
        try!(run_migration(conn, &migration, output));
    }
    Ok(())
}

fn run_migration<Conn>(conn: &Conn, migration: &Migration, output: &mut Write)
    -> Result<(), RunMigrationsError> where
        Conn: MigrationConnection,
{
    conn.transaction(|| {
        try!(writeln!(output, "Running migration {}", migration.version()));
        try!(migration.run(conn));
        try!(conn.insert_new_migration(migration.version()));
        Ok(())
    })
}

fn revert_migration<Conn: Connection>(conn: &Conn, migration: Box<Migration>, output: &mut Write)
    -> Result<(), RunMigrationsError>
{
    conn.transaction(|| {
        try!(writeln!(output, "Rolling back migration {}", migration.version()));
        try!(migration.revert(conn));
        let target = __diesel_schema_migrations.filter(version.eq(migration.version()));
        try!(::delete(target).execute(conn));
        Ok(())
    })
}

/// Returns the directory containing migrations. Will look at for
/// $PWD/migrations. If it is not found, it will search the parents of the
/// current directory, until it reaches the root directory.  Returns
/// `MigrationError::MigrationDirectoryNotFound` if no directory is found.
pub fn find_migrations_directory() -> Result<PathBuf, MigrationError> {
    search_for_migrations_directory(&try!(env::current_dir()))
}

/// Searches for the migrations directory relative to the given path. See
/// `find_migrations_directory` for more details.
pub fn search_for_migrations_directory(path: &Path) -> Result<PathBuf, MigrationError> {
    let migration_path = path.join("migrations");
    if migration_path.is_dir() {
        Ok(migration_path)
    } else {
        path.parent().map(search_for_migrations_directory)
            .unwrap_or(Err(MigrationError::MigrationDirectoryNotFound))
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::*;

    use self::tempdir::TempDir;
    use std::fs;

    #[test]
    fn migration_directory_not_found_if_no_migration_dir_exists() {
        let dir = TempDir::new("diesel").unwrap();

        assert_eq!(Err(MigrationError::MigrationDirectoryNotFound),
            search_for_migrations_directory(dir.path()));
    }

    #[test]
    fn migration_directory_defaults_to_pwd_slash_migrations() {
        let dir = TempDir::new("diesel").unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");

        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(Ok(migrations_path), search_for_migrations_directory(&temp_path));
    }

    #[test]
    fn migration_directory_checks_parents() {
        let dir = TempDir::new("diesel").unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let child_path = temp_path.join("child");

        fs::create_dir(&child_path).unwrap();
        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(Ok(migrations_path), search_for_migrations_directory(&child_path));
    }
}
<commit_msg>Add function to check for pending migrations<commit_after>//! Provides functions for maintaining database schema.
//!
//! A database migration always provides procedures to update the schema, as well as to revert
//! itself. Diesel's migrations are versioned, and run in order. Diesel also takes care of tracking
//! which migrations have already been run automatically. Your migrations don't need to be
//! idempotent, as Diesel will ensure no migration is run twice unless it has been reverted.
//!
//! Migrations should be placed in a `/migrations` directory at the root of your project (the same
//! directory as `Cargo.toml`). When any of these functions are run, Diesel will search for the
//! migrations directory in the current directory and its parents, stopping when it finds the
//! directory containing `Cargo.toml`.
//!
//! Individual migrations should be a folder containing exactly two files, `up.sql` and `down.sql`.
//! `up.sql` will be used to run the migration, while `down.sql` will be used for reverting it. The
//! folder itself should have the structure `{version}_{migration_name}`. It is recommended that
//! you use the timestamp of creation for the version.
//!
//! ## Example
//!
//! ```text
//! # Directory Structure
//! - 20151219180527_create_users
//!     - up.sql
//!     - down.sql
//! - 20160107082941_create_posts
//!     - up.sql
//!     - down.sql
//! ```
//!
//! ```sql
//! -- 20151219180527_create_users/up.sql
//! CREATE TABLE users (
//!   id SERIAL PRIMARY KEY,
//!   name VARCHAR NOT NULL,
//!   hair_color VARCHAR
//! );
//! ```
//!
//! ```sql
//! -- 20151219180527_create_users/down.sql
//! DROP TABLE users;
//! ```
//!
//! ```sql
//! -- 20160107082941_create_posts/up.sql
//! CREATE TABLE posts (
//!   id SERIAL PRIMARY KEY,
//!   user_id INTEGER NOT NULL,
//!   title VARCHAR NOT NULL,
//!   body TEXT
//! );
//! ```
//!
//! ```sql
//! -- 20160107082941_create_posts/down.sql
//! DROP TABLE posts;
//! ```
mod migration;
#[doc(hidden)]
pub mod connection;
mod migration_error;
#[doc(hidden)]
pub mod schema;

#[doc(inline)]
pub use self::connection::MigrationConnection;
#[doc(inline)]
pub use self::migration::*;
pub use self::migration_error::*;

use std::fs::DirEntry;
use std::io::{stdout, Write};

use expression::expression_methods::*;
use query_dsl::*;
use self::schema::__diesel_schema_migrations::dsl::*;
use {Connection, QueryResult};

use std::env;
use std::path::{PathBuf, Path};

pub static TIMESTAMP_FORMAT: &'static str ="%Y%m%d%H%M%S";

/// Runs all migrations that have not yet been run. This function will print all progress to
/// stdout. This function will return an `Err` if some error occurs reading the migrations, or if
/// any migration fails to run. Each migration is run in its own transaction, so some migrations
/// may be committed, even if a later migration fails to run.
///
/// It should be noted that this runs all migrations that have not already been run, regardless of
/// whether or not their version is later than the latest run migration. This is generally not a
/// problem, and eases the more common case of two developers generating independent migrations on
/// a branch. Whoever created the second one will eventually need to run the first when both
/// branches are merged.
///
/// See the [module level documentation](index.html) for information on how migrations should be
/// structured, and where Diesel will look for them by default.
pub fn run_pending_migrations<Conn>(conn: &Conn) -> Result<(), RunMigrationsError> where
    Conn: MigrationConnection,
{
    let migrations_dir = try!(find_migrations_directory());
    run_pending_migrations_in_directory(conn, &migrations_dir, &mut stdout())
}

#[doc(hidden)]
pub fn run_pending_migrations_in_directory<Conn>(conn: &Conn, migrations_dir: &Path, output: &mut Write)
    -> Result<(), RunMigrationsError> where
        Conn: MigrationConnection,
{
    let all_migrations = try!(migrations_in_directory(migrations_dir));
    run_migrations(conn, all_migrations, output)
}

/// Compares migrations found in `migrations_dir` to those that have been applied.
/// Returns a list of pathbufs and whether they have been applied.
pub fn mark_migrations_in_directory<Conn>(conn: &Conn, migrations_dir: &Path)
    -> Result<Vec<(Option<PathBuf>, bool)>, RunMigrationsError> where
        Conn: MigrationConnection,
{
    let migrations = migrations_in_directory(migrations_dir)?;
    setup_database(conn)?;
    let already_run = conn.previously_run_migration_versions()?;
    let migrations = migrations.into_iter().map(|m| {
        let applied = already_run.contains(&m.version().to_string());
        (m.file_path().map(|p| p.to_path_buf()), applied)
    }).collect();
    Ok(migrations)
}

// Returns true if there are outstanding migrations in the migrations directory, otherwise
// returns false. Returns an `Err` if there are problems with migration setup.
///
/// See the [module level documentation](index.html) for information on how migrations should be
/// structured, and where Diesel will look for them by default.
pub fn any_pending_migrations<Conn>(conn: &Conn) -> Result<bool, RunMigrationsError> where
    Conn: MigrationConnection
{
    let migrations_dir = find_migrations_directory()?;
    let all_migrations = migrations_in_directory(&migrations_dir)?;
    let already_run = conn.previously_run_migration_versions()?;

    let pending = all_migrations.into_iter()
        .any(|m| !already_run.contains(&m.version().to_string()));

    Ok(pending)
}

/// Reverts the last migration that was run. Returns the version that was reverted. Returns an
/// `Err` if no migrations have ever been run.
///
/// See the [module level documentation](index.html) for information on how migrations should be
/// structured, and where Diesel will look for them by default.
pub fn revert_latest_migration<Conn>(conn: &Conn) -> Result<String, RunMigrationsError> where
    Conn: MigrationConnection,
{
    try!(setup_database(conn));
    let latest_migration_version = conn.latest_run_migration_version()?
        .ok_or_else(|| RunMigrationsError::MigrationError(MigrationError::NoMigrationRun))?;
    revert_migration_with_version(conn, &latest_migration_version, &mut stdout())
        .map(|_| latest_migration_version)
}

#[doc(hidden)]
pub fn revert_migration_with_version<Conn: Connection>(conn: &Conn, ver: &str, output: &mut Write)
    -> Result<(), RunMigrationsError>
{
    migration_with_version(ver)
        .map_err(|e| e.into())
        .and_then(|m| revert_migration(conn, m, output))
}

#[doc(hidden)]
pub fn run_migration_with_version<Conn>(conn: &Conn, ver: &str, output: &mut Write)
    -> Result<(), RunMigrationsError> where
        Conn: MigrationConnection,
{
    migration_with_version(ver)
        .map_err(|e| e.into())
        .and_then(|m| run_migration(conn, &*m, output))
}

fn migration_with_version(ver: &str) -> Result<Box<Migration>, MigrationError> {
    let migrations_dir = try!(find_migrations_directory());
    let all_migrations = try!(migrations_in_directory(&migrations_dir));
    let migration = all_migrations.into_iter().find(|m| {
        m.version() == ver
    });
    match migration {
        Some(m) => Ok(m),
        None => Err(MigrationError::UnknownMigrationVersion(ver.into())),
    }
}

#[doc(hidden)]
pub fn setup_database<Conn: Connection>(conn: &Conn) -> QueryResult<usize> {
    conn.setup_helper_functions();
    create_schema_migrations_table_if_needed(conn)
}

fn create_schema_migrations_table_if_needed<Conn: Connection>(conn: &Conn) -> QueryResult<usize> {
    conn.silence_notices(|| {
        conn.execute("CREATE TABLE IF NOT EXISTS __diesel_schema_migrations (
            version VARCHAR(50) PRIMARY KEY NOT NULL,
            run_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
        )")
    })
}

#[doc(hidden)]
pub fn migration_paths_in_directory(path: &Path) -> Result<Vec<DirEntry>, MigrationError> {
    try!(path.read_dir())
        .filter_map(|entry| {
            let entry = match entry {
                Ok(e) => e,
                Err(e) => return Some(Err(e.into())),
            };
            if entry.file_name().to_string_lossy().starts_with('.') {
                None
            } else {
                Some(Ok(entry))
            }
        }).collect()
}

fn migrations_in_directory(path: &Path) -> Result<Vec<Box<Migration>>, MigrationError> {
    use self::migration::migration_from;

    try!(migration_paths_in_directory(path)).iter().map(|e| {
        migration_from(e.path())
    }).collect()
}

/// Run all pending migrations in the given list. Apps should likely be calling
/// `run_pending_migrations` or `run_pending_migrations_in_directory` instead.
pub fn run_migrations<Conn, List>(
    conn: &Conn,
    migrations: List,
    output: &mut Write,
) -> Result<(), RunMigrationsError> where
    Conn: MigrationConnection,
    List: IntoIterator,
    List::Item: Migration,
{
    try!(setup_database(conn));
    let already_run = try!(conn.previously_run_migration_versions());
    let mut pending_migrations: Vec<_> = migrations.into_iter()
        .filter(|m| {
            !already_run.contains(&m.version().to_string())
        }).collect();

    pending_migrations.sort_by(|a, b| a.version().cmp(b.version()));
    for migration in pending_migrations {
        try!(run_migration(conn, &migration, output));
    }
    Ok(())
}

fn run_migration<Conn>(conn: &Conn, migration: &Migration, output: &mut Write)
    -> Result<(), RunMigrationsError> where
        Conn: MigrationConnection,
{
    conn.transaction(|| {
        try!(writeln!(output, "Running migration {}", migration.version()));
        try!(migration.run(conn));
        try!(conn.insert_new_migration(migration.version()));
        Ok(())
    })
}

fn revert_migration<Conn: Connection>(conn: &Conn, migration: Box<Migration>, output: &mut Write)
    -> Result<(), RunMigrationsError>
{
    conn.transaction(|| {
        try!(writeln!(output, "Rolling back migration {}", migration.version()));
        try!(migration.revert(conn));
        let target = __diesel_schema_migrations.filter(version.eq(migration.version()));
        try!(::delete(target).execute(conn));
        Ok(())
    })
}

/// Returns the directory containing migrations. Will look at for
/// $PWD/migrations. If it is not found, it will search the parents of the
/// current directory, until it reaches the root directory.  Returns
/// `MigrationError::MigrationDirectoryNotFound` if no directory is found.
pub fn find_migrations_directory() -> Result<PathBuf, MigrationError> {
    search_for_migrations_directory(&try!(env::current_dir()))
}

/// Searches for the migrations directory relative to the given path. See
/// `find_migrations_directory` for more details.
pub fn search_for_migrations_directory(path: &Path) -> Result<PathBuf, MigrationError> {
    let migration_path = path.join("migrations");
    if migration_path.is_dir() {
        Ok(migration_path)
    } else {
        path.parent().map(search_for_migrations_directory)
            .unwrap_or(Err(MigrationError::MigrationDirectoryNotFound))
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;

    use super::*;

    use self::tempdir::TempDir;
    use std::fs;

    #[test]
    fn migration_directory_not_found_if_no_migration_dir_exists() {
        let dir = TempDir::new("diesel").unwrap();

        assert_eq!(Err(MigrationError::MigrationDirectoryNotFound),
            search_for_migrations_directory(dir.path()));
    }

    #[test]
    fn migration_directory_defaults_to_pwd_slash_migrations() {
        let dir = TempDir::new("diesel").unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");

        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(Ok(migrations_path), search_for_migrations_directory(&temp_path));
    }

    #[test]
    fn migration_directory_checks_parents() {
        let dir = TempDir::new("diesel").unwrap();
        let temp_path = dir.path().canonicalize().unwrap();
        let migrations_path = temp_path.join("migrations");
        let child_path = temp_path.join("child");

        fs::create_dir(&child_path).unwrap();
        fs::create_dir(&migrations_path).unwrap();

        assert_eq!(Ok(migrations_path), search_for_migrations_directory(&child_path));
    }
}
<|endoftext|>


<commit_before><commit_msg>metadata.rs is empty<commit_after><|endoftext|>


<commit_before>#![cfg(feature = "full")]

#[macro_use]
extern crate quote;
extern crate syn;
extern crate syntex_pos;
extern crate syntex_syntax;
extern crate walkdir;

use syntex_pos::Span;
use syntex_syntax::ast;
use syntex_syntax::parse::{self, ParseSess, PResult};
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use std::fs::File;
use std::io::{self, Read, Write};
use std::panic;
use std::time::Instant;

macro_rules! errorf {
    ($($tt:tt)*) => {
        write!(io::stderr(), $($tt)*).unwrap();
    };
}

fn filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail") ||
       path_string.starts_with("tests/rust/src/test/compile-fail") {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // TODO better support for attributes
        "tests/rust/src/test/pretty/stmt_expr_attributes.rs" |
        // not actually a test case
        "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/cfg_stmt_expr.rs" |
        // TODO weird glob import
        "tests/rust/src/test/run-pass/import-glob-crate.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/inner-attrs-on-impl.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/item-attributes.rs" |
        // TODO precedence issue with binop vs poly trait ref
        "tests/rust/src/test/run-pass/try-macro.rs" => false,
        _ => true,
    }
}

#[test]
fn test_round_trip() {
    {
        let min_stack_value = std::env::var("RUST_MIN_STACK").expect("RUST_MIN_STACK env var should be set since some tests require it.");
        let min_stack_value: usize = min_stack_value.parse().expect("RUST_MIN_STACK env var should be set since some tests require it.");
        assert!(min_stack_value >= 16000000);
    }

    let mut failed = 0;

    let walk = WalkDir::new("tests/rust").sort_by(|a, b| a.cmp(b));
    for entry in walk.into_iter().filter_entry(filter) {
        let entry = entry.unwrap();

        let path = entry.path();
        if path.is_dir() {
            continue;
        }
        errorf!("=== {}: ", path.display());

        let mut file = File::open(path).unwrap();
        let mut content = String::new();
        file.read_to_string(&mut content).unwrap();

        let start = Instant::now();
        let (krate, elapsed) = match syn::parse_crate(&content) {
            Ok(krate) => (krate, start.elapsed()),
            Err(msg) => {
                errorf!("syn failed to parse\n{}\n", msg);
                failed += 1;
                continue;
            }
        };
        let back = quote!(#krate).to_string();

        let equal = panic::catch_unwind(|| {
            let sess = ParseSess::new();
            let before = match syntex_parse(content, &sess) {
                Ok(before) => before,
                Err(mut diagnostic) => {
                    diagnostic.cancel();
                    if diagnostic.message().starts_with("file not found for module") {
                        errorf!("ignore\n");
                        return true;
                    } else {
                        errorf!("FAIL: {}\n", diagnostic.message());
                        return false;
                    }
                }
            };
            let after = match syntex_parse(back, &sess) {
                Ok(after) => after,
                Err(mut diagnostic) => {
                    errorf!("syntex failed to parse");
                    diagnostic.emit();
                    return false;
                }
            };

            if before == after {
                errorf!("pass in {}ms\n",
                        elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000);
                true
            } else {
                errorf!("FAIL\nbefore: {}\nafter: {}\n",
                        format!("{:?}", before).replace("\n", ""),
                        format!("{:?}", after).replace("\n", ""));
                false
            }
        });
        match equal {
            Err(_) => errorf!("ignoring syntex panic\n"),
            Ok(true) => {}
            Ok(false) => failed += 1,
        }
    }

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn syntex_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
    let name = "test_round_trip".to_string();
    parse::parse_crate_from_source_str(name, content, sess).map(respan_crate)
}

fn respan_crate(krate: ast::Crate) -> ast::Crate {
    use std::rc::Rc;
    use syntex_syntax::ast::{Attribute, Expr, ExprKind, Field, FnDecl, FunctionRetTy, ImplItem,
                             ImplItemKind, ItemKind, Mac, MetaItem, MetaItemKind, MethodSig,
                             NestedMetaItem, NestedMetaItemKind, TraitItem, TraitItemKind, TyParam,
                             Visibility};
    use syntex_syntax::codemap::{self, Spanned};
    use syntex_syntax::fold::{self, Folder};
    use syntex_syntax::parse::token::{Lit, Token};
    use syntex_syntax::ptr::P;
    use syntex_syntax::symbol::Symbol;
    use syntex_syntax::tokenstream::{Delimited, SequenceRepetition, TokenTree};
    use syntex_syntax::util::move_map::MoveMap;
    use syntex_syntax::util::small_vector::SmallVector;

    struct Respanner;

    impl Respanner {
        fn fold_spanned<T>(&mut self, spanned: Spanned<T>) -> Spanned<T> {
            codemap::respan(self.new_span(spanned.span), spanned.node)
        }

        fn fold_lit(&mut self, l: Lit) -> Lit {
            // Give up on comparing literals inside of macros because there are
            // so many equivalent representations of the same literal; they are
            // tested elsewhere
            match l {
                Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
                Lit::Char(_) => Lit::Char(Symbol::intern("")),
                Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
                Lit::Float(_) => Lit::Float(Symbol::intern("")),
                Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
                Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
                _ => l,
            }
        }
    }

    impl Folder for Respanner {
        fn new_span(&mut self, _: Span) -> Span {
            syntex_pos::DUMMY_SP
        }

        fn fold_item_kind(&mut self, i: ItemKind) -> ItemKind {
            match i {
                ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
                    let generics = self.fold_generics(generics);
                    let decl = self.fold_fn_decl(decl);
                    let body = self.fold_block(body);
                    // default fold_item_kind does not fold this span
                    let constness = self.fold_spanned(constness);
                    ItemKind::Fn(decl, unsafety, constness, abi, generics, body)
                }
                _ => fold::noop_fold_item_kind(i, self),
            }
        }

        fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
            e.map(|e| {
                let folded = fold::noop_fold_expr(e, self);
                Expr {
                    node: match folded.node {
                        ExprKind::Lit(l) => {
                            // default fold_expr does not fold lits
                            ExprKind::Lit(l.map(|l| self.fold_spanned(l)))
                        }
                        ExprKind::Binary(op, lhs, rhs) => {
                            // default fold_expr does not fold the op span
                            ExprKind::Binary(self.fold_spanned(op),
                                             self.fold_expr(lhs),
                                             self.fold_expr(rhs))
                        }
                        ExprKind::AssignOp(op, lhs, rhs) => {
                            // default fold_expr does not fold the op span
                            ExprKind::AssignOp(self.fold_spanned(op),
                                               self.fold_expr(lhs),
                                               self.fold_expr(rhs))
                        }
                        other => other,
                    },
                    ..folded
                }
            })
        }

        fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
            TyParam {
                // default fold_ty_param does not fold the span
                span: self.new_span(tp.span),
                ..fold::noop_fold_ty_param(tp, self)
            }
        }

        fn fold_fn_decl(&mut self, decl: P<FnDecl>) -> P<FnDecl> {
            decl.map(|FnDecl { inputs, output, variadic }| {
                FnDecl {
                    inputs: inputs.move_map(|x| self.fold_arg(x)),
                    output: match output {
                        FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(self.fold_ty(ty)),
                        // default fold_fn_decl does not fold this span
                        FunctionRetTy::Default(span) => FunctionRetTy::Default(self.new_span(span)),
                    },
                    variadic: variadic,
                }
            })
        }

        fn fold_field(&mut self, field: Field) -> Field {
            Field {
                ident: codemap::respan(// default fold_field does not fold this span
                                       self.new_span(field.ident.span),
                                       self.fold_ident(field.ident.node)),
                expr: self.fold_expr(field.expr),
                span: self.new_span(field.span),
                is_shorthand: field.is_shorthand,
                attrs: ast::ThinVec::new(),
            }
        }

        fn fold_trait_item(&mut self, i: TraitItem) -> SmallVector<TraitItem> {
            let noop = fold::noop_fold_trait_item(i, self).expect_one("");
            SmallVector::one(TraitItem {
                                 node: match noop.node {
                                     TraitItemKind::Method(sig, body) => {
                        TraitItemKind::Method(MethodSig {
                                                  constness: self.fold_spanned(sig.constness),
                                                  ..sig
                                              },
                                              body)
                    }
                                     node => node,
                                 },
                                 ..noop
                             })
        }

        fn fold_impl_item(&mut self, i: ImplItem) -> SmallVector<ImplItem> {
            let noop = fold::noop_fold_impl_item(i, self).expect_one("");
            SmallVector::one(ImplItem {
                                 node: match noop.node {
                                     ImplItemKind::Method(sig, body) => {
                        ImplItemKind::Method(MethodSig {
                                                 constness: self.fold_spanned(sig.constness),
                                                 ..sig
                                             },
                                             body)
                    }
                                     node => node,
                                 },
                                 ..noop
                             })
        }

        fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
            at.id.0 = 0;
            fold::noop_fold_attribute(at, self)
        }

        fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
            let MetaItem { name, node, span } = meta_item;
            MetaItem {
                name: name,
                node: match node {
                    MetaItemKind::Word => MetaItemKind::Word,
                    MetaItemKind::List(nested) => {
                        MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
                    }
                    // default fold_meta_item does not fold the value span
                    MetaItemKind::NameValue(lit) => MetaItemKind::NameValue(self.fold_spanned(lit)),
                },
                span: self.new_span(span),
            }
        }

        fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
            Spanned {
                node: match list_item.node {
                    NestedMetaItemKind::MetaItem(mi) => {
                        NestedMetaItemKind::MetaItem(self.fold_meta_item(mi))
                    }
                    // default fold_meta_list_item does not fold the span
                    NestedMetaItemKind::Literal(lit) => {
                        NestedMetaItemKind::Literal(self.fold_spanned(lit))
                    }
                },
                span: self.new_span(list_item.span),
            }
        }

        fn fold_mac(&mut self, mac: Mac) -> Mac {
            fold::noop_fold_mac(mac, self)
        }

        fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree {
            match *tt {
                TokenTree::Token(span, ref tok) => {
                    TokenTree::Token(self.new_span(span), self.fold_token(tok.clone()))
                }
                TokenTree::Delimited(span, ref delimed) => {
                    TokenTree::Delimited(self.new_span(span),
                                         Rc::new(Delimited {
                                                     delim: delimed.delim,
                                                     tts: self.fold_tts(&delimed.tts),
                                                 }))
                }
                TokenTree::Sequence(span, ref seq) => {
                    TokenTree::Sequence(self.new_span(span),
                                        Rc::new(SequenceRepetition {
                                            tts: self.fold_tts(&seq.tts),
                                            separator: seq.separator
                                                .clone()
                                                .map(|tok| self.fold_token(tok)),
                                            ..**seq
                                        }))
                }
            }
        }

        fn fold_token(&mut self, t: Token) -> Token {
            match t {
                // default fold_token does not fold literals
                Token::Literal(lit, repr) => Token::Literal(self.fold_lit(lit), repr),
                Token::Ident(id) => Token::Ident(self.fold_ident(id)),
                Token::Lifetime(id) => Token::Lifetime(self.fold_ident(id)),
                Token::Interpolated(nt) => {
                    let nt = match Rc::try_unwrap(nt) {
                        Ok(nt) => nt,
                        Err(nt) => (*nt).clone(),
                    };
                    Token::Interpolated(Rc::new(self.fold_interpolated(nt)))
                }
                Token::SubstNt(ident) => Token::SubstNt(self.fold_ident(ident)),
                Token::MatchNt(name, kind) => {
                    Token::MatchNt(self.fold_ident(name), self.fold_ident(kind))
                }
                _ => t,
            }
        }

        fn fold_vis(&mut self, vis: Visibility) -> Visibility {
            match vis {
                Visibility::Crate(span) => Visibility::Crate(self.new_span(span)),
                _ => fold::noop_fold_vis(vis, self),
            }
        }
    }

    Respanner.fold_crate(krate)
}
<commit_msg>Consider the test a success if syntex fails to parse the original content.<commit_after>#![cfg(feature = "full")]

#[macro_use]
extern crate quote;
extern crate syn;
extern crate syntex_pos;
extern crate syntex_syntax;
extern crate walkdir;

use syntex_pos::Span;
use syntex_syntax::ast;
use syntex_syntax::parse::{self, ParseSess, PResult};
use walkdir::{DirEntry, WalkDir, WalkDirIterator};

use std::fs::File;
use std::io::{self, Read, Write};
use std::panic;
use std::time::Instant;

macro_rules! errorf {
    ($($tt:tt)*) => {
        write!(io::stderr(), $($tt)*).unwrap();
    };
}

fn filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail") ||
       path_string.starts_with("tests/rust/src/test/compile-fail") {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // TODO better support for attributes
        "tests/rust/src/test/pretty/stmt_expr_attributes.rs" |
        // not actually a test case
        "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/cfg_stmt_expr.rs" |
        // TODO weird glob import
        "tests/rust/src/test/run-pass/import-glob-crate.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/inner-attrs-on-impl.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/item-attributes.rs" |
        // TODO precedence issue with binop vs poly trait ref
        "tests/rust/src/test/run-pass/try-macro.rs" => false,
        _ => true,
    }
}

#[test]
fn test_round_trip() {
    {
        let min_stack_value = std::env::var("RUST_MIN_STACK").expect("RUST_MIN_STACK env var should be set since some tests require it.");
        let min_stack_value: usize = min_stack_value.parse().expect("RUST_MIN_STACK env var should be set since some tests require it.");
        assert!(min_stack_value >= 16000000);
    }

    let mut failed = 0;

    let walk = WalkDir::new("tests/rust").sort_by(|a, b| a.cmp(b));
    for entry in walk.into_iter().filter_entry(filter) {
        let entry = entry.unwrap();

        let path = entry.path();
        if path.is_dir() {
            continue;
        }
        errorf!("=== {}: ", path.display());

        let mut file = File::open(path).unwrap();
        let mut content = String::new();
        file.read_to_string(&mut content).unwrap();

        let start = Instant::now();
        let (krate, elapsed) = match syn::parse_crate(&content) {
            Ok(krate) => (krate, start.elapsed()),
            Err(msg) => {
                errorf!("syn failed to parse\n{}\n", msg);
                failed += 1;
                continue;
            }
        };
        let back = quote!(#krate).to_string();

        let equal = panic::catch_unwind(|| {
            let sess = ParseSess::new();
            let before = match syntex_parse(content, &sess) {
                Ok(before) => before,
                Err(mut diagnostic) => {
                    diagnostic.cancel();
                    if diagnostic.message().starts_with("file not found for module") {
                        errorf!("ignore\n");
                    } else {
                        errorf!("ignore - syntex failed to parse original content: {}\n", diagnostic.message());
                    }
                    return true;
                }
            };
            let after = match syntex_parse(back, &sess) {
                Ok(after) => after,
                Err(mut diagnostic) => {
                    errorf!("syntex failed to parse");
                    diagnostic.emit();
                    return false;
                }
            };

            if before == after {
                errorf!("pass in {}ms\n",
                        elapsed.as_secs() * 1000 + elapsed.subsec_nanos() as u64 / 1_000_000);
                true
            } else {
                errorf!("FAIL\nbefore: {}\nafter: {}\n",
                        format!("{:?}", before).replace("\n", ""),
                        format!("{:?}", after).replace("\n", ""));
                false
            }
        });
        match equal {
            Err(_) => errorf!("ignoring syntex panic\n"),
            Ok(true) => {}
            Ok(false) => failed += 1,
        }
    }

    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn syntex_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
    let name = "test_round_trip".to_string();
    parse::parse_crate_from_source_str(name, content, sess).map(respan_crate)
}

fn respan_crate(krate: ast::Crate) -> ast::Crate {
    use std::rc::Rc;
    use syntex_syntax::ast::{Attribute, Expr, ExprKind, Field, FnDecl, FunctionRetTy, ImplItem,
                             ImplItemKind, ItemKind, Mac, MetaItem, MetaItemKind, MethodSig,
                             NestedMetaItem, NestedMetaItemKind, TraitItem, TraitItemKind, TyParam,
                             Visibility};
    use syntex_syntax::codemap::{self, Spanned};
    use syntex_syntax::fold::{self, Folder};
    use syntex_syntax::parse::token::{Lit, Token};
    use syntex_syntax::ptr::P;
    use syntex_syntax::symbol::Symbol;
    use syntex_syntax::tokenstream::{Delimited, SequenceRepetition, TokenTree};
    use syntex_syntax::util::move_map::MoveMap;
    use syntex_syntax::util::small_vector::SmallVector;

    struct Respanner;

    impl Respanner {
        fn fold_spanned<T>(&mut self, spanned: Spanned<T>) -> Spanned<T> {
            codemap::respan(self.new_span(spanned.span), spanned.node)
        }

        fn fold_lit(&mut self, l: Lit) -> Lit {
            // Give up on comparing literals inside of macros because there are
            // so many equivalent representations of the same literal; they are
            // tested elsewhere
            match l {
                Lit::Byte(_) => Lit::Byte(Symbol::intern("")),
                Lit::Char(_) => Lit::Char(Symbol::intern("")),
                Lit::Integer(_) => Lit::Integer(Symbol::intern("")),
                Lit::Float(_) => Lit::Float(Symbol::intern("")),
                Lit::Str_(_) => Lit::Str_(Symbol::intern("")),
                Lit::ByteStr(_) => Lit::ByteStr(Symbol::intern("")),
                _ => l,
            }
        }
    }

    impl Folder for Respanner {
        fn new_span(&mut self, _: Span) -> Span {
            syntex_pos::DUMMY_SP
        }

        fn fold_item_kind(&mut self, i: ItemKind) -> ItemKind {
            match i {
                ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
                    let generics = self.fold_generics(generics);
                    let decl = self.fold_fn_decl(decl);
                    let body = self.fold_block(body);
                    // default fold_item_kind does not fold this span
                    let constness = self.fold_spanned(constness);
                    ItemKind::Fn(decl, unsafety, constness, abi, generics, body)
                }
                _ => fold::noop_fold_item_kind(i, self),
            }
        }

        fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
            e.map(|e| {
                let folded = fold::noop_fold_expr(e, self);
                Expr {
                    node: match folded.node {
                        ExprKind::Lit(l) => {
                            // default fold_expr does not fold lits
                            ExprKind::Lit(l.map(|l| self.fold_spanned(l)))
                        }
                        ExprKind::Binary(op, lhs, rhs) => {
                            // default fold_expr does not fold the op span
                            ExprKind::Binary(self.fold_spanned(op),
                                             self.fold_expr(lhs),
                                             self.fold_expr(rhs))
                        }
                        ExprKind::AssignOp(op, lhs, rhs) => {
                            // default fold_expr does not fold the op span
                            ExprKind::AssignOp(self.fold_spanned(op),
                                               self.fold_expr(lhs),
                                               self.fold_expr(rhs))
                        }
                        other => other,
                    },
                    ..folded
                }
            })
        }

        fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
            TyParam {
                // default fold_ty_param does not fold the span
                span: self.new_span(tp.span),
                ..fold::noop_fold_ty_param(tp, self)
            }
        }

        fn fold_fn_decl(&mut self, decl: P<FnDecl>) -> P<FnDecl> {
            decl.map(|FnDecl { inputs, output, variadic }| {
                FnDecl {
                    inputs: inputs.move_map(|x| self.fold_arg(x)),
                    output: match output {
                        FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(self.fold_ty(ty)),
                        // default fold_fn_decl does not fold this span
                        FunctionRetTy::Default(span) => FunctionRetTy::Default(self.new_span(span)),
                    },
                    variadic: variadic,
                }
            })
        }

        fn fold_field(&mut self, field: Field) -> Field {
            Field {
                ident: codemap::respan(// default fold_field does not fold this span
                                       self.new_span(field.ident.span),
                                       self.fold_ident(field.ident.node)),
                expr: self.fold_expr(field.expr),
                span: self.new_span(field.span),
                is_shorthand: field.is_shorthand,
                attrs: ast::ThinVec::new(),
            }
        }

        fn fold_trait_item(&mut self, i: TraitItem) -> SmallVector<TraitItem> {
            let noop = fold::noop_fold_trait_item(i, self).expect_one("");
            SmallVector::one(TraitItem {
                                 node: match noop.node {
                                     TraitItemKind::Method(sig, body) => {
                        TraitItemKind::Method(MethodSig {
                                                  constness: self.fold_spanned(sig.constness),
                                                  ..sig
                                              },
                                              body)
                    }
                                     node => node,
                                 },
                                 ..noop
                             })
        }

        fn fold_impl_item(&mut self, i: ImplItem) -> SmallVector<ImplItem> {
            let noop = fold::noop_fold_impl_item(i, self).expect_one("");
            SmallVector::one(ImplItem {
                                 node: match noop.node {
                                     ImplItemKind::Method(sig, body) => {
                        ImplItemKind::Method(MethodSig {
                                                 constness: self.fold_spanned(sig.constness),
                                                 ..sig
                                             },
                                             body)
                    }
                                     node => node,
                                 },
                                 ..noop
                             })
        }

        fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
            at.id.0 = 0;
            fold::noop_fold_attribute(at, self)
        }

        fn fold_meta_item(&mut self, meta_item: MetaItem) -> MetaItem {
            let MetaItem { name, node, span } = meta_item;
            MetaItem {
                name: name,
                node: match node {
                    MetaItemKind::Word => MetaItemKind::Word,
                    MetaItemKind::List(nested) => {
                        MetaItemKind::List(nested.move_map(|e| self.fold_meta_list_item(e)))
                    }
                    // default fold_meta_item does not fold the value span
                    MetaItemKind::NameValue(lit) => MetaItemKind::NameValue(self.fold_spanned(lit)),
                },
                span: self.new_span(span),
            }
        }

        fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem {
            Spanned {
                node: match list_item.node {
                    NestedMetaItemKind::MetaItem(mi) => {
                        NestedMetaItemKind::MetaItem(self.fold_meta_item(mi))
                    }
                    // default fold_meta_list_item does not fold the span
                    NestedMetaItemKind::Literal(lit) => {
                        NestedMetaItemKind::Literal(self.fold_spanned(lit))
                    }
                },
                span: self.new_span(list_item.span),
            }
        }

        fn fold_mac(&mut self, mac: Mac) -> Mac {
            fold::noop_fold_mac(mac, self)
        }

        fn fold_tt(&mut self, tt: &TokenTree) -> TokenTree {
            match *tt {
                TokenTree::Token(span, ref tok) => {
                    TokenTree::Token(self.new_span(span), self.fold_token(tok.clone()))
                }
                TokenTree::Delimited(span, ref delimed) => {
                    TokenTree::Delimited(self.new_span(span),
                                         Rc::new(Delimited {
                                                     delim: delimed.delim,
                                                     tts: self.fold_tts(&delimed.tts),
                                                 }))
                }
                TokenTree::Sequence(span, ref seq) => {
                    TokenTree::Sequence(self.new_span(span),
                                        Rc::new(SequenceRepetition {
                                            tts: self.fold_tts(&seq.tts),
                                            separator: seq.separator
                                                .clone()
                                                .map(|tok| self.fold_token(tok)),
                                            ..**seq
                                        }))
                }
            }
        }

        fn fold_token(&mut self, t: Token) -> Token {
            match t {
                // default fold_token does not fold literals
                Token::Literal(lit, repr) => Token::Literal(self.fold_lit(lit), repr),
                Token::Ident(id) => Token::Ident(self.fold_ident(id)),
                Token::Lifetime(id) => Token::Lifetime(self.fold_ident(id)),
                Token::Interpolated(nt) => {
                    let nt = match Rc::try_unwrap(nt) {
                        Ok(nt) => nt,
                        Err(nt) => (*nt).clone(),
                    };
                    Token::Interpolated(Rc::new(self.fold_interpolated(nt)))
                }
                Token::SubstNt(ident) => Token::SubstNt(self.fold_ident(ident)),
                Token::MatchNt(name, kind) => {
                    Token::MatchNt(self.fold_ident(name), self.fold_ident(kind))
                }
                _ => t,
            }
        }

        fn fold_vis(&mut self, vis: Visibility) -> Visibility {
            match vis {
                Visibility::Crate(span) => Visibility::Crate(self.new_span(span)),
                _ => fold::noop_fold_vis(vis, self),
            }
        }
    }

    Respanner.fold_crate(krate)
}
<|endoftext|>


<commit_before>extern crate msgflo;

use msgflo::participant::{Participant, InfoBuilder, Info};

struct Repeat {
    state: Option<String>, // we don't really have any state
}

impl Participant for Repeat {
    fn info(&self) -> Info {
        InfoBuilder::new("rust/Repeat")
            .label("Repeats input as-is")
            .inport("in")
            .outport("out")
            .build()
    }

    fn process(&self, input: Vec<u8>) -> Result<Vec<u8>, Vec<u8>> {
        println!("repeat process():");
        return Ok(input);
    }

}

fn main() {
    static r: Repeat = Repeat { state: None };
    msgflo::participant::main(&r);
}
<commit_msg>examples: Formatting<commit_after>extern crate msgflo;
use msgflo::participant::{Participant, InfoBuilder, Info};

struct Repeat {
    state: Option<String>, // we don't really have any state
}
impl Participant for Repeat {
    fn info(&self) -> Info {
        InfoBuilder::new("rust/Repeat").label("Repeats input as-is")
            .inport("in")
            .outport("out")
            .build()
    }
    // Will be called with input AMQP data on 'in' port, and send to 'out'
    fn process(&self, input: Vec<u8>) -> Result<Vec<u8>, Vec<u8>> {
        println!("repeat process():");
        return Ok(input);
    }
}
fn main() {
    static r: Repeat = Repeat { state: None };
    msgflo::participant::main(&r);
}
<|endoftext|>


<commit_before>extern crate syntect;
extern crate getopts;

use getopts::Options;
use std::borrow::Cow;
use std::io::BufRead;
use std::path::Path;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::{Theme, ThemeSet, Style};
use syntect::util::as_24_bit_terminal_escaped;
use syntect::easy::HighlightFile;
use syntect::dumps::{from_dump_file, dump_to_file};

fn load_theme(tm_file: &String, enable_caching: bool) -> Theme {
    let tm_path = Path::new(tm_file);

    if enable_caching {
        let tm_cache = tm_path.with_extension("tmdump");

        if tm_cache.exists() {
            from_dump_file(tm_cache).unwrap()
        } else {
            let theme = ThemeSet::get_theme(tm_path).unwrap();
            dump_to_file(&theme, tm_cache).unwrap();
            theme
        }
    } else {
        ThemeSet::get_theme(tm_path).unwrap()
    }
}

fn main() {
    let ss = SyntaxSet::load_defaults_newlines(); // note we load the version with newlines
    let ts = ThemeSet::load_defaults();

    let args: Vec<String> = std::env::args().collect();
    let mut opts = Options::new();
    opts.optflag("l", "list-file-types", "Lists supported file types");
    opts.optflag("L", "list-embedded-themes", "Lists themes present in the executable");
    opts.optopt("t", "theme-file", "THEME_FILE", "Theme file to use. May be a path, or an embedded theme. Embedded themes will take precendence. Default: base16-ocean.dark");
    opts.optflag("c", "cache-theme", "Cache the parsed theme file.");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("list-file-types") {
        println!("Supported file types:");

        for sd in ss.syntaxes() {
            println!("- {} (.{})", sd.name, sd.file_extensions.join(", ."));
        }

    } else if matches.opt_present("list-embedded-themes") {
        println!("Embedded themes:");

        for t in ts.themes.keys() {
            println!("- {}", t);
        }

    } else if matches.free.len() == 0 {
        let brief = format!("USAGE: {} [options] FILES", args[0]);
        println!("{}", opts.usage(&brief));

    } else {
        let theme_file : String = matches.opt_str("theme-file")
            .unwrap_or("base16-ocean.dark".to_string());

        let theme = ts.themes.get(&theme_file)
            .map(|t| Cow::Borrowed(t))
            .unwrap_or_else(|| Cow::Owned(load_theme(&theme_file, matches.opt_present("cache-theme"))));

        for src in &matches.free[..] {
            if matches.free.len() > 1 {
                println!("==> {} <==", src);
            }

            let mut highlighter = HighlightFile::new(src, &ss, &theme).unwrap();

            // We use read_line instead of `for line in highlighter.reader.lines()` because that
            // doesn't return strings with a `\n`, and including the `\n` gets us more robust highlighting.
            // See the documentation for `SyntaxSet::load_syntaxes`.
            // It also allows re-using the line buffer, which should be a tiny bit faster.
            let mut line = String::new();
            while highlighter.reader.read_line(&mut line).unwrap() > 0 {
                {
                    let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line);
                    print!("{}", as_24_bit_terminal_escaped(&regions[..], true));
                }
                line.clear();
            }

            // Clear the formatting
            println!("\x1b[0m");
        }
    }
}
<commit_msg>Add option to load extra syntaxes in syncat<commit_after>extern crate syntect;
extern crate getopts;

use getopts::Options;
use std::borrow::Cow;
use std::io::BufRead;
use std::path::Path;
use syntect::parsing::SyntaxSet;
use syntect::highlighting::{Theme, ThemeSet, Style};
use syntect::util::as_24_bit_terminal_escaped;
use syntect::easy::HighlightFile;
use syntect::dumps::{from_dump_file, dump_to_file};

fn load_theme(tm_file: &String, enable_caching: bool) -> Theme {
    let tm_path = Path::new(tm_file);

    if enable_caching {
        let tm_cache = tm_path.with_extension("tmdump");

        if tm_cache.exists() {
            from_dump_file(tm_cache).unwrap()
        } else {
            let theme = ThemeSet::get_theme(tm_path).unwrap();
            dump_to_file(&theme, tm_cache).unwrap();
            theme
        }
    } else {
        ThemeSet::get_theme(tm_path).unwrap()
    }
}

fn main() {
    let mut ss = SyntaxSet::load_defaults_newlines(); // note we load the version with newlines
    let ts = ThemeSet::load_defaults();

    let args: Vec<String> = std::env::args().collect();
    let mut opts = Options::new();
    opts.optflag("l", "list-file-types", "Lists supported file types");
    opts.optflag("L", "list-embedded-themes", "Lists themes present in the executable");
    opts.optopt("t", "theme-file", "THEME_FILE", "Theme file to use. May be a path, or an embedded theme. Embedded themes will take precendence. Default: base16-ocean.dark");
    opts.optopt("s", "extra-syntaxes", "SYNTAX_FOLDER", "Additional folder to search for .sublime-syntax files in.");
    opts.optflag("c", "cache-theme", "Cache the parsed theme file.");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("list-file-types") {
        println!("Supported file types:");

        for sd in ss.syntaxes() {
            println!("- {} (.{})", sd.name, sd.file_extensions.join(", ."));
        }

    } else if matches.opt_present("list-embedded-themes") {
        println!("Embedded themes:");

        for t in ts.themes.keys() {
            println!("- {}", t);
        }

    } else if matches.free.len() == 0 {
        let brief = format!("USAGE: {} [options] FILES", args[0]);
        println!("{}", opts.usage(&brief));

    } else {
        let theme_file : String = matches.opt_str("theme-file")
            .unwrap_or("base16-ocean.dark".to_string());

        let theme = ts.themes.get(&theme_file)
            .map(|t| Cow::Borrowed(t))
            .unwrap_or_else(|| Cow::Owned(load_theme(&theme_file, matches.opt_present("cache-theme"))));

        if let Some(folder) = matches.opt_str("extra-syntaxes") {
            ss.load_syntaxes(folder, true).unwrap();
            ss.link_syntaxes();
        }

        for src in &matches.free[..] {
            if matches.free.len() > 1 {
                println!("==> {} <==", src);
            }

            let mut highlighter = HighlightFile::new(src, &ss, &theme).unwrap();

            // We use read_line instead of `for line in highlighter.reader.lines()` because that
            // doesn't return strings with a `\n`, and including the `\n` gets us more robust highlighting.
            // See the documentation for `SyntaxSet::load_syntaxes`.
            // It also allows re-using the line buffer, which should be a tiny bit faster.
            let mut line = String::new();
            while highlighter.reader.read_line(&mut line).unwrap() > 0 {
                {
                    let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line);
                    print!("{}", as_24_bit_terminal_escaped(&regions[..], true));
                }
                line.clear();
            }

            // Clear the formatting
            println!("\x1b[0m");
        }
    }
}
<|endoftext|>


<commit_before>// test1.rs
// This is a test for the following sections:
// - Variables
// - Functions

// Mary is buying apples. One apple usually costs 2 dollars, but if you buy
// more than 40 at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the order amount. No hints this time!

// Put your function here!
// fn ..... {

// Don't modify this function!
#[test]
fn verify_test() {
    let price1 = calculate_price(55);
    let price2 = calculate_price(40);

    assert_eq!(price1, 55);
    assert_eq!(price2, 80);
}
<commit_msg>fix(test1): Swap assertion parameter order<commit_after>// test1.rs
// This is a test for the following sections:
// - Variables
// - Functions

// Mary is buying apples. One apple usually costs 2 dollars, but if you buy
// more than 40 at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the order amount. No hints this time!

// Put your function here!
// fn ..... {

// Don't modify this function!
#[test]
fn verify_test() {
    let price1 = calculate_price(55);
    let price2 = calculate_price(40);

    assert_eq!(55, price1);
    assert_eq!(80, price2);
}
<|endoftext|>


<commit_before>use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;
use reduction::*;

// PAIR := λxyf.f x y
pub fn pair() -> Term { abs(abs(abs(Var(1).app(Var(3)).app(Var(2))))) }

// FIRST := λp.p TRUE
pub fn first() -> Term { abs(Var(1).app(tru())) }

// SECOND := λp.p FALSE
pub fn second() -> Term { abs(Var(1).app(fls())) }

// NIL := λx.TRUE
pub fn nil() -> Term { abs(tru()) }

// NULL := λp.p (λxy.FALSE)
pub fn null() -> Term { abs(Var(1).app(abs(abs(fls())))) }

// CONS := λht.PAIR FALSE (PAIR h t)
pub fn cons() -> Term { abs(abs(pair().app(fls()).app(pair().app(Var(2)).app(Var(1))))) }

// HEAD := λz.FIRST (SECOND z)
pub fn head() -> Term { abs(first().app(second().app(Var(1)))) }

// TAIL := λz.SECOND (SECOND z)
pub fn tail() -> Term { abs(second().app(second().app(Var(1)))) }

impl Term {
	pub fn is_pair(&self) -> bool {
		self.fst_ref().is_ok() && self.snd_ref().is_ok()
	}

	pub fn unpair(self) -> Result<(Term, Term), Error> {
		if let Abs(_) = self {
			if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		} else {
			if let Ok((wrapped_a, b)) = self.unapp() {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		}
	}

	pub fn fst(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs()
				.and_then(|t| t.lhs())
				.and_then(|t| t.rhs())
		} else {
			self.lhs().and_then(|t| t.rhs())
		}
	}

	pub fn fst_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref()
				.and_then(|t| t.lhs_ref())
				.and_then(|t| t.rhs_ref())
		} else {
			self.lhs_ref().and_then(|t| t.rhs_ref())
		}
	}

	pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut()
				.and_then(|t| t.lhs_ref_mut())
				.and_then(|t| t.rhs_ref_mut())
		} else {
			self.lhs_ref_mut().and_then(|t| t.rhs_ref_mut())
		}
	}

	pub fn snd(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs().and_then(|t| t.rhs())
		} else {
			self.rhs()
		}
	}

	pub fn snd_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref().and_then(|t| t.rhs_ref())
		} else {
			self.rhs_ref()
		}
	}

	pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut().and_then(|t| t.rhs_ref_mut())
		} else {
			self.rhs_ref_mut()
		}
	}

	pub fn is_list(&self) -> bool {
		self.is_empty() || self.head_ref().is_ok() && self.tail_ref().is_ok()
	}

	pub fn is_empty(&self) -> bool {
		*self == nil()
	}

	pub fn uncons(self) -> Result<(Term, Term), Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.unpair())
	}

	pub fn head(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.fst())
	}

	pub fn head_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.fst_ref())
	}

	pub fn head_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.fst_ref_mut())
	}

	pub fn tail(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.snd())
	}

	pub fn tail_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.snd_ref())
	}

	pub fn tail_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.snd_ref_mut())
	}

	pub fn len(&self) -> Result<usize, Error> {
		let mut inner = self;
		let mut n = 0;

		while *inner != nil() {
			n += 1;
			inner = try!(inner.tail_ref());
		}

		Ok(n)
	}

	pub fn push(self, t: Term) -> Term {
		normalize(cons().app(t).app(self))
	}
}

impl From<Vec<Term>> for Term {
	fn from(terms: Vec<Term>) -> Self {
		let mut output = nil();

		for t in terms {
			output = cons().app(t).app(output);
		}

		normalize(output)
	}
}
/*
impl Iterator for Term {
	type Item = Term;

	fn next(&mut self) -> Option<Term> {
		if self.is_empty() {
			None
		} else {
			self.pop()
		}
	}
}
*/
#[cfg(test)]
mod test {
	use super::*;
	use arithmetic::*;

	#[test]
	fn empty_list() {
		let empty_list = nil();

		assert!(empty_list.is_list());
		assert!(empty_list.is_empty());
	}

	#[test]
	fn list_length() {
		let list0 = nil();
		assert_eq!(list0.len(), Ok(0));
		let list1 = normalize(cons().app(one()).app(list0));
		assert_eq!(list1.len(), Ok(1));
		let list2 = normalize(cons().app(one()).app(list1));
		assert_eq!(list2.len(), Ok(2));
		let list3 = normalize(cons().app(one()).app(list2));
		assert_eq!(list3.len(), Ok(3));
	}

	#[test]
	fn list_from_vector() {
		let terms_vec = vec![one(), zero(), one()];
		let list_from_vec = Term::from(terms_vec);
		let list_manual = normalize(cons().app(one()).app(cons().app(zero()).app(cons().app(one()).app(nil()))));

		assert_eq!(list_from_vec, list_manual);
	}

	#[test]
	fn pair_operations() {
		let pair_four_three = normalize(pair().app(to_cnum(4)).app(to_cnum(3)));

		assert!(pair_four_three.is_pair());

		assert_eq!(pair_four_three.fst_ref(), Ok(&to_cnum(4)));
		assert_eq!(pair_four_three.snd_ref(), Ok(&to_cnum(3)));

		let unpaired = pair_four_three.unpair();
		assert_eq!(unpaired, Ok((to_cnum(4), to_cnum(3))));
	}

	#[test]
	fn list_operations() {
		let empty_list = nil();
		let list_four = cons().app(to_cnum(4)).app(empty_list);
		let list_five_four = cons().app(to_cnum(5)).app(list_four);
		let list_three_five_four = normalize(cons().app(to_cnum(3)).app(list_five_four));

		assert!(list_three_five_four.is_list());

		assert_eq!(list_three_five_four.head_ref(), Ok(&to_cnum(3)));
		assert_eq!(list_three_five_four.tail_ref(), Ok(&normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil())))));

		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.tail_ref()).and_then(|t| t.head_ref()), Ok(&to_cnum(4)));

		let unconsed = list_three_five_four.uncons();
		assert_eq!(unconsed, Ok((to_cnum(3), normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil()))))));
	}

	#[test]
	fn list_push() {
		let list_pushed = nil().push(one()).push(zero()).push(one());
		let list_manual = normalize(cons().app(one()).app(cons().app(zero()).app(cons().app(one()).app(nil()))));

		assert_eq!(list_pushed, list_manual);
	}

/*
	#[test]
	fn list_pop() {
		let mut list = List::from(vec![Var(1), Var(0), Var(1)]);

		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), Some(Var(0)));
		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), None);
	}

	#[test]
	fn iterating_list() {
		let list = List::from(vec![Var(0), Var(1), Var(0)]);
		let mut iter = list.into_iter();

		assert_eq!(iter.next(), Some(Var(0)));
		assert_eq!(iter.next(), Some(Var(1)));
		assert_eq!(iter.next(), Some(Var(0)));
	}
*/
}<commit_msg>Fix from(), refactor tests<commit_after>use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;
use reduction::*;

// PAIR := λxyf.f x y
pub fn pair() -> Term { abs(abs(abs(Var(1).app(Var(3)).app(Var(2))))) }

// FIRST := λp.p TRUE
pub fn first() -> Term { abs(Var(1).app(tru())) }

// SECOND := λp.p FALSE
pub fn second() -> Term { abs(Var(1).app(fls())) }

// NIL := λx.TRUE
pub fn nil() -> Term { abs(tru()) }

// NULL := λp.p (λxy.FALSE)
pub fn null() -> Term { abs(Var(1).app(abs(abs(fls())))) }

// CONS := λht.PAIR FALSE (PAIR h t)
pub fn cons() -> Term { abs(abs(pair().app(fls()).app(pair().app(Var(2)).app(Var(1))))) }

// HEAD := λz.FIRST (SECOND z)
pub fn head() -> Term { abs(first().app(second().app(Var(1)))) }

// TAIL := λz.SECOND (SECOND z)
pub fn tail() -> Term { abs(second().app(second().app(Var(1)))) }

impl Term {
	pub fn is_pair(&self) -> bool {
		self.fst_ref().is_ok() && self.snd_ref().is_ok()
	}

	pub fn unpair(self) -> Result<(Term, Term), Error> {
		if let Abs(_) = self {
			if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		} else {
			if let Ok((wrapped_a, b)) = self.unapp() {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		}
	}

	pub fn fst(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs()
				.and_then(|t| t.lhs())
				.and_then(|t| t.rhs())
		} else {
			self.lhs().and_then(|t| t.rhs())
		}
	}

	pub fn fst_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref()
				.and_then(|t| t.lhs_ref())
				.and_then(|t| t.rhs_ref())
		} else {
			self.lhs_ref().and_then(|t| t.rhs_ref())
		}
	}

	pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut()
				.and_then(|t| t.lhs_ref_mut())
				.and_then(|t| t.rhs_ref_mut())
		} else {
			self.lhs_ref_mut().and_then(|t| t.rhs_ref_mut())
		}
	}

	pub fn snd(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs().and_then(|t| t.rhs())
		} else {
			self.rhs()
		}
	}

	pub fn snd_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref().and_then(|t| t.rhs_ref())
		} else {
			self.rhs_ref()
		}
	}

	pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut().and_then(|t| t.rhs_ref_mut())
		} else {
			self.rhs_ref_mut()
		}
	}

	pub fn is_list(&self) -> bool {
		self.is_empty() || self.head_ref().is_ok() && self.tail_ref().is_ok()
	}

	pub fn is_empty(&self) -> bool {
		*self == nil()
	}

	pub fn uncons(self) -> Result<(Term, Term), Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.unpair())
	}

	pub fn head(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.fst())
	}

	pub fn head_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.fst_ref())
	}

	pub fn head_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.fst_ref_mut())
	}

	pub fn tail(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.snd())
	}

	pub fn tail_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.snd_ref())
	}

	pub fn tail_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.snd_ref_mut())
	}

	pub fn len(&self) -> Result<usize, Error> {
		let mut inner = self;
		let mut n = 0;

		while *inner != nil() {
			n += 1;
			inner = try!(inner.tail_ref());
		}

		Ok(n)
	}

	pub fn push(self, t: Term) -> Term {
		normalize(cons().app(t).app(self))
	}
}

impl From<Vec<Term>> for Term {
	fn from(terms: Vec<Term>) -> Self {
		let mut output = nil();

		for t in terms.into_iter().rev() {
			output = cons().app(t).app(output);
		}

		normalize(output)
	}
}
/*
impl Iterator for Term {
	type Item = Term;

	fn next(&mut self) -> Option<Term> {
		if self.is_empty() {
			None
		} else {
			self.pop()
		}
	}
}
*/
#[cfg(test)]
mod test {
	use super::*;
	use arithmetic::*;

	#[test]
	fn pair_operations() {
		let pair_four_three = normalize(pair().app(to_cnum(4)).app(to_cnum(3)));

		assert!(pair_four_three.is_pair());

		assert_eq!(pair_four_three.fst_ref(), Ok(&to_cnum(4)));
		assert_eq!(pair_four_three.snd_ref(), Ok(&to_cnum(3)));

		let unpaired = pair_four_three.unpair();
		assert_eq!(unpaired, Ok((to_cnum(4), to_cnum(3))));
	}

	#[test]
	fn empty_list() {
		let empty_list = nil();

		assert!(empty_list.is_list());
		assert!(empty_list.is_empty());
	}

	#[test]
	fn list_push() {
		let list_pushed = nil().push(zero()).push(one()).push(one());
		let list_manual = normalize(cons().app(one()).app(cons().app(one()).app(cons().app(zero()).app(nil()))));

		assert_eq!(list_pushed, list_manual);
	}

	#[test]
	fn list_from_vector() {
		let list_from_vec = Term::from(vec![one(), one(), zero()]);
		let list_pushed = nil().push(zero()).push(one()).push(one());

		assert_eq!(list_from_vec, list_pushed);
	}

	#[test]
	fn list_length() {
		let list0 = nil();
		assert_eq!(list0.len(), Ok(0));
		let list1 = list0.push(one());
		assert_eq!(list1.len(), Ok(1));
		let list2 = list1.push(one());
		assert_eq!(list2.len(), Ok(2));
		let list3 = list2.push(one());
		assert_eq!(list3.len(), Ok(3));
	}

	#[test]
	fn list_operations() {
		let list_three_five_four = Term::from(vec![to_cnum(3), to_cnum(5), to_cnum(4)]);

		assert!(list_three_five_four.is_list());

		assert_eq!(list_three_five_four.head_ref(), Ok(&to_cnum(3)));
		assert_eq!(list_three_five_four.tail_ref(), Ok(&Term::from(vec![to_cnum(5), to_cnum(4)])));

		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.tail_ref()).and_then(|t| t.head_ref()), Ok(&to_cnum(4)));

		let unconsed = list_three_five_four.uncons();
		assert_eq!(unconsed, Ok((to_cnum(3), Term::from(vec![to_cnum(5), to_cnum(4)]))));
	}

/*
	#[test]
	fn list_pop() {
		let mut list = List::from(vec![Var(1), Var(0), Var(1)]);

		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), Some(Var(0)));
		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), None);
	}

	#[test]
	fn iterating_list() {
		let list = List::from(vec![Var(0), Var(1), Var(0)]);
		let mut iter = list.into_iter();

		assert_eq!(iter.next(), Some(Var(0)));
		assert_eq!(iter.next(), Some(Var(1)));
		assert_eq!(iter.next(), Some(Var(0)));
	}
*/
}<|endoftext|>


<commit_before>extern crate sysfs_gpio;
extern crate sysfs_pwm;

use self::sysfs_gpio::{Direction, Pin};
use self::sysfs_pwm::{Pwm};
use ::std::error::Error;

#[test]
fn it_works() {
    assert_eq!(1, 0+1);
}

const PWM_CHIP: u32 = 0;
const PWM_NUMBER: u32 = 0;

//http://www.jumpnowtek.com/rpi/Using-the-Raspberry-Pi-Hardware-PWM-timers.html
//https://github.com/rust-embedded/rust-sysfs-pwm/blob/master/examples/breathe.rs
#[test]
#[ignore]
fn testPwm() {
    let pwm = Pwm::new(0, 0).unwrap();
    pwm.export().unwrap();
    pwm.enable(true).unwrap();
    pwm.set_period_ns(10000000).unwrap();
    pwm.set_duty_cycle_ns(8000000).unwrap();
    pwm.enable(false).unwrap();
    pwm.unexport().unwrap()
}<commit_msg>test_pwm<commit_after>extern crate sysfs_gpio;
extern crate sysfs_pwm;

use self::sysfs_gpio::{Direction, Pin};
use self::sysfs_pwm::{Pwm};
use ::std::error::Error;

#[test]
fn it_works() {
    assert_eq!(1, 0+1);
}

//http://www.jumpnowtek.com/rpi/Using-the-Raspberry-Pi-Hardware-PWM-timers.html
//https://github.com/rust-embedded/rust-sysfs-pwm/blob/master/examples/breathe.rs
#[test]
#[ignore]
fn test_pwm() {
    let pwm = Pwm::new(0, 0).unwrap();
    pwm.export().unwrap();
    pwm.enable(true).unwrap();
    pwm.set_period_ns(10000000).unwrap();
    pwm.set_duty_cycle_ns(8000000).unwrap();
    pwm.enable(false).unwrap();
    pwm.unexport().unwrap()
}<|endoftext|>


<commit_before>use crate::Config;
use std::io;
use std::io::Write;
use super::encoder::EncoderWriter;

/// A `Write` implementation that base64-encodes data using the provided config and accumulates the
/// resulting base64 in memory, which is then exposed as a String via `into_inner()`.
///
/// # Examples
///
/// Buffer base64 in a new String:
///
/// ```
/// use std::io::Write;
///
/// let mut enc = base64::write::EncoderStringWriter::new(base64::STANDARD);
///
/// enc.write_all(b"asdf").unwrap();
///
/// // get the resulting String
/// let b64_string = enc.into_inner();
///
/// assert_eq!("YXNkZg==", &b64_string);
/// ```
///
/// Or, append to an existing String:
///
/// ```
/// use std::io::Write;
///
/// let mut buf = String::from("base64: ");
///
/// let mut enc = base64::write::EncoderStringWriter::from(&mut buf, base64::STANDARD);
///
/// enc.write_all(b"asdf").unwrap();
///
/// // release the &mut reference on buf
/// let _ = enc.into_inner();
///
/// assert_eq!("base64: YXNkZg==", &buf);
/// ```
///
/// # Panics
///
/// Calling `write()` (or related methods) or `finish()` after `finish()` has completed without
/// error is invalid and will panic.
///
/// # Performance
///
/// Because it has to validate that the base64 is UTF-8, it is about 80% as fast as writing plain
/// bytes to a `io::Write`.
pub struct EncoderStringWriter<S: StrWrite> {
    encoder: EncoderWriter<Utf8SingleCodeUnitWriter<S>>,
}

impl<S: StrWrite> EncoderStringWriter<S> {
    /// Create a EncoderStringWriter that will append to the provided `StrWrite`.
    pub fn from(str_writer: S, config: Config) -> Self {
        EncoderStringWriter { encoder: EncoderWriter::new(Utf8SingleCodeUnitWriter { str_writer }, config) }
    }

    /// Encode all remaining buffered data, including any trailing incomplete input triples and
    /// associated padding.
    ///
    /// Once this succeeds, no further writes or calls to this method are allowed.
    ///
    /// Returns the base64-encoded form of the accumulated written data.
    pub fn into_inner(mut self) -> S {
        self.encoder.finish()
            .expect("Writing to a Vec<u8> should never fail")
            .str_writer
    }
}

impl EncoderStringWriter<String> {
    /// Create a EncoderStringWriter that will encode into a new String with the provided config.
    pub fn new(config: Config) -> Self {
        EncoderStringWriter::from(String::new(), config)
    }
}

impl <S: StrWrite> Write for EncoderStringWriter<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.encoder.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.encoder.flush()
    }
}

/// An abstraction around infallible writes of `str`s.
///
/// Typically, this will just be String.
pub trait StrWrite {
    /// The write must succeed, and must write the entire `buf`.
    fn write(&mut self, buf: &str);
}

/// As for io::Write, StrWrite is implemented automatically for `&mut S`.
impl<S: StrWrite + ?Sized> StrWrite for &mut S {
    fn write(&mut self, buf: &str) {
        (**self).write(buf)
    }
}

impl StrWrite for String {
    fn write(&mut self, buf: &str) {
        self.push_str(buf)
    }
}

/// A `Write` that only can handle bytes that are valid single-byte UTF-8 code units.
///
/// This is safe because we only use it when writing base64, which is always valid UTF-8.
struct Utf8SingleCodeUnitWriter<S: StrWrite> {
    str_writer: S
}

impl<S: StrWrite> io::Write for Utf8SingleCodeUnitWriter<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let s = std::str::from_utf8(buf)
            .expect("Input must be valid UTF-8");

        self.str_writer.write(s);

        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        // no op
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::encode_config_buf;
    use crate::tests::random_config;
    use rand::Rng;
    use std::io::Write;
    use crate::write::encoder_string_writer::EncoderStringWriter;

    #[test]
    fn every_possible_split_of_input() {
        let mut rng = rand::thread_rng();
        let mut orig_data = Vec::<u8>::new();
        let mut normal_encoded = String::new();

        let size = 5_000;

        for i in 0..size {
            orig_data.clear();
            normal_encoded.clear();

            for _ in 0..size {
                orig_data.push(rng.gen());
            }

            let config = random_config(&mut rng);
            encode_config_buf(&orig_data, config, &mut normal_encoded);

            let mut stream_encoder = EncoderStringWriter::new(config);
            // Write the first i bytes, then the rest
            stream_encoder.write_all(&orig_data[0..i]).unwrap();
            stream_encoder.write_all(&orig_data[i..]).unwrap();

            let stream_encoded = stream_encoder.into_inner();

            assert_eq!(normal_encoded, stream_encoded);
        }
    }
}
<commit_msg>Rename StrWrite to StrConsumer<commit_after>use crate::Config;
use std::io;
use std::io::Write;
use super::encoder::EncoderWriter;

/// A `Write` implementation that base64-encodes data using the provided config and accumulates the
/// resulting base64 in memory, which is then exposed as a String via `into_inner()`.
///
/// # Examples
///
/// Buffer base64 in a new String:
///
/// ```
/// use std::io::Write;
///
/// let mut enc = base64::write::EncoderStringWriter::new(base64::STANDARD);
///
/// enc.write_all(b"asdf").unwrap();
///
/// // get the resulting String
/// let b64_string = enc.into_inner();
///
/// assert_eq!("YXNkZg==", &b64_string);
/// ```
///
/// Or, append to an existing String:
///
/// ```
/// use std::io::Write;
///
/// let mut buf = String::from("base64: ");
///
/// let mut enc = base64::write::EncoderStringWriter::from(&mut buf, base64::STANDARD);
///
/// enc.write_all(b"asdf").unwrap();
///
/// // release the &mut reference on buf
/// let _ = enc.into_inner();
///
/// assert_eq!("base64: YXNkZg==", &buf);
/// ```
///
/// # Panics
///
/// Calling `write()` (or related methods) or `finish()` after `finish()` has completed without
/// error is invalid and will panic.
///
/// # Performance
///
/// Because it has to validate that the base64 is UTF-8, it is about 80% as fast as writing plain
/// bytes to a `io::Write`.
pub struct EncoderStringWriter<S: StrConsumer> {
    encoder: EncoderWriter<Utf8SingleCodeUnitWriter<S>>,
}

impl<S: StrConsumer> EncoderStringWriter<S> {
    /// Create a EncoderStringWriter that will append to the provided `StrConsumer`.
    pub fn from(str_consumer: S, config: Config) -> Self {
        EncoderStringWriter { encoder: EncoderWriter::new(Utf8SingleCodeUnitWriter { str_consumer }, config) }
    }

    /// Encode all remaining buffered data, including any trailing incomplete input triples and
    /// associated padding.
    ///
    /// Once this succeeds, no further writes or calls to this method are allowed.
    ///
    /// Returns the base64-encoded form of the accumulated written data.
    pub fn into_inner(mut self) -> S {
        self.encoder.finish()
            .expect("Writing to a Vec<u8> should never fail")
            .str_consumer
    }
}

impl EncoderStringWriter<String> {
    /// Create a EncoderStringWriter that will encode into a new String with the provided config.
    pub fn new(config: Config) -> Self {
        EncoderStringWriter::from(String::new(), config)
    }
}

impl <S: StrConsumer> Write for EncoderStringWriter<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.encoder.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.encoder.flush()
    }
}

/// An abstraction around consuming `str`s produced by base64 encoding.
pub trait StrConsumer {
    /// Consume the base64 encoded data in `buf`
    fn consume(&mut self, buf: &str);
}

/// As for io::Write, `StrConsumer` is implemented automatically for `&mut S`.
impl<S: StrConsumer + ?Sized> StrConsumer for &mut S {
    fn consume(&mut self, buf: &str) {
        (**self).consume(buf)
    }
}

/// Pushes the str onto the end of the String
impl StrConsumer for String {
    fn consume(&mut self, buf: &str) {
        self.push_str(buf)
    }
}

/// A `Write` that only can handle bytes that are valid single-byte UTF-8 code units.
///
/// This is safe because we only use it when writing base64, which is always valid UTF-8.
struct Utf8SingleCodeUnitWriter<S: StrConsumer> {
    str_consumer: S
}

impl<S: StrConsumer> io::Write for Utf8SingleCodeUnitWriter<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        // Because we expect all input to be valid utf-8 individual bytes, we can encode any buffer
        // length
        let s = std::str::from_utf8(buf)
            .expect("Input must be valid UTF-8");

        self.str_consumer.consume(s);

        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        // no op
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::encode_config_buf;
    use crate::tests::random_config;
    use rand::Rng;
    use std::io::Write;
    use crate::write::encoder_string_writer::EncoderStringWriter;

    #[test]
    fn every_possible_split_of_input() {
        let mut rng = rand::thread_rng();
        let mut orig_data = Vec::<u8>::new();
        let mut normal_encoded = String::new();

        let size = 5_000;

        for i in 0..size {
            orig_data.clear();
            normal_encoded.clear();

            for _ in 0..size {
                orig_data.push(rng.gen());
            }

            let config = random_config(&mut rng);
            encode_config_buf(&orig_data, config, &mut normal_encoded);

            let mut stream_encoder = EncoderStringWriter::new(config);
            // Write the first i bytes, then the rest
            stream_encoder.write_all(&orig_data[0..i]).unwrap();
            stream_encoder.write_all(&orig_data[i..]).unwrap();

            let stream_encoded = stream_encoder.into_inner();

            assert_eq!(normal_encoded, stream_encoded);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// 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.

//! Main for building the genesis generation utility.

use std::fs;
use std::sync::Arc;

<<<<<<< HEAD
use chrono::prelude::Utc;
use chrono::Duration;
=======
use chrono::Duration;
use chrono::prelude::Utc;
>>>>>>> 3e7bc2888c4f23d3a362dd777ed28a4c9ab0b5ae
use curl;
use serde_json;

use grin_chain as chain;
use grin_core as core;
use grin_store as store;
use grin_util as util;

use grin_keychain::{ExtKeychain, Keychain};

static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";

fn main() {
	// get the latest bitcoin hash
	let h1 = get_bchain_head();
	let h2 = get_bcypher_head();
	let h3 = get_bchair_head();
	if h1 != h2 || h1 != h3 {
		panic!(
			"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
			h1, h2, h3
		);
	}
	println!("Using bitcoin block hash {}", h1);

	// build the basic parts of the genesis block header, perhaps some of this
	// can be moved to core
	let mut gen = core::genesis::genesis_main();
	gen.header.timestamp = Utc::now() + Duration::minutes(30);
	gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();
	println!("Built genesis:\n{:?}", gen);

	// TODO get the proper keychain and/or raw coinbase
	let keychain = ExtKeychain::from_random_seed().unwrap();
	let key_id = ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
	let reward = core::libtx::reward::output(&keychain, &key_id, 0, 0).unwrap();
	gen = gen.with_reward(reward.0, reward.1);

	{
		// setup a tmp chain to set block header roots
		let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
		tmp_chain.set_txhashset_roots(&mut gen).unwrap();
	}

	// TODO mine a valid Cuckatoo29 solution
	// TODO check again the bitcoin block to make sure it's not been orphaned
	// TODO Commit genesis block info in git and tag
}

fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
	util::init_test_logger();
	let _ = fs::remove_dir_all(dir_name);
	let verifier_cache = Arc::new(util::RwLock::new(
		core::core::verifier_cache::LruVerifierCache::new(),
	));
	let db_env = Arc::new(store::new_env(dir_name.to_string()));
	chain::Chain::init(
		dir_name.to_string(),
		db_env,
		Arc::new(chain::types::NoopAdapter {}),
		genesis,
		core::pow::verify_size,
		verifier_cache,
		false,
	)
	.unwrap()
}

fn get_bchain_head() -> String {
	get_json(BCHAIN_INFO_URL)["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_bcypher_head() -> String {
	get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}

fn get_bchair_head() -> String {
	get_json(BCHAIR_URL)["data"][0]["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_json(url: &str) -> serde_json::Value {
	let mut body = Vec::new();
	let mut easy = curl::easy::Easy::new();
	easy.url(url).unwrap();
	{
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				body.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	serde_json::from_slice(&body).unwrap()
}
<commit_msg>Trying to fix slight snafu<commit_after>// Copyright 2018 The Grin Developers
//
// 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.

//! Main for building the genesis generation utility.

use std::fs;
use std::sync::Arc;

use chrono::prelude::Utc;
use chrono::Duration;
use curl;
use serde_json;

use grin_chain as chain;
use grin_core as core;
use grin_store as store;
use grin_util as util;

use grin_keychain::{ExtKeychain, Keychain};

static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock";
static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main";
static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2";

fn main() {
	// get the latest bitcoin hash
	let h1 = get_bchain_head();
	let h2 = get_bcypher_head();
	let h3 = get_bchair_head();
	if h1 != h2 || h1 != h3 {
		panic!(
			"Bitcoin chain head is inconsistent, please retry ({}, {}, {}).",
			h1, h2, h3
		);
	}
	println!("Using bitcoin block hash {}", h1);

	// build the basic parts of the genesis block header, perhaps some of this
	// can be moved to core
	let mut gen = core::genesis::genesis_main();
	gen.header.timestamp = Utc::now() + Duration::minutes(30);
	gen.header.prev_root = core::core::hash::Hash::from_hex(&h1).unwrap();
	println!("Built genesis:\n{:?}", gen);

	// TODO get the proper keychain and/or raw coinbase
	let keychain = ExtKeychain::from_random_seed().unwrap();
	let key_id = ExtKeychain::derive_key_id(0, 1, 0, 0, 0);
	let reward = core::libtx::reward::output(&keychain, &key_id, 0, 0).unwrap();
	gen = gen.with_reward(reward.0, reward.1);

	{
		// setup a tmp chain to set block header roots
		let tmp_chain = setup_chain(".grin.tmp", core::pow::mine_genesis_block().unwrap());
		tmp_chain.set_txhashset_roots(&mut gen).unwrap();
	}

	// TODO mine a valid Cuckatoo29 solution
	// TODO check again the bitcoin block to make sure it's not been orphaned
	// TODO Commit genesis block info in git and tag
}

fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {
	util::init_test_logger();
	let _ = fs::remove_dir_all(dir_name);
	let verifier_cache = Arc::new(util::RwLock::new(
		core::core::verifier_cache::LruVerifierCache::new(),
	));
	let db_env = Arc::new(store::new_env(dir_name.to_string()));
	chain::Chain::init(
		dir_name.to_string(),
		db_env,
		Arc::new(chain::types::NoopAdapter {}),
		genesis,
		core::pow::verify_size,
		verifier_cache,
		false,
	)
	.unwrap()
}

fn get_bchain_head() -> String {
	get_json(BCHAIN_INFO_URL)["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_bcypher_head() -> String {
	get_json(BCYPHER_URL)["hash"].as_str().unwrap().to_string()
}

fn get_bchair_head() -> String {
	get_json(BCHAIR_URL)["data"][0]["hash"]
		.as_str()
		.unwrap()
		.to_string()
}

fn get_json(url: &str) -> serde_json::Value {
	let mut body = Vec::new();
	let mut easy = curl::easy::Easy::new();
	easy.url(url).unwrap();
	{
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				body.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	serde_json::from_slice(&body).unwrap()
}
<|endoftext|>