<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::exec;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::fshelper;
use crate::internal::{opts::FdOptions, osstr_to_bytes, MAX_BUFFER_LENGTH};
use crate::output;

use std::borrow::Cow;
use std::convert::TryFrom;
use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::bytes::Regex;

/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
    /// Receiver is still buffering in order to sort the results, if the search finishes fast
    /// enough.
    Buffering,

    /// Receiver is directly printing results to the output.
    Streaming,
}

/// The Worker threads can result in a valid entry having PathBuf or an error.
pub enum WorkerResult {
    Entry(PathBuf),
    Error(ignore::Error),
}

/// Converts a WorkerResult to a PathBuf. This is required as in some cases,
/// the underlying `ignore` libary will return an error when we actually
/// still want to show the path.
///
/// Currently, the cases supported are:
///   - a broken symlink should still be found and the path returned
impl TryFrom<WorkerResult> for PathBuf {
    type Error = ignore::Error;

    fn try_from(worker_result: WorkerResult) -> Result<PathBuf, Self::Error> {
        match worker_result {
            WorkerResult::Entry(value) => return Ok(value),
            WorkerResult::Error(ignore_error) => {
                if let ignore::Error::WithPath { path, err } = &ignore_error {
                    if let ignore::Error::Io(ref io_err) = **err {
                        if io_err.kind() == io::ErrorKind::NotFound {
                            if let Ok(metadata) = fs::symlink_metadata(&path) {
                                if metadata.file_type().is_symlink() {
                                    return Ok(path.to_path_buf());
                                }
                            }
                        }
                    }
                }
                return Err(ignore_error);
            }
        }
    }
}

/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) -> ExitCode {
    let mut path_iter = path_vec.iter();
    let first_path_buf = path_iter
        .next()
        .expect("Error: Path vector can not be empty");
    let (tx, rx) = channel();

    let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());

    for pattern in &config.exclude_patterns {
        let res = override_builder.add(pattern);
        if res.is_err() {
            print_error_and_exit!("Malformed exclude pattern '{}'", pattern);
        }
    }
    let overrides = override_builder.build().unwrap_or_else(|_| {
        print_error_and_exit!("Mismatch in exclude patterns");
    });

    let mut walker = WalkBuilder::new(first_path_buf.as_path());
    walker
        .hidden(config.ignore_hidden)
        .ignore(config.read_fdignore)
        .parents(config.read_fdignore || config.read_vcsignore)
        .git_ignore(config.read_vcsignore)
        .git_global(config.read_vcsignore)
        .git_exclude(config.read_vcsignore)
        .overrides(overrides)
        .follow_links(config.follow_links)
        // No need to check for supported platforms, option is unavailable on unsupported ones
        .same_file_system(config.one_file_system)
        .max_depth(config.max_depth);

    if config.read_fdignore {
        walker.add_custom_ignore_filename(".fdignore");
    }

    for ignore_file in &config.ignore_files {
        let result = walker.add_ignore(ignore_file);
        match result {
            Some(ignore::Error::Partial(_)) => (),
            Some(err) => {
                print_error!(
                    "{}",
                    format!(
                        "Malformed pattern in custom ignore file '{}': {}.",
                        ignore_file.to_string_lossy(),
                        err.description()
                    )
                );
            }
            None => (),
        }
    }

    for path_entry in path_iter {
        walker.add(path_entry.as_path());
    }

    let parallel_walker = walker.threads(config.threads).build_parallel();

    let wants_to_quit = Arc::new(AtomicBool::new(false));
    if config.ls_colors.is_some() && config.command.is_none() {
        let wq = Arc::clone(&wants_to_quit);
        ctrlc::set_handler(move || {
            if wq.load(Ordering::Relaxed) {
                // Ctrl-C has been pressed twice, exit NOW
                process::exit(ExitCode::KilledBySigint.into());
            } else {
                wq.store(true, Ordering::Relaxed);
            }
        })
        .unwrap();
    }

    // Spawn the thread that receives all results through the channel.
    let receiver_thread = spawn_receiver(&config, &wants_to_quit, rx);

    // Spawn the sender threads.
    spawn_senders(&config, &wants_to_quit, pattern, parallel_walker, tx);

    // Wait for the receiver thread to print out all results.
    let exit_code = receiver_thread.join().unwrap();

    if wants_to_quit.load(Ordering::Relaxed) {
        process::exit(ExitCode::KilledBySigint.into());
    }

    exit_code
}

fn spawn_receiver(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    rx: Receiver<WorkerResult>,
) -> thread::JoinHandle<ExitCode> {
    let config = Arc::clone(config);
    let wants_to_quit = Arc::clone(wants_to_quit);

    let show_filesystem_errors = config.show_filesystem_errors;
    let threads = config.threads;

    thread::spawn(move || {
        // This will be set to `Some` if the `--exec` argument was supplied.
        if let Some(ref cmd) = config.command {
            if cmd.in_batch_mode() {
                exec::batch(rx, cmd, show_filesystem_errors)
            } else {
                let shared_rx = Arc::new(Mutex::new(rx));

                let out_perm = Arc::new(Mutex::new(()));

                // Each spawned job will store it's thread handle in here.
                let mut handles = Vec::with_capacity(threads);
                for _ in 0..threads {
                    let rx = Arc::clone(&shared_rx);
                    let cmd = Arc::clone(cmd);
                    let out_perm = Arc::clone(&out_perm);

                    // Spawn a job thread that will listen for and execute inputs.
                    let handle =
                        thread::spawn(move || exec::job(rx, cmd, out_perm, show_filesystem_errors));

                    // Push the handle of the spawned thread into the vector for later joining.
                    handles.push(handle);
                }

                // Wait for all threads to exit before exiting the program.
                let mut results: Vec<ExitCode> = Vec::new();
                for h in handles {
                    results.push(h.join().unwrap());
                }

                merge_exitcodes(results)
            }
        } else {
            let start = time::Instant::now();

            let mut buffer = vec![];

            // Start in buffering mode
            let mut mode = ReceiverMode::Buffering;

            // Maximum time to wait before we start streaming to the console.
            let max_buffer_time = config
                .max_buffer_time
                .unwrap_or_else(|| time::Duration::from_millis(100));

            let stdout = io::stdout();
            let mut stdout = stdout.lock();

            for worker_result in rx {
                match PathBuf::try_from(worker_result) {
                    Ok(value) => {
                        match mode {
                            ReceiverMode::Buffering => {
                                buffer.push(value);

                                // Have we reached the maximum buffer size or maximum buffering time?
                                if buffer.len() > MAX_BUFFER_LENGTH
                                    || time::Instant::now() - start > max_buffer_time
                                {
                                    // Flush the buffer
                                    for v in &buffer {
                                        output::print_entry(
                                            &mut stdout,
                                            v,
                                            &config,
                                            &wants_to_quit,
                                        );
                                    }
                                    buffer.clear();

                                    // Start streaming
                                    mode = ReceiverMode::Streaming;
                                }
                            }
                            ReceiverMode::Streaming => {
                                output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                            }
                        }
                    }
                    Err(err) => {
                        if show_filesystem_errors {
                            print_error!("{}", err);
                        }
                    }
                }
            }

            // If we have finished fast enough (faster than max_buffer_time), we haven't streamed
            // anything to the console, yet. In this case, sort the results and print them:
            if !buffer.is_empty() {
                buffer.sort();
                for value in buffer {
                    output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                }
            }

            ExitCode::Success
        }
    })
}

fn spawn_senders(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    pattern: Arc<Regex>,
    parallel_walker: ignore::WalkParallel,
    tx: Sender<WorkerResult>,
) {
    parallel_walker.run(|| {
        let config = Arc::clone(config);
        let pattern = Arc::clone(&pattern);
        let tx_thread = tx.clone();
        let wants_to_quit = Arc::clone(wants_to_quit);

        Box::new(move |entry_o| {
            if wants_to_quit.load(Ordering::Relaxed) {
                return ignore::WalkState::Quit;
            }

            let entry = match entry_o {
                Ok(e) => e,
                Err(err) => {
                    tx_thread.send(WorkerResult::Error(err)).unwrap();
                    return ignore::WalkState::Continue;
                }
            };

            if entry.depth() == 0 {
                return ignore::WalkState::Continue;
            }

            // Check the name first, since it doesn't require metadata
            let entry_path = entry.path();

            let search_str: Cow<OsStr> = if config.search_full_path {
                match fshelper::path_absolute_form(entry_path) {
                    Ok(path_abs_buf) => Cow::Owned(path_abs_buf.as_os_str().to_os_string()),
                    Err(_) => {
                        print_error_and_exit!("Unable to retrieve absolute path.");
                    }
                }
            } else {
                match entry_path.file_name() {
                    Some(filename) => Cow::Borrowed(filename),
                    None => unreachable!(
                        "Encountered file system entry without a file name. This should only \
                         happen for paths like 'foo/bar/..' or '/' which are not supposed to \
                         appear in a file system traversal."
                    ),
                }
            };

            if !pattern.is_match(&osstr_to_bytes(search_str.as_ref())) {
                return ignore::WalkState::Continue;
            }

            // Filter out unwanted extensions.
            if let Some(ref exts_regex) = config.extensions {
                if let Some(path_str) = entry_path.file_name() {
                    if !exts_regex.is_match(&osstr_to_bytes(path_str)) {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted file types.
            if let Some(ref file_types) = config.file_types {
                if let Some(ref entry_type) = entry.file_type() {
                    if (!file_types.files && entry_type.is_file())
                        || (!file_types.directories && entry_type.is_dir())
                        || (!file_types.symlinks && entry_type.is_symlink())
                        || (file_types.executables_only
                            && !entry
                                .metadata()
                                .map(|m| fshelper::is_executable(&m))
                                .unwrap_or(false))
                        || (file_types.empty_only && !fshelper::is_empty(&entry))
                        || !(entry_type.is_file() || entry_type.is_dir() || entry_type.is_symlink())
                    {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted sizes if it is a file and we have been given size constraints.
            if !config.size_constraints.is_empty() {
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        let file_size = metadata.len();
                        if config
                            .size_constraints
                            .iter()
                            .any(|sc| !sc.is_within(file_size))
                        {
                            return ignore::WalkState::Continue;
                        }
                    } else {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted modification times
            if !config.time_constraints.is_empty() {
                let mut matched = false;
                if let Ok(metadata) = entry_path.metadata() {
                    if let Ok(modified) = metadata.modified() {
                        matched = config
                            .time_constraints
                            .iter()
                            .all(|tf| tf.applies_to(&modified));
                    }
                }
                if !matched {
                    return ignore::WalkState::Continue;
                }
            }

            let send_result = tx_thread.send(WorkerResult::Entry(entry_path.to_owned()));

            if !send_result.is_ok() {
                return ignore::WalkState::Quit;
            }

            ignore::WalkState::Continue
        })
    });
}
<commit_msg>Further simplify the code<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::exec;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::fshelper;
use crate::internal::{opts::FdOptions, osstr_to_bytes, MAX_BUFFER_LENGTH};
use crate::output;

use std::borrow::Cow;
use std::convert::TryFrom;
use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::bytes::Regex;

/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
    /// Receiver is still buffering in order to sort the results, if the search finishes fast
    /// enough.
    Buffering,

    /// Receiver is directly printing results to the output.
    Streaming,
}

/// The Worker threads can result in a valid entry having PathBuf or an error.
pub enum WorkerResult {
    Entry(PathBuf),
    Error(ignore::Error),
}

/// Converts a WorkerResult to a PathBuf. This is required as in some cases,
/// the underlying `ignore` libary will return an error when we actually
/// still want to show the path.
///
/// Currently, the cases supported are:
///   - a broken symlink should still be found and the path returned
impl TryFrom<WorkerResult> for PathBuf {
    type Error = ignore::Error;

    fn try_from(worker_result: WorkerResult) -> Result<PathBuf, Self::Error> {
        match worker_result {
            WorkerResult::Entry(value) => return Ok(value),
            WorkerResult::Error(ignore_error) => {
                if let ignore::Error::WithPath { path, err } = &ignore_error {
                    if let ignore::Error::Io(ref io_err) = **err {
                        if io_err.kind() == io::ErrorKind::NotFound
                            && fs::symlink_metadata(&path)
                                .map_or(false, |m| m.file_type().is_symlink())
                        {
                            return Ok(path.to_path_buf());
                        }
                    }
                }
                return Err(ignore_error);
            }
        }
    }
}

/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) -> ExitCode {
    let mut path_iter = path_vec.iter();
    let first_path_buf = path_iter
        .next()
        .expect("Error: Path vector can not be empty");
    let (tx, rx) = channel();

    let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());

    for pattern in &config.exclude_patterns {
        let res = override_builder.add(pattern);
        if res.is_err() {
            print_error_and_exit!("Malformed exclude pattern '{}'", pattern);
        }
    }
    let overrides = override_builder.build().unwrap_or_else(|_| {
        print_error_and_exit!("Mismatch in exclude patterns");
    });

    let mut walker = WalkBuilder::new(first_path_buf.as_path());
    walker
        .hidden(config.ignore_hidden)
        .ignore(config.read_fdignore)
        .parents(config.read_fdignore || config.read_vcsignore)
        .git_ignore(config.read_vcsignore)
        .git_global(config.read_vcsignore)
        .git_exclude(config.read_vcsignore)
        .overrides(overrides)
        .follow_links(config.follow_links)
        // No need to check for supported platforms, option is unavailable on unsupported ones
        .same_file_system(config.one_file_system)
        .max_depth(config.max_depth);

    if config.read_fdignore {
        walker.add_custom_ignore_filename(".fdignore");
    }

    for ignore_file in &config.ignore_files {
        let result = walker.add_ignore(ignore_file);
        match result {
            Some(ignore::Error::Partial(_)) => (),
            Some(err) => {
                print_error!(
                    "{}",
                    format!(
                        "Malformed pattern in custom ignore file '{}': {}.",
                        ignore_file.to_string_lossy(),
                        err.description()
                    )
                );
            }
            None => (),
        }
    }

    for path_entry in path_iter {
        walker.add(path_entry.as_path());
    }

    let parallel_walker = walker.threads(config.threads).build_parallel();

    let wants_to_quit = Arc::new(AtomicBool::new(false));
    if config.ls_colors.is_some() && config.command.is_none() {
        let wq = Arc::clone(&wants_to_quit);
        ctrlc::set_handler(move || {
            if wq.load(Ordering::Relaxed) {
                // Ctrl-C has been pressed twice, exit NOW
                process::exit(ExitCode::KilledBySigint.into());
            } else {
                wq.store(true, Ordering::Relaxed);
            }
        })
        .unwrap();
    }

    // Spawn the thread that receives all results through the channel.
    let receiver_thread = spawn_receiver(&config, &wants_to_quit, rx);

    // Spawn the sender threads.
    spawn_senders(&config, &wants_to_quit, pattern, parallel_walker, tx);

    // Wait for the receiver thread to print out all results.
    let exit_code = receiver_thread.join().unwrap();

    if wants_to_quit.load(Ordering::Relaxed) {
        process::exit(ExitCode::KilledBySigint.into());
    }

    exit_code
}

fn spawn_receiver(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    rx: Receiver<WorkerResult>,
) -> thread::JoinHandle<ExitCode> {
    let config = Arc::clone(config);
    let wants_to_quit = Arc::clone(wants_to_quit);

    let show_filesystem_errors = config.show_filesystem_errors;
    let threads = config.threads;

    thread::spawn(move || {
        // This will be set to `Some` if the `--exec` argument was supplied.
        if let Some(ref cmd) = config.command {
            if cmd.in_batch_mode() {
                exec::batch(rx, cmd, show_filesystem_errors)
            } else {
                let shared_rx = Arc::new(Mutex::new(rx));

                let out_perm = Arc::new(Mutex::new(()));

                // Each spawned job will store it's thread handle in here.
                let mut handles = Vec::with_capacity(threads);
                for _ in 0..threads {
                    let rx = Arc::clone(&shared_rx);
                    let cmd = Arc::clone(cmd);
                    let out_perm = Arc::clone(&out_perm);

                    // Spawn a job thread that will listen for and execute inputs.
                    let handle =
                        thread::spawn(move || exec::job(rx, cmd, out_perm, show_filesystem_errors));

                    // Push the handle of the spawned thread into the vector for later joining.
                    handles.push(handle);
                }

                // Wait for all threads to exit before exiting the program.
                let mut results: Vec<ExitCode> = Vec::new();
                for h in handles {
                    results.push(h.join().unwrap());
                }

                merge_exitcodes(results)
            }
        } else {
            let start = time::Instant::now();

            let mut buffer = vec![];

            // Start in buffering mode
            let mut mode = ReceiverMode::Buffering;

            // Maximum time to wait before we start streaming to the console.
            let max_buffer_time = config
                .max_buffer_time
                .unwrap_or_else(|| time::Duration::from_millis(100));

            let stdout = io::stdout();
            let mut stdout = stdout.lock();

            for worker_result in rx {
                match PathBuf::try_from(worker_result) {
                    Ok(value) => {
                        match mode {
                            ReceiverMode::Buffering => {
                                buffer.push(value);

                                // Have we reached the maximum buffer size or maximum buffering time?
                                if buffer.len() > MAX_BUFFER_LENGTH
                                    || time::Instant::now() - start > max_buffer_time
                                {
                                    // Flush the buffer
                                    for v in &buffer {
                                        output::print_entry(
                                            &mut stdout,
                                            v,
                                            &config,
                                            &wants_to_quit,
                                        );
                                    }
                                    buffer.clear();

                                    // Start streaming
                                    mode = ReceiverMode::Streaming;
                                }
                            }
                            ReceiverMode::Streaming => {
                                output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                            }
                        }
                    }
                    Err(err) => {
                        if show_filesystem_errors {
                            print_error!("{}", err);
                        }
                    }
                }
            }

            // If we have finished fast enough (faster than max_buffer_time), we haven't streamed
            // anything to the console, yet. In this case, sort the results and print them:
            if !buffer.is_empty() {
                buffer.sort();
                for value in buffer {
                    output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
                }
            }

            ExitCode::Success
        }
    })
}

fn spawn_senders(
    config: &Arc<FdOptions>,
    wants_to_quit: &Arc<AtomicBool>,
    pattern: Arc<Regex>,
    parallel_walker: ignore::WalkParallel,
    tx: Sender<WorkerResult>,
) {
    parallel_walker.run(|| {
        let config = Arc::clone(config);
        let pattern = Arc::clone(&pattern);
        let tx_thread = tx.clone();
        let wants_to_quit = Arc::clone(wants_to_quit);

        Box::new(move |entry_o| {
            if wants_to_quit.load(Ordering::Relaxed) {
                return ignore::WalkState::Quit;
            }

            let entry = match entry_o {
                Ok(e) => e,
                Err(err) => {
                    tx_thread.send(WorkerResult::Error(err)).unwrap();
                    return ignore::WalkState::Continue;
                }
            };

            if entry.depth() == 0 {
                return ignore::WalkState::Continue;
            }

            // Check the name first, since it doesn't require metadata
            let entry_path = entry.path();

            let search_str: Cow<OsStr> = if config.search_full_path {
                match fshelper::path_absolute_form(entry_path) {
                    Ok(path_abs_buf) => Cow::Owned(path_abs_buf.as_os_str().to_os_string()),
                    Err(_) => {
                        print_error_and_exit!("Unable to retrieve absolute path.");
                    }
                }
            } else {
                match entry_path.file_name() {
                    Some(filename) => Cow::Borrowed(filename),
                    None => unreachable!(
                        "Encountered file system entry without a file name. This should only \
                         happen for paths like 'foo/bar/..' or '/' which are not supposed to \
                         appear in a file system traversal."
                    ),
                }
            };

            if !pattern.is_match(&osstr_to_bytes(search_str.as_ref())) {
                return ignore::WalkState::Continue;
            }

            // Filter out unwanted extensions.
            if let Some(ref exts_regex) = config.extensions {
                if let Some(path_str) = entry_path.file_name() {
                    if !exts_regex.is_match(&osstr_to_bytes(path_str)) {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted file types.
            if let Some(ref file_types) = config.file_types {
                if let Some(ref entry_type) = entry.file_type() {
                    if (!file_types.files && entry_type.is_file())
                        || (!file_types.directories && entry_type.is_dir())
                        || (!file_types.symlinks && entry_type.is_symlink())
                        || (file_types.executables_only
                            && !entry
                                .metadata()
                                .map(|m| fshelper::is_executable(&m))
                                .unwrap_or(false))
                        || (file_types.empty_only && !fshelper::is_empty(&entry))
                        || !(entry_type.is_file() || entry_type.is_dir() || entry_type.is_symlink())
                    {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted sizes if it is a file and we have been given size constraints.
            if !config.size_constraints.is_empty() {
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        let file_size = metadata.len();
                        if config
                            .size_constraints
                            .iter()
                            .any(|sc| !sc.is_within(file_size))
                        {
                            return ignore::WalkState::Continue;
                        }
                    } else {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted modification times
            if !config.time_constraints.is_empty() {
                let mut matched = false;
                if let Ok(metadata) = entry_path.metadata() {
                    if let Ok(modified) = metadata.modified() {
                        matched = config
                            .time_constraints
                            .iter()
                            .all(|tf| tf.applies_to(&modified));
                    }
                }
                if !matched {
                    return ignore::WalkState::Continue;
                }
            }

            let send_result = tx_thread.send(WorkerResult::Entry(entry_path.to_owned()));

            if !send_result.is_ok() {
                return ignore::WalkState::Quit;
            }

            ignore::WalkState::Continue
        })
    });
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
  extern crate base58;
  use self::base58::encode_base58;

  #[test] // TODO Put this test to test.rs file
  fn should_encode_from_string_to_base58_string() {
    // Given
    let empty = String::from_str("");
    let azerty = String::from_str("azerty");
    let lorem = String::from_str("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");

    // When
    let empty_encoded = encode_base58(empty);
    let azerty_encoded = encode_base58(azerty);
    let lorem_encoded = encode_base58(lorem);

    // Then
    assert_eq!(empty_encoded, String::from_str(""));
    assert_eq!(azerty_encoded, String::from_str("qYPmmAqv"));
    assert_eq!(lorem_encoded, String::from_str("RKDitRLwUhnQCAmM9hhenQXRAiKrL3ByvJ4CYouvhmw6yV8fapqyM95bN6KQVJbKvEN3uHeMdP9G7b5HNxmwRGqGibzcjrKaRLL2Nn1GFZRRv2Q8AvQU7MtRagLLzcZcwBDzkMqEpbRy9CvGr3BE7t2rH4wXmdExSGNKqV5XxAG7QT2S4ZQ4nzom8QFmoUgkfj8ykPye3z8FU9gJzSf2cDRA1ecYwFJtNdycgKTYCQ92pcfq95DoWfTBhnJfkKZXe1Dv3guVKk5otHz4XtWFJjcSC2GLrkRhTAEtgkySmaePs5YyoQHKb8PU5paS3dxAWc7sV5rqwrJbSbj7ybK6FQDN2mgbBxy7Wc7CnX6Q3Jm4B8cmo4oGixuHKdufABEs4FM3PAhF5CTk9xFsyw3CVJGxE2sMyC5EKnAv5Zc4kGfzzTxQe7VZrm188XqGZKZVRhjSW9CeceAf9bvqefLahgGiKps13595WSErpo1HpHb6Qt22QLSMJFGB2Aq7asXXUj55wPxCfVCz8NiqewcNpxF9bvjW9xsaMGqgD4dpgrBFzUw6irds1X481DHnRDi98yAhQJVUoxP8WSm3qJ93qhq8Hx7Eg4aiy"));
  }

}

#[cfg(test)]
mod bench {
  extern crate test;
  extern crate base58;

  use self::test::Bencher;
  use self::base58::encode_base58;

  #[bench]
  fn encode_lorem_ispum(b: &mut Bencher) {
    b.iter(|| encode_base58(String::from_str("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")));
  }
}<commit_msg>Split a test method into 3 test methods<commit_after>#[cfg(test)]
mod tests {
  extern crate base58;
  use self::base58::encode_base58;

  #[test]
  fn should_encode_empty_string_to_empty_base58() {
    // Given
    let empty = String::from_str("");

    // When
    let empty_encoded = encode_base58(empty);

    // Then
    assert_eq!(empty_encoded, String::from_str(""));
  }

  #[test]
  fn should_encode_azerty_to_base58() {
    // Given
    let azerty = String::from_str("azerty");

    // When
    let azerty_encoded = encode_base58(azerty);

    // Then
    assert_eq!(azerty_encoded, String::from_str("qYPmmAqv"));
  }

  #[test]
  fn should_encode_lorem_string_to_base58() {
    // Given
    let lorem = String::from_str("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");

    // When
    let lorem_encoded = encode_base58(lorem);

    // Then
    assert_eq!(lorem_encoded, String::from_str("RKDitRLwUhnQCAmM9hhenQXRAiKrL3ByvJ4CYouvhmw6yV8fapqyM95bN6KQVJbKvEN3uHeMdP9G7b5HNxmwRGqGibzcjrKaRLL2Nn1GFZRRv2Q8AvQU7MtRagLLzcZcwBDzkMqEpbRy9CvGr3BE7t2rH4wXmdExSGNKqV5XxAG7QT2S4ZQ4nzom8QFmoUgkfj8ykPye3z8FU9gJzSf2cDRA1ecYwFJtNdycgKTYCQ92pcfq95DoWfTBhnJfkKZXe1Dv3guVKk5otHz4XtWFJjcSC2GLrkRhTAEtgkySmaePs5YyoQHKb8PU5paS3dxAWc7sV5rqwrJbSbj7ybK6FQDN2mgbBxy7Wc7CnX6Q3Jm4B8cmo4oGixuHKdufABEs4FM3PAhF5CTk9xFsyw3CVJGxE2sMyC5EKnAv5Zc4kGfzzTxQe7VZrm188XqGZKZVRhjSW9CeceAf9bvqefLahgGiKps13595WSErpo1HpHb6Qt22QLSMJFGB2Aq7asXXUj55wPxCfVCz8NiqewcNpxF9bvjW9xsaMGqgD4dpgrBFzUw6irds1X481DHnRDi98yAhQJVUoxP8WSm3qJ93qhq8Hx7Eg4aiy"));
  }

}

#[cfg(test)]
mod bench {
  extern crate test;
  extern crate base58;

  use self::test::Bencher;
  use self::base58::encode_base58;

  #[bench]
  fn encode_lorem_ispum(b: &mut Bencher) {
    b.iter(|| encode_base58(String::from_str("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")));
  }
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#![feature(conservative_impl_trait)]

extern crate futures;
extern crate gtk;
#[macro_use]
extern crate relm;
extern crate tokio_core;
extern crate url;

use std::net::ToSocketAddrs;

use futures::Future;
use futures::future::ok;
use gtk::{Button, ButtonExt, ContainerExt, Image, Label, WidgetExt, Window, WindowType};
use gtk::Orientation::Vertical;
use relm::{EventStream, Handle, QuitFuture, Relm, UnitFuture, Widget, connect};
use tokio_core::net::TcpStream;
use url::Url;

use self::Msg::*;

#[derive(Clone, Debug)]
struct Model {
    gif_url: String,
    topic: String,
}

#[derive(Clone)]
enum Msg {
    FetchImage,
    FetchUrl,
    NewGif(String),
    Quit,
}

struct Widgets {
    button: Button,
    image: Image,
    label: Label,
    window: Window,
}

struct Win {
    model: Model,
    widgets: Widgets,
}

impl Win {
    fn view() -> Widgets {
        let vbox = gtk::Box::new(Vertical, 0);

        let label = Label::new(None);
        vbox.add(&label);

        let image = Image::new();
        vbox.add(&image);

        let button = Button::new_with_label("Load image");
        vbox.add(&button);

        let window = Window::new(WindowType::Toplevel);

        window.add(&vbox);

        window.show_all();

        Widgets {
            button: button,
            image: image,
            label: label,
            window: window,
        }
    }
}

impl Widget<Msg> for Win {
    fn connect_events(&self, relm: &Relm<Msg>) {
        connect!(relm, self.widgets.button, connect_clicked(_), FetchUrl);
        connect_no_inhibit!(relm, self.widgets.window, connect_delete_event(_, _), Quit);
    }

    fn new() -> Self {
        Win {
            model: Model {
                gif_url: "waiting.gif".to_string(),
                topic: "cats".to_string(),
            },
            widgets: Self::view(),
        }
    }

    fn update(&mut self, event: Msg, handle: Handle, stream: EventStream<Msg>) -> UnitFuture {
        match event {
            FetchImage => {
            },
            FetchUrl => {
                let url = format!("https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag={}", self.model.topic);
                let http_future = http_get(&url, handle);
                return connect(http_future, NewGif, stream).boxed();
            },
            NewGif(result) => {
                println!("{}", result);
            },
            Quit => return QuitFuture.boxed(),
        }

        ok(()).boxed()
    }
}

fn http_get<'a>(url: &str, handle: Handle) -> impl Future<Item=String, Error=()> + 'a {
    let url = Url::parse(url).unwrap();
    let path = format!("{}?{}", url.path(), url.query().unwrap_or(""));
    let url = url.host_str();
    let url = url.unwrap();
    let host = format!("{}:80", url);
    let addr = host.to_socket_addrs().unwrap().next().unwrap();
    let socket = TcpStream::connect(&addr, &handle);
    let http = format!("\
        GET {} HTTP/1.0\r\n\
        Host: {}\r\n\
        \r\n\
    ", path, url);
    let request = socket.and_then(move |socket| {
        tokio_core::io::write_all(socket, http.into_bytes())
    });

    let response = request.and_then(|(socket, _request)| {
        tokio_core::io::read_to_end(socket, Vec::new())
    });
    response.and_then(|(_socket, response)| {
        let string = String::from_utf8(response).unwrap();
        let strings: Vec<_> = string.split("\n\n").collect();
        let body = strings[1].to_string();
        ok(body)
    })
        // TODO: try to box (so that it becomes Send) the error to keep it instead of ignoring it.
        .map_err(|_| ())
}

fn main() {
    Relm::run::<Win>().unwrap();
}
<commit_msg>Refactor and fix the http request code.<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#![feature(conservative_impl_trait)]

extern crate futures;
extern crate gtk;
#[macro_use]
extern crate relm;
extern crate tokio_core;
extern crate url;

use std::io::Error;
use std::net::ToSocketAddrs;

use futures::Future;
use futures::future::ok;
use gtk::{Button, ButtonExt, ContainerExt, Image, Label, WidgetExt, Window, WindowType};
use gtk::Orientation::Vertical;
use relm::{EventStream, Handle, QuitFuture, Relm, UnitFuture, Widget, connect};
use tokio_core::net::TcpStream;
use url::Url;

use self::Msg::*;

#[derive(Clone, Debug)]
struct Model {
    gif_url: String,
    topic: String,
}

#[derive(Clone)]
enum Msg {
    FetchImage,
    FetchUrl,
    NewGif(String),
    Quit,
}

struct Widgets {
    button: Button,
    image: Image,
    label: Label,
    window: Window,
}

struct Win {
    model: Model,
    widgets: Widgets,
}

impl Win {
    fn view() -> Widgets {
        let vbox = gtk::Box::new(Vertical, 0);

        let label = Label::new(None);
        vbox.add(&label);

        let image = Image::new();
        vbox.add(&image);

        let button = Button::new_with_label("Load image");
        vbox.add(&button);

        let window = Window::new(WindowType::Toplevel);

        window.add(&vbox);

        window.show_all();

        Widgets {
            button: button,
            image: image,
            label: label,
            window: window,
        }
    }
}

impl Widget<Msg> for Win {
    fn connect_events(&self, relm: &Relm<Msg>) {
        connect!(relm, self.widgets.button, connect_clicked(_), FetchUrl);
        connect_no_inhibit!(relm, self.widgets.window, connect_delete_event(_, _), Quit);
    }

    fn new() -> Self {
        Win {
            model: Model {
                gif_url: "waiting.gif".to_string(),
                topic: "cats".to_string(),
            },
            widgets: Self::view(),
        }
    }

    fn update(&mut self, event: Msg, handle: Handle, stream: EventStream<Msg>) -> UnitFuture {
        match event {
            FetchImage => {
            },
            FetchUrl => {
                let url = format!("https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag={}", self.model.topic);
                let http_future = http_get(&url, handle);
                return connect(http_future, NewGif, stream).boxed();
            },
            NewGif(result) => {
                println!("{}", result);
            },
            Quit => return QuitFuture.boxed(),
        }

        ok(()).boxed()
    }
}

fn http_get<'a>(url: &str, handle: Handle) -> impl Future<Item=String, Error=Error> + 'a {
    let url = Url::parse(url).unwrap();
    let path = format!("{}?{}", url.path(), url.query().unwrap_or(""));
    let url = url.host_str();
    let url = url.unwrap();
    let host = format!("{}:80", url);
    let addr = host.to_socket_addrs().unwrap().next().unwrap();
    let socket = TcpStream::connect(&addr, &handle);
    let http = format!("\
        GET {} HTTP/1.0\r\n\
        Host: {}\r\n\
        \r\n\
    ", path, url);
    let request = socket.and_then(move |socket| {
        tokio_core::io::write_all(socket, http.into_bytes())
    });

    let response = request.and_then(|(socket, _request)| {
        tokio_core::io::read_to_end(socket, Vec::new())
    });
    response.and_then(|(_socket, response)| {
        let string = String::from_utf8(response).unwrap();
        let strings: Vec<_> = string.split("\n\n").collect();
        let body = strings[1..].join("\n\n");
        ok(body)
    })
}

fn main() {
    Relm::run::<Win>().unwrap();
}
<|endoftext|>


<commit_before>//! A basic output stream example, using an Output AudioUnit to generate a sine wave.

extern crate coreaudio_rs as coreaudio;
extern crate num;

use coreaudio::audio_unit::{AudioUnit, Type, SubType};
use num::Float;
use std::f64::consts::PI;

// NOTE: temporary replacement for unstable `std::iter::iterate`
struct Iter {
    value: f64,
}
impl Iterator for Iter {
    type Item = f64;
    fn next(&mut self) -> Option<f64> {
        self.value += 440.0 / 44_100.0;
        Some(self.value)
    }
}

fn main() {

    // 440hz sine wave generator.
    let mut samples = Iter { value: 0.0 }
        .map(|phase| (phase * PI * 2.0).sin() as f32 * 0.15);

    // Construct an Output audio unit.
    let audio_unit = AudioUnit::new(Type::Output, SubType::HalOutput)
        .render_callback(Box::new(move |buffer, num_frames| {
            for frame in (0..num_frames) {
                let sample = samples.next().unwrap();
                for channel in buffer.iter_mut() {
                    channel[frame] = sample;
                }
            }
            Ok(())
        }))
        .start()
        .unwrap();

    ::std::thread::sleep_ms(3000);

    audio_unit.close();

}

<commit_msg>Updated example<commit_after>//! A basic output stream example, using an Output AudioUnit to generate a sine wave.

extern crate coreaudio_rs as coreaudio;
extern crate num;

use coreaudio::audio_unit::{AudioUnit, Type, SubType};
use num::Float;
use std::f64::consts::PI;

// NOTE: temporary replacement for unstable `std::iter::iterate`
struct Iter {
    value: f64,
}
impl Iterator for Iter {
    type Item = f64;
    fn next(&mut self) -> Option<f64> {
        self.value += 440.0 / 44_100.0;
        Some(self.value)
    }
}

fn main() {

    // 440hz sine wave generator.
    let mut samples = Iter { value: 0.0 }
        .map(|phase| (phase * PI * 2.0).sin() as f32 * 0.15);

    // Construct an Output audio unit.
    let mut audio_unit = AudioUnit::new(Type::Output, SubType::HalOutput).unwrap();
    audio_unit.render_callback(Some(Box::new(move |buffer, num_frames| {
        for frame in (0..num_frames) {
            let sample = samples.next().unwrap();
            for channel in buffer.iter_mut() {
                channel[frame] = sample;
            }
        }
        Ok(())
    }))).ok();
    audio_unit.start().ok();

    ::std::thread::sleep_ms(3000);
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

/// Escape a filter literal.
///
/// Literal values appearing in an LDAP filter can contain any character,
/// but some characters (parentheses, asterisk, backslash, NUL) must be
/// escaped in the filter's string representation. This function does the
/// escaping.
///
/// The argument, `lit`, can be owned or borrowed. The function doesn't
/// allocate the return value unless there's need to escape the input.
pub fn ldap_escape<'a, S: Into<Cow<'a, str>>>(lit: S) -> Cow<'a, str> {
    #[inline]
    fn needs_escape(c: u8) -> bool {
        c == b'\\' || c == b'*' || c == b'(' || c == b')' || c == 0
    }

    #[inline]
    fn xdigit(c: u8) -> u8 {
        c + if c < 10 { b'0' } else { b'a' - 10 }
    }

    let lit = lit.into();
    let mut output = None;
    for (i, &c) in lit.as_bytes().iter().enumerate() {
        if needs_escape(c) {
            if output.is_none() {
                output = Some(Vec::with_capacity(lit.len() + 12)); // guess: up to 4 escaped chars
                output.as_mut().unwrap().extend(lit[..i].as_bytes());
            }
            let output = output.as_mut().unwrap();
            output.push(b'\\');
            output.push(xdigit(c >> 4));
            output.push(xdigit(c & 0xF));
        } else if let Some(ref mut output) = output {
            output.push(c);
        }
    }
    if let Some(output) = output {
        // unchecked conversion is safe here: we receive a valid
        // UTF-8 value, by definition, and only replace single ASCII
        // bytes with ASCII byte sequences
        Cow::Owned(unsafe { String::from_utf8_unchecked(output) })
    } else {
        lit.into()
    }
}

/// Escape an attribute value in a relative distinguished name (RDN).
///
/// When a literal string is used to represent an attribute value in an RDN,
/// some of it characters might need to be escaped according to the rules
/// of [RFC 4514](https://tools.ietf.org/html/rfc4514).
///
/// The function is named `dn_escape()` instead of `rdn_escape()` because of
/// a long-standing association of its intended use with the handling of DNs.
///
/// The argument, `val`, can be owned or borrowed. The function doesn't
/// allocate the return value unless there's need to escape the input.
pub fn dn_escape<'a, S: Into<Cow<'a, str>>>(val: S) -> Cow<'a, str> {
    #[inline]
    fn always_escape(c: u8) -> bool {
        c == b'"' || c == b'+' || c == b',' || c == b';' ||
        c == b'<' || c == b'=' || c == b'>' || c == b'\\' ||
        c == 0
    }

    #[inline]
    fn escape_leading(c: u8) -> bool {
        c == b' ' || c == b'#'
    }

    #[inline]
    fn escape_trailing(c: u8) -> bool {
        c == b' '
    }

    #[inline]
    fn xdigit(c: u8) -> u8 {
        c + if c < 10 { b'0' } else { b'a' - 10 }
    }

    let val = val.into();
    let mut output = None;
    for (i, &c) in val.as_bytes().iter().enumerate() {
        if always_escape(c) || i == 0 && escape_leading(c) || i + 1 == val.len() && escape_trailing(c) {
            if output.is_none() {
                output = Some(Vec::with_capacity(val.len() + 12)); // guess: up to 4 escaped chars
                output.as_mut().unwrap().extend(val[..i].as_bytes());
            }
            let output = output.as_mut().unwrap();
            output.push(b'\\');
            output.push(xdigit(c >> 4));
            output.push(xdigit(c & 0xF));
        } else if let Some(ref mut output) = output {
            output.push(c);
        }
    }
    if let Some(output) = output {
        // see the rationale for the same construct in ldap_escape()
        Cow::Owned(unsafe { String::from_utf8_unchecked(output) })
    } else {
        val.into()
    }
}
<commit_msg>Add tests for dn_escape()<commit_after>use std::borrow::Cow;

/// Escape a filter literal.
///
/// Literal values appearing in an LDAP filter can contain any character,
/// but some characters (parentheses, asterisk, backslash, NUL) must be
/// escaped in the filter's string representation. This function does the
/// escaping.
///
/// The argument, `lit`, can be owned or borrowed. The function doesn't
/// allocate the return value unless there's need to escape the input.
pub fn ldap_escape<'a, S: Into<Cow<'a, str>>>(lit: S) -> Cow<'a, str> {
    #[inline]
    fn needs_escape(c: u8) -> bool {
        c == b'\\' || c == b'*' || c == b'(' || c == b')' || c == 0
    }

    #[inline]
    fn xdigit(c: u8) -> u8 {
        c + if c < 10 { b'0' } else { b'a' - 10 }
    }

    let lit = lit.into();
    let mut output = None;
    for (i, &c) in lit.as_bytes().iter().enumerate() {
        if needs_escape(c) {
            if output.is_none() {
                output = Some(Vec::with_capacity(lit.len() + 12)); // guess: up to 4 escaped chars
                output.as_mut().unwrap().extend(lit[..i].as_bytes());
            }
            let output = output.as_mut().unwrap();
            output.push(b'\\');
            output.push(xdigit(c >> 4));
            output.push(xdigit(c & 0xF));
        } else if let Some(ref mut output) = output {
            output.push(c);
        }
    }
    if let Some(output) = output {
        // unchecked conversion is safe here: we receive a valid
        // UTF-8 value, by definition, and only replace single ASCII
        // bytes with ASCII byte sequences
        Cow::Owned(unsafe { String::from_utf8_unchecked(output) })
    } else {
        lit.into()
    }
}

/// Escape an attribute value in a relative distinguished name (RDN).
///
/// When a literal string is used to represent an attribute value in an RDN,
/// some of it characters might need to be escaped according to the rules
/// of [RFC 4514](https://tools.ietf.org/html/rfc4514).
///
/// The function is named `dn_escape()` instead of `rdn_escape()` because of
/// a long-standing association of its intended use with the handling of DNs.
///
/// The argument, `val`, can be owned or borrowed. The function doesn't
/// allocate the return value unless there's need to escape the input.
pub fn dn_escape<'a, S: Into<Cow<'a, str>>>(val: S) -> Cow<'a, str> {
    #[inline]
    fn always_escape(c: u8) -> bool {
        c == b'"' || c == b'+' || c == b',' || c == b';' ||
        c == b'<' || c == b'=' || c == b'>' || c == b'\\' ||
        c == 0
    }

    #[inline]
    fn escape_leading(c: u8) -> bool {
        c == b' ' || c == b'#'
    }

    #[inline]
    fn escape_trailing(c: u8) -> bool {
        c == b' '
    }

    #[inline]
    fn xdigit(c: u8) -> u8 {
        c + if c < 10 { b'0' } else { b'a' - 10 }
    }

    let val = val.into();
    let mut output = None;
    for (i, &c) in val.as_bytes().iter().enumerate() {
        if always_escape(c) || i == 0 && escape_leading(c) || i + 1 == val.len() && escape_trailing(c) {
            if output.is_none() {
                output = Some(Vec::with_capacity(val.len() + 12)); // guess: up to 4 escaped chars
                output.as_mut().unwrap().extend(val[..i].as_bytes());
            }
            let output = output.as_mut().unwrap();
            output.push(b'\\');
            output.push(xdigit(c >> 4));
            output.push(xdigit(c & 0xF));
        } else if let Some(ref mut output) = output {
            output.push(c);
        }
    }
    if let Some(output) = output {
        // see the rationale for the same construct in ldap_escape()
        Cow::Owned(unsafe { String::from_utf8_unchecked(output) })
    } else {
        val.into()
    }
}

#[cfg(test)]
mod test {
    use super::dn_escape;

    #[test]
    fn dn_esc_leading_space() {
        assert_eq!(dn_escape(" foo"), "\\20foo");
    }

    #[test]
    fn dn_esc_trailing_space() {
        assert_eq!(dn_escape("foo "), "foo\\20");
    }

    #[test]
    fn dn_esc_inner_space() {
        assert_eq!(dn_escape("f o o"), "f o o");
    }

    #[test]
    fn dn_esc_single_space() {
        assert_eq!(dn_escape(" "), "\\20");
    }

    #[test]
    fn dn_esc_two_spaces() {
        assert_eq!(dn_escape("  "), "\\20\\20");
    }

    #[test]
    fn dn_esc_three_spaces() {
        assert_eq!(dn_escape("   "), "\\20 \\20");
    }

    #[test]
    fn dn_esc_leading_hash() {
        assert_eq!(dn_escape("#rust"), "\\23rust");
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;

extern crate sliding_window;
use sliding_window::SliceRing;
use sliding_window::OptimizedSliceRing;

macro_rules! test_slice_ring {
    ($new:expr) => {{
        let mut testable = $new;

        let input = (0..10000).collect::<Vec<i32>>();
        testable.push_many_back(&input[..]);
        assert_eq!(testable.len(), 10000);
        assert_eq!(testable.capacity(), 16383);

        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        assert_eq!(testable.read_many_front(&mut output[..]), 1000);
        assert_eq!(output, (0..1000).collect::<Vec<i32>>());

        let mut output: Vec<i32> = std::iter::repeat(0).take(200).collect();
        assert_eq!(testable.read_many_front(&mut output[..]), 200);
        assert_eq!(output, (0..200).collect::<Vec<i32>>());

        assert_eq!(testable.drop_many_front(100), 100);
        assert_eq!(testable.len(), 9900);

        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        assert_eq!(testable.read_many_front(&mut output[..]), 1000);
        assert_eq!(output, (100..1100).collect::<Vec<i32>>());
    }};
}

#[test]
fn test_deque_slice_ring() {
    test_slice_ring!(VecDeque::<i32>::new());
}

#[test]
fn test_optimized_slice_ring() {
    test_slice_ring!(OptimizedSliceRing::<i32>::new());
}
// #[test]
// fn test_window_1_step_1() {
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(1, 1);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     let samples: Vec<i32> = vec![1];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let samples: Vec<i32> = vec![1, 2, 3];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 3);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 2);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![2]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![3]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//     assert!(!sliding_window.can_fill());
// }
//
// #[test]
// fn test_window_4_step_2() {
//     // 50% overlap
//
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(4, 2);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             calls += 1;
//         });
//         assert_eq!(calls, 0);
//         assert_eq!(window, vec![0, 0, 0, 0]);
//         assert_eq!(ring.len(), 3);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3, 4];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             assert_eq!(ring.len(), 2);
//             assert_eq!(window, vec![1, 2, 3, 4]);
//             calls += 1;
//         });
//         assert_eq!(calls, 1);
//         assert_eq!(window, vec![1, 2, 3, 4]);
//         assert_eq!(ring.len(), 2);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3 ,4, 5, 6, 7, 8, 9, 10, 11];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![1, 2, 3, 4]) },
//                 1 => { assert_eq!(window, vec![3, 4, 5, 6]) },
//                 2 => { assert_eq!(window, vec![5, 6, 7, 8]) },
//                 3 => { assert_eq!(window, vec![7, 8, 9, 10]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 4);
//         assert_eq!(window, vec![7, 8, 9, 10]);
//         assert_eq!(ring.len(), 3);
//
//         let samples: Vec<i32> = vec![12, 13, 14, 15, 16];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![9, 10, 11, 12]) },
//                 1 => { assert_eq!(window, vec![11, 12, 13, 14]) },
//                 2 => { assert_eq!(window, vec![13, 14, 15, 16]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 3);
//         assert_eq!(window, vec![13, 14, 15, 16]);
//         assert_eq!(ring.len(), 2);
//     }
// }
//
// #[test]
// fn test_window_1024_step_512() {
//     // 50% overlap
//     use std::collections::VecDeque;
//     use std::iter;
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0; 1024];
//         let samples: Vec<i32> =
//             iter::repeat(1).take(1024)
//             .chain(iter::repeat(2).take(1024))
//             .chain(iter::repeat(3).take(1024))
//             .chain(iter::repeat(4).take(1024))
//             .collect();
//         assert_eq!(samples.len(), 1024 * 4);
//         let mut calls = 0;
//         window!(512, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 1 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(512)
//                         .chain(iter::repeat(2).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 2 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 3 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(512)
//                         .chain(iter::repeat(3).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 4 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 5 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(512)
//                         .chain(iter::repeat(4).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 6 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(4).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 _ => {}
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 7);
//         assert_eq!(ring.len(), 512);
//     }
// }

// 4048 and 512
<commit_msg>update tests<commit_after>use std::collections::VecDeque;

extern crate sliding_window;
use sliding_window::SliceRing;
use sliding_window::OptimizedSliceRing;

macro_rules! test_slice_ring {
    ($new:expr) => {{
        let mut testable = $new;

        let input = (0..3000).collect::<Vec<i32>>();
        testable.push_many_back(&input[..]);
        assert_eq!(testable.len(), 3000);
        assert_eq!(testable.capacity(), 4095);

        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        assert_eq!(testable.read_many_front(&mut output[..]), 1000);
        assert_eq!(output, (0..1000).collect::<Vec<i32>>());

        let mut output: Vec<i32> = std::iter::repeat(0).take(200).collect();
        assert_eq!(testable.read_many_front(&mut output[..]), 200);
        assert_eq!(output, (0..200).collect::<Vec<i32>>());

        assert_eq!(testable.drop_many_front(100), 100);
        assert_eq!(testable.len(), 2900);

        let mut output: Vec<i32> = std::iter::repeat(0).take(1000).collect();
        assert_eq!(testable.read_many_front(&mut output[..]), 1000);
        assert_eq!(output, (100..1100).collect::<Vec<i32>>());
    }};
}

#[test]
fn test_deque_slice_ring() {
    test_slice_ring!(VecDeque::<i32>::new());
}

#[test]
fn test_optimized_slice_ring() {
    test_slice_ring!(OptimizedSliceRing::<i32>::new());
}
// #[test]
// fn test_window_1_step_1() {
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(1, 1);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     let samples: Vec<i32> = vec![1];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let samples: Vec<i32> = vec![1, 2, 3];
//     sliding_window.write(&samples[..]);
//     assert_eq!(sliding_window.ringbuffer.len(), 3);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![1]);
//     assert_eq!(sliding_window.ringbuffer.len(), 2);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![2]);
//     assert_eq!(sliding_window.ringbuffer.len(), 1);
//
//     assert!(sliding_window.can_fill());
//     assert!(sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![3]);
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//     assert!(!sliding_window.can_fill());
// }
//
// #[test]
// fn test_window_4_step_2() {
//     // 50% overlap
//
//     let mut sliding_window: SlidingWindow<i32> = SlidingWindow::new(4, 2);
//     assert!(!sliding_window.can_fill());
//     let samples: Vec<i32> = vec![];
//     sliding_window.write(&samples[..]);
//     assert!(!sliding_window.can_fill());
//     assert_eq!(sliding_window.ringbuffer.len(), 0);
//
//     let mut window: Vec<i32> = vec![0];
//     assert!(!sliding_window.read(&mut window[..]));
//     assert_eq!(window, vec![0]);
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             calls += 1;
//         });
//         assert_eq!(calls, 0);
//         assert_eq!(window, vec![0, 0, 0, 0]);
//         assert_eq!(ring.len(), 3);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3, 4];
//         // println!("samples {:?}", samples);
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             assert_eq!(ring.len(), 2);
//             assert_eq!(window, vec![1, 2, 3, 4]);
//             calls += 1;
//         });
//         assert_eq!(calls, 1);
//         assert_eq!(window, vec![1, 2, 3, 4]);
//         assert_eq!(ring.len(), 2);
//     }
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0, 0, 0, 0];
//         let samples: Vec<i32> = vec![1, 2, 3 ,4, 5, 6, 7, 8, 9, 10, 11];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![1, 2, 3, 4]) },
//                 1 => { assert_eq!(window, vec![3, 4, 5, 6]) },
//                 2 => { assert_eq!(window, vec![5, 6, 7, 8]) },
//                 3 => { assert_eq!(window, vec![7, 8, 9, 10]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 4);
//         assert_eq!(window, vec![7, 8, 9, 10]);
//         assert_eq!(ring.len(), 3);
//
//         let samples: Vec<i32> = vec![12, 13, 14, 15, 16];
//         let mut calls = 0;
//         window!(2, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => { assert_eq!(window, vec![9, 10, 11, 12]) },
//                 1 => { assert_eq!(window, vec![11, 12, 13, 14]) },
//                 2 => { assert_eq!(window, vec![13, 14, 15, 16]) },
//                 _ => { assert!(false) },
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 3);
//         assert_eq!(window, vec![13, 14, 15, 16]);
//         assert_eq!(ring.len(), 2);
//     }
// }
//
// #[test]
// fn test_window_1024_step_512() {
//     // 50% overlap
//     use std::collections::VecDeque;
//     use std::iter;
//
//     {
//         let mut ring: VecDeque<i32> = VecDeque::new();
//         let mut window: Vec<i32> = vec![0; 1024];
//         let samples: Vec<i32> =
//             iter::repeat(1).take(1024)
//             .chain(iter::repeat(2).take(1024))
//             .chain(iter::repeat(3).take(1024))
//             .chain(iter::repeat(4).take(1024))
//             .collect();
//         assert_eq!(samples.len(), 1024 * 4);
//         let mut calls = 0;
//         window!(512, ring, &samples[..], &mut window[..], {
//             match calls {
//                 0 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 1 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(1).take(512)
//                         .chain(iter::repeat(2).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 2 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 3 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(2).take(512)
//                         .chain(iter::repeat(3).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 4 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 5 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(3).take(512)
//                         .chain(iter::repeat(4).take(512))
//                         .collect::<Vec<i32>>()
//                     );
//                 },
//                 6 => {
//                     assert_eq!(
//                         window,
//                         iter::repeat(4).take(1024).collect::<Vec<i32>>()
//                     );
//                 },
//                 _ => {}
//             }
//             calls += 1;
//         });
//         assert_eq!(calls, 7);
//         assert_eq!(ring.len(), 512);
//     }
// }

// 4048 and 512
<|endoftext|>


<commit_before>use line::Line;
use update::Update;

pub struct View {
    last_rev: u64,
    filepath: String,
    lines: Vec<Line>,
}

impl View {
    pub fn update(&mut self, update: &Update) {
        if self.last_rev > update.rev {
            return;
        }
        let mut lines = vec![];
        let mut index = 0;

        for op in update.ops.iter() {
            index = op.apply(&self.lines, index, &mut lines);
        }

        self.last_rev = update.rev;
        self.lines = lines;
    }
}
<commit_msg>Makes a View's filepath public and derives Clone<commit_after>use line::Line;
use update::Update;

#[derive(Clone)]
pub struct View {
    last_rev: u64,
    pub filepath: String,
    lines: Vec<Line>,
}

impl View {
    pub fn update(&mut self, update: &Update) {
        if self.last_rev > update.rev {
            return;
        }
        let mut lines = vec![];
        let mut index = 0;

        for op in update.ops.iter() {
            index = op.apply(&self.lines, index, &mut lines);
        }

        self.last_rev = update.rev;
        self.lines = lines;
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::{self, Read, Write};

use sha1::Sha1;
use parity_wasm;
use cargo_shim::BuildConfig;
use serde_json;

use wasm_gc;

use wasm_context::Context;
use wasm_inline_js;
use wasm_export_main;
use wasm_export_table;
use wasm_hook_grow;
use wasm_intrinsics;
use wasm_runtime::{self, RuntimeKind};
use wasm_js_export;
use wasm_js_snippet;

#[derive(Serialize, Deserialize)]
struct Metadata {
    wasm_hash: String
}

fn get_sha1sum< P: AsRef< Path > >( path: P ) -> io::Result< String > {
    let path = path.as_ref();
    let mut fp = File::open( path )?;
    let mut hasher = Sha1::new();

    let mut buffer = Vec::new();
    buffer.resize( 1024 * 1024, 0 );
    loop {
        match fp.read( &mut buffer )? {
            0 => break,
            count => hasher.update( &buffer[ 0..count ] )
        }
    }

    Ok( format!( "{}", hasher.digest() ) )
}

pub fn process_wasm_file< P: AsRef< Path > + ?Sized >( uses_old_stdweb: bool, runtime: RuntimeKind, build: &BuildConfig, prepend_js: &str, target_dir: &Path, artifact: &P ) -> Option< PathBuf > {
    if !build.triplet.as_ref().map( |triplet| triplet == "wasm32-unknown-unknown" ).unwrap_or( false ) {
        return None;
    }

    let path = artifact.as_ref();
    if !path.extension().map( |ext| ext == "wasm" ).unwrap_or( false ) {
        return None;
    }

    if !uses_old_stdweb {
        new_process_wasm_file( runtime, prepend_js, target_dir, path )
    } else {
        old_process_wasm_file( runtime, prepend_js, path )
    }
}

fn new_process_wasm_file( runtime: RuntimeKind, prepend_js: &str, target_dir: &Path, path: &Path ) -> Option< PathBuf > {
    eprintln!( "    Processing {:?}...", path.file_name().unwrap() );

    let mut module = parity_wasm::deserialize_file( &path ).unwrap();
    let mut ctx = Context::from_module( module );
    let snippets = wasm_js_snippet::process( target_dir, &mut ctx );
    let intrinsics = wasm_intrinsics::process( &mut ctx );
    let main_symbol = wasm_export_main::process( &mut ctx );
    let exports = wasm_js_export::process( &mut ctx );
    wasm_export_main::process( &mut ctx );
    wasm_export_table::process( &mut ctx );
    wasm_hook_grow::process( &mut ctx );
    module = ctx.into_module();

    parity_wasm::serialize_to_file( path, module ).unwrap();

    let mut all_snippets: Vec< _ > = snippets.into_iter().chain( intrinsics.into_iter() ).collect();
    all_snippets.sort_by( |a, b| a.name.cmp( &b.name ) );

    let js_path = path.with_extension( "js" );
    let js = wasm_runtime::generate_js( runtime, main_symbol, path, prepend_js, &all_snippets, &exports );
    let mut fp = File::create( &js_path ).unwrap();
    fp.write_all( js.as_bytes() ).unwrap();

    eprintln!( "    Finished processing of {:?}!", path.file_name().unwrap() );
    Some( js_path )

}

fn old_process_wasm_file( runtime: RuntimeKind, prepend_js: &str, path: &Path ) -> Option< PathBuf > {
    let wasm_hash = get_sha1sum( path ).expect( "cannot calculate sha1sum of the `.wasm` file" );
    debug!( "Hash of {:?}: {}", path, wasm_hash );

    let js_path = path.with_extension( "js" );
    let metadata_path = path.with_extension( "cargoweb-metadata" );
    if js_path.exists() && metadata_path.exists() {
        // TODO: This is just a quick workaround. We should always regenerate the `.js` file.
        let fp = File::open( &metadata_path ).expect( "cannot open the metadata file" );
        let metadata: Metadata = serde_json::from_reader( fp ).expect( "cannot deserialize metadata; delete your `target` directory" );
        if metadata.wasm_hash == wasm_hash {
            debug!( "Skipping `.js` generation and `.wasm` processing!" );
            return Some( js_path );
        }
    }

    eprintln!( "    Garbage collecting {:?}...", path.file_name().unwrap() );
    wasm_gc::run( &path, &path );

    eprintln!( "    Processing {:?}...", path.file_name().unwrap() );
    let mut module = parity_wasm::deserialize_file( &path ).unwrap();
    let mut ctx = Context::from_module( module );
    let snippets = wasm_inline_js::process_and_extract( &mut ctx );
    let intrinsics = wasm_intrinsics::process( &mut ctx );
    let main_symbol = wasm_export_main::process( &mut ctx );
    let exports = wasm_js_export::process( &mut ctx );
    wasm_export_main::process( &mut ctx );
    wasm_export_table::process( &mut ctx );
    wasm_hook_grow::process( &mut ctx );
    module = ctx.into_module();

    // At least on Linux when a `.wasm` file is built it's
    // hard-linked from two places:
    //    1) target/wasm32-unknown-unknown/release/$name.wasm
    //    2) target/wasm32-unknown-unknown/release/deps/$name.wasm
    //
    // If you trigger a `cargo build` in a case where your project
    // doesn't need to be rebuilt it will just recreate
    // the `deps/$name.wasm` -> `$name.wasm` hard-link
    // and report that the file was rebuilt. (Even though it wasn't!)
    //
    // This wouldn't normally be a problem, however since we
    // modify the `.wasm` file we end up modifying *both* of
    // them which breaks any subsequent builds.
    //
    // So we forcefully remove the `$name.wasm` here before
    // overwriting it to get rid of the hard-link.
    let _ = fs::remove_file( path );

    parity_wasm::serialize_to_file( path, module ).unwrap();

    let mut all_snippets: Vec< _ > = snippets.into_iter().chain( intrinsics.into_iter() ).collect();

    all_snippets.sort_by( |a, b| a.name.cmp( &b.name ) );

    let js = wasm_runtime::generate_js( runtime, main_symbol, path, prepend_js, &all_snippets, &exports );
    let mut fp = File::create( &js_path ).unwrap();
    fp.write_all( js.as_bytes() ).unwrap();

    let new_wasm_hash = get_sha1sum( path ).expect( "cannot calculate sha1sum of the `.wasm` file" );
    debug!( "New hash of {:?}: {}", path, new_wasm_hash );

    let fp = File::create( &metadata_path ).unwrap();
    serde_json::to_writer( fp, &Metadata { wasm_hash: new_wasm_hash } ).unwrap();

    eprintln!( "    Finished processing of {:?}!", path.file_name().unwrap() );
    Some( js_path )
}
<commit_msg>Delete the `.wasm` file before overwriting<commit_after>use std::path::{Path, PathBuf};
use std::fs::{self, File};
use std::io::{self, Read, Write};

use sha1::Sha1;
use parity_wasm;
use cargo_shim::BuildConfig;
use serde_json;

use wasm_gc;

use wasm_context::Context;
use wasm_inline_js;
use wasm_export_main;
use wasm_export_table;
use wasm_hook_grow;
use wasm_intrinsics;
use wasm_runtime::{self, RuntimeKind};
use wasm_js_export;
use wasm_js_snippet;

#[derive(Serialize, Deserialize)]
struct Metadata {
    wasm_hash: String
}

fn get_sha1sum< P: AsRef< Path > >( path: P ) -> io::Result< String > {
    let path = path.as_ref();
    let mut fp = File::open( path )?;
    let mut hasher = Sha1::new();

    let mut buffer = Vec::new();
    buffer.resize( 1024 * 1024, 0 );
    loop {
        match fp.read( &mut buffer )? {
            0 => break,
            count => hasher.update( &buffer[ 0..count ] )
        }
    }

    Ok( format!( "{}", hasher.digest() ) )
}

pub fn process_wasm_file< P: AsRef< Path > + ?Sized >( uses_old_stdweb: bool, runtime: RuntimeKind, build: &BuildConfig, prepend_js: &str, target_dir: &Path, artifact: &P ) -> Option< PathBuf > {
    if !build.triplet.as_ref().map( |triplet| triplet == "wasm32-unknown-unknown" ).unwrap_or( false ) {
        return None;
    }

    let path = artifact.as_ref();
    if !path.extension().map( |ext| ext == "wasm" ).unwrap_or( false ) {
        return None;
    }

    if !uses_old_stdweb {
        new_process_wasm_file( runtime, prepend_js, target_dir, path )
    } else {
        old_process_wasm_file( runtime, prepend_js, path )
    }
}

fn new_process_wasm_file( runtime: RuntimeKind, prepend_js: &str, target_dir: &Path, path: &Path ) -> Option< PathBuf > {
    eprintln!( "    Processing {:?}...", path.file_name().unwrap() );

    let mut module = parity_wasm::deserialize_file( &path ).unwrap();
    let mut ctx = Context::from_module( module );
    let snippets = wasm_js_snippet::process( target_dir, &mut ctx );
    let intrinsics = wasm_intrinsics::process( &mut ctx );
    let main_symbol = wasm_export_main::process( &mut ctx );
    let exports = wasm_js_export::process( &mut ctx );
    wasm_export_main::process( &mut ctx );
    wasm_export_table::process( &mut ctx );
    wasm_hook_grow::process( &mut ctx );
    module = ctx.into_module();

    // TODO: Remove this once we stop losing information when we process the `.wasm` file.
    //       (That is - migrate the `#[js_export]` macro to use another mechanism.)
    let _ = fs::remove_file( path );

    parity_wasm::serialize_to_file( path, module ).unwrap();

    let mut all_snippets: Vec< _ > = snippets.into_iter().chain( intrinsics.into_iter() ).collect();
    all_snippets.sort_by( |a, b| a.name.cmp( &b.name ) );

    let js_path = path.with_extension( "js" );
    let js = wasm_runtime::generate_js( runtime, main_symbol, path, prepend_js, &all_snippets, &exports );
    let mut fp = File::create( &js_path ).unwrap();
    fp.write_all( js.as_bytes() ).unwrap();

    eprintln!( "    Finished processing of {:?}!", path.file_name().unwrap() );
    Some( js_path )

}

fn old_process_wasm_file( runtime: RuntimeKind, prepend_js: &str, path: &Path ) -> Option< PathBuf > {
    let wasm_hash = get_sha1sum( path ).expect( "cannot calculate sha1sum of the `.wasm` file" );
    debug!( "Hash of {:?}: {}", path, wasm_hash );

    let js_path = path.with_extension( "js" );
    let metadata_path = path.with_extension( "cargoweb-metadata" );
    if js_path.exists() && metadata_path.exists() {
        // TODO: This is just a quick workaround. We should always regenerate the `.js` file.
        let fp = File::open( &metadata_path ).expect( "cannot open the metadata file" );
        let metadata: Metadata = serde_json::from_reader( fp ).expect( "cannot deserialize metadata; delete your `target` directory" );
        if metadata.wasm_hash == wasm_hash {
            debug!( "Skipping `.js` generation and `.wasm` processing!" );
            return Some( js_path );
        }
    }

    eprintln!( "    Garbage collecting {:?}...", path.file_name().unwrap() );
    wasm_gc::run( &path, &path );

    eprintln!( "    Processing {:?}...", path.file_name().unwrap() );
    let mut module = parity_wasm::deserialize_file( &path ).unwrap();
    let mut ctx = Context::from_module( module );
    let snippets = wasm_inline_js::process_and_extract( &mut ctx );
    let intrinsics = wasm_intrinsics::process( &mut ctx );
    let main_symbol = wasm_export_main::process( &mut ctx );
    let exports = wasm_js_export::process( &mut ctx );
    wasm_export_main::process( &mut ctx );
    wasm_export_table::process( &mut ctx );
    wasm_hook_grow::process( &mut ctx );
    module = ctx.into_module();

    // At least on Linux when a `.wasm` file is built it's
    // hard-linked from two places:
    //    1) target/wasm32-unknown-unknown/release/$name.wasm
    //    2) target/wasm32-unknown-unknown/release/deps/$name.wasm
    //
    // If you trigger a `cargo build` in a case where your project
    // doesn't need to be rebuilt it will just recreate
    // the `deps/$name.wasm` -> `$name.wasm` hard-link
    // and report that the file was rebuilt. (Even though it wasn't!)
    //
    // This wouldn't normally be a problem, however since we
    // modify the `.wasm` file we end up modifying *both* of
    // them which breaks any subsequent builds.
    //
    // So we forcefully remove the `$name.wasm` here before
    // overwriting it to get rid of the hard-link.
    let _ = fs::remove_file( path );

    parity_wasm::serialize_to_file( path, module ).unwrap();

    let mut all_snippets: Vec< _ > = snippets.into_iter().chain( intrinsics.into_iter() ).collect();

    all_snippets.sort_by( |a, b| a.name.cmp( &b.name ) );

    let js = wasm_runtime::generate_js( runtime, main_symbol, path, prepend_js, &all_snippets, &exports );
    let mut fp = File::create( &js_path ).unwrap();
    fp.write_all( js.as_bytes() ).unwrap();

    let new_wasm_hash = get_sha1sum( path ).expect( "cannot calculate sha1sum of the `.wasm` file" );
    debug!( "New hash of {:?}: {}", path, new_wasm_hash );

    let fp = File::create( &metadata_path ).unwrap();
    serde_json::to_writer( fp, &Metadata { wasm_hash: new_wasm_hash } ).unwrap();

    eprintln!( "    Finished processing of {:?}!", path.file_name().unwrap() );
    Some( js_path )
}
<|endoftext|>


<commit_before>
import str::sbuf;
import vec::vbuf;

export program;
export run_program;
export start_program;
export program_output;

native "rust" mod rustrt {
    fn rust_run_program(vbuf argv, int in_fd, int out_fd, int err_fd) -> int;
}

fn arg_vec(str prog, vec[str] args) -> vec[sbuf] {
    auto argptrs = [str::buf(prog)];
    for (str arg in args) { vec::push[sbuf](argptrs, str::buf(arg)); }
    vec::push[sbuf](argptrs, 0 as sbuf);
    ret argptrs;
}

fn spawn_process(str prog, vec[str] args,
                 int in_fd, int out_fd, int err_fd) -> int {
    // Note: we have to hold on to this vector reference while we hold a
    // pointer to its buffer
    auto argv = arg_vec(prog, args);
    auto pid = rustrt::rust_run_program(vec::buf(argv),
                                        in_fd, out_fd, err_fd);
    ret pid;
}

fn run_program(str prog, vec[str] args) -> int {
    ret os::waitpid(spawn_process(prog, args, 0, 0, 0));
}

type program =
    obj {
        fn get_id() -> int ;
        fn input() -> io::writer ;
        fn output() -> io::reader ;
        fn close_input() ;
        fn finish() -> int ;
    };

fn start_program(str prog, vec[str] args) -> @program {
    auto pipe_input = os::pipe();
    auto pipe_output = os::pipe();
    auto pid = spawn_process(prog, args, pipe_input._0, pipe_output._1, 0);

    if (pid == -1) { fail; }
    os::libc::close(pipe_input._0);
    os::libc::close(pipe_output._1);
    obj new_program(int pid,
                    int in_fd,
                    os::libc::FILE out_file,
                    mutable bool finished) {
        fn get_id() -> int { ret pid; }
        fn input() -> io::writer {
            ret io::new_writer(io::fd_buf_writer(in_fd, false));
        }
        fn output() -> io::reader {
            ret io::new_reader(io::FILE_buf_reader(out_file, false));
        }
        fn close_input() { os::libc::close(in_fd); }
        fn finish() -> int {
            if (finished) { ret 0; }
            finished = true;
            os::libc::close(in_fd);
            ret os::waitpid(pid);
        }drop {
             if (!finished) { os::libc::close(in_fd); os::waitpid(pid); }
             os::libc::fclose(out_file);
         }
    }
    ret @new_program(pid, pipe_input._1, os::fd_FILE(pipe_output._0), false);
}

fn program_output(str prog, vec[str] args) -> rec(int status, str out) {
    auto pr = start_program(prog, args);
    pr.close_input();
    auto out = pr.output();
    auto buf = "";
    while (!out.eof()) {
        auto bytes = out.read_bytes(4096u);
        buf += str::unsafe_from_bytes(bytes);
    }
    ret rec(status=pr.finish(), out=buf);
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Avoid double-closing pipes in std::run::start_program<commit_after>
import str::sbuf;
import vec::vbuf;

export program;
export run_program;
export start_program;
export program_output;

native "rust" mod rustrt {
    fn rust_run_program(vbuf argv, int in_fd, int out_fd, int err_fd) -> int;
}

fn arg_vec(str prog, vec[str] args) -> vec[sbuf] {
    auto argptrs = [str::buf(prog)];
    for (str arg in args) { vec::push[sbuf](argptrs, str::buf(arg)); }
    vec::push[sbuf](argptrs, 0 as sbuf);
    ret argptrs;
}

fn spawn_process(str prog, vec[str] args,
                 int in_fd, int out_fd, int err_fd) -> int {
    // Note: we have to hold on to this vector reference while we hold a
    // pointer to its buffer
    auto argv = arg_vec(prog, args);
    auto pid = rustrt::rust_run_program(vec::buf(argv),
                                        in_fd, out_fd, err_fd);
    ret pid;
}

fn run_program(str prog, vec[str] args) -> int {
    ret os::waitpid(spawn_process(prog, args, 0, 0, 0));
}

type program =
    obj {
        fn get_id() -> int ;
        fn input() -> io::writer ;
        fn output() -> io::reader ;
        fn close_input() ;
        fn finish() -> int ;
    };

fn start_program(str prog, vec[str] args) -> @program {
    auto pipe_input = os::pipe();
    auto pipe_output = os::pipe();
    auto pid = spawn_process(prog, args, pipe_input._0, pipe_output._1, 0);

    if (pid == -1) { fail; }
    os::libc::close(pipe_input._0);
    os::libc::close(pipe_output._1);
    obj new_program(int pid,
                    mutable int in_fd,
                    os::libc::FILE out_file,
                    mutable bool finished) {
        fn get_id() -> int { ret pid; }
        fn input() -> io::writer {
            ret io::new_writer(io::fd_buf_writer(in_fd, false));
        }
        fn output() -> io::reader {
            ret io::new_reader(io::FILE_buf_reader(out_file, false));
        }
        fn close_input() {
            auto invalid_fd = -1;
            if (in_fd != invalid_fd) {
                os::libc::close(in_fd);
                in_fd = invalid_fd;
            }
        }
        fn finish() -> int {
            if (finished) { ret 0; }
            finished = true;
            self.close_input();
            ret os::waitpid(pid);
        }drop {
            self.close_input();
            if (!finished) {
                os::waitpid(pid);
            }
             os::libc::fclose(out_file);
         }
    }
    ret @new_program(pid, pipe_input._1, os::fd_FILE(pipe_output._0), false);
}

fn program_output(str prog, vec[str] args) -> rec(int status, str out) {
    auto pr = start_program(prog, args);
    pr.close_input();
    auto out = pr.output();
    auto buf = "";
    while (!out.eof()) {
        auto bytes = out.read_bytes(4096u);
        buf += str::unsafe_from_bytes(bytes);
    }
    ret rec(status=pr.finish(), out=buf);
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>