<commit_before>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::process::exit;
use std::fs::File;
use std::io::Write;
use std::time::Duration;
use std::path::PathBuf;
use libc::fork;
use time;
use docbuilder::RustwideBuilder;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

pub fn start_daemon(background: bool) {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect(&format!("Environment variable {} not found", v));
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    if background {
        // fork the process
        let pid = unsafe { fork() };
        if pid > 0 {
            let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
                .expect("Failed to create pid file");
            writeln!(&mut file, "{}", pid).expect("Failed to write pid");

            info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
            exit(0);
        }
    }

    // check new crates every minute
    thread::Builder::new().name("crates.io reader".to_string()).spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            if doc_builder.is_locked() {
                debug!("Lock file exists, skipping checking new crates");
            } else {
                debug!("Checking new crates");
                match doc_builder.get_new_crates() {
                    Ok(n) => debug!("{} crates added to queue", n),
                    Err(e) => error!("Failed to get new crates: {}", e),
                }
            }

            thread::sleep(Duration::from_secs(60));
        }
    }).unwrap();

    // build new crates every minute
    thread::Builder::new().name("build queue reader".to_string()).spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut builder = RustwideBuilder::init().unwrap();

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.count() > 0 {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package(&mut builder) {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    }).unwrap();

    // update release activity everyday at 23:55
    thread::Builder::new().name("release activity updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    }).unwrap();

    // update search index every 3 hours
    thread::Builder::new().name("search index updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    }).unwrap();

    // update github stats every 6 hours
    thread::Builder::new().name("github stat updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    }).unwrap();

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::Server::start(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<commit_msg>Only use fork on non-windows OS<commit_after>//! Simple daemon
//!
//! This daemon will start web server, track new packages and build them

use std::{env, thread};
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::time::Duration;
use std::path::PathBuf;
use time;
use docbuilder::RustwideBuilder;
use DocBuilderOptions;
use DocBuilder;
use utils::{update_release_activity, github_updater, pubsubhubbub};
use db::{connect_db, update_search_index};

#[cfg(not(target_os = "windows"))]
use ::{
    libc::fork,
    std::process::exit,
    std::fs::File,
    std::io::Write
};

pub fn start_daemon(background: bool) {
    // first check required environment variables
    for v in ["CRATESFYI_PREFIX",
              "CRATESFYI_PREFIX",
              "CRATESFYI_GITHUB_USERNAME",
              "CRATESFYI_GITHUB_ACCESSTOKEN"]
        .iter() {
        env::var(v).expect(&format!("Environment variable {} not found", v));
    }

    let dbopts = opts();

    // check paths once
    dbopts.check_paths().unwrap();

    if background {
        #[cfg(target_os = "windows")]
        {
            panic!("running in background not supported on windows");
        }
        #[cfg(not(target_os = "windows"))]
        {
            // fork the process
            let pid = unsafe { fork() };
            if pid > 0 {
                let mut file = File::create(dbopts.prefix.join("cratesfyi.pid"))
                    .expect("Failed to create pid file");
                writeln!(&mut file, "{}", pid).expect("Failed to write pid");

                info!("cratesfyi {} daemon started on: {}", ::BUILD_VERSION, pid);
                exit(0);
            }
        }
    }

    // check new crates every minute
    thread::Builder::new().name("crates.io reader".to_string()).spawn(move || {
        // space this out to prevent it from clashing against the queue-builder thread on launch
        thread::sleep(Duration::from_secs(30));
        loop {
            let opts = opts();
            let mut doc_builder = DocBuilder::new(opts);

            if doc_builder.is_locked() {
                debug!("Lock file exists, skipping checking new crates");
            } else {
                debug!("Checking new crates");
                match doc_builder.get_new_crates() {
                    Ok(n) => debug!("{} crates added to queue", n),
                    Err(e) => error!("Failed to get new crates: {}", e),
                }
            }

            thread::sleep(Duration::from_secs(60));
        }
    }).unwrap();

    // build new crates every minute
    thread::Builder::new().name("build queue reader".to_string()).spawn(move || {
        let opts = opts();
        let mut doc_builder = DocBuilder::new(opts);

        /// Represents the current state of the builder thread.
        enum BuilderState {
            /// The builder thread has just started, and hasn't built any crates yet.
            Fresh,
            /// The builder has just seen an empty build queue.
            EmptyQueue,
            /// The builder has just seen the lock file.
            Locked,
            /// The builder has just finished building a crate. The enclosed count is the number of
            /// crates built since the caches have been refreshed.
            QueueInProgress(usize),
        }

        let mut builder = RustwideBuilder::init().unwrap();

        let mut status = BuilderState::Fresh;

        loop {
            if !status.is_in_progress() {
                thread::sleep(Duration::from_secs(60));
            }

            // check lock file
            if doc_builder.is_locked() {
                warn!("Lock file exits, skipping building new crates");
                status = BuilderState::Locked;
                continue;
            }

            if status.count() >= 10 {
                // periodically, we need to flush our caches and ping the hubs
                debug!("10 builds in a row; flushing caches");
                status = BuilderState::QueueInProgress(0);

                match pubsubhubbub::ping_hubs() {
                    Err(e) => error!("Failed to ping hub: {}", e),
                    Ok(n) => debug!("Succesfully pinged {} hubs", n)
                }

                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                }

                if let Err(e) = doc_builder.save_cache() {
                    error!("Failed to save cache: {}", e);
                }
            }

            // Only build crates if there are any to build
            debug!("Checking build queue");
            match doc_builder.get_queue_count() {
                Err(e) => {
                    error!("Failed to read the number of crates in the queue: {}", e);
                    continue;
                }
                Ok(0) => {
                    if status.count() > 0 {
                        // ping the hubs before continuing
                        match pubsubhubbub::ping_hubs() {
                            Err(e) => error!("Failed to ping hub: {}", e),
                            Ok(n) => debug!("Succesfully pinged {} hubs", n)
                        }

                        if let Err(e) = doc_builder.save_cache() {
                            error!("Failed to save cache: {}", e);
                        }
                    }
                    debug!("Queue is empty, going back to sleep");
                    status = BuilderState::EmptyQueue;
                    continue;
                }
                Ok(queue_count) => {
                    info!("Starting build with {} crates in queue (currently on a {} crate streak)",
                          queue_count, status.count());
                }
            }

            // if we're starting a new batch, reload our caches and sources
            if !status.is_in_progress() {
                if let Err(e) = doc_builder.load_cache() {
                    error!("Failed to load cache: {}", e);
                    continue;
                }
            }

            // Run build_packages_queue under `catch_unwind` to catch panics
            // This only panicked twice in the last 6 months but its just a better
            // idea to do this.
            let res = catch_unwind(AssertUnwindSafe(|| {
                match doc_builder.build_next_queue_package(&mut builder) {
                    Err(e) => error!("Failed to build crate from queue: {}", e),
                    Ok(crate_built) => if crate_built {
                        status.increment();
                    }

                }
            }));

            if let Err(e) = res {
                error!("GRAVE ERROR Building new crates panicked: {:?}", e);
            }
        }

        impl BuilderState {
            fn count(&self) -> usize {
                match *self {
                    BuilderState::QueueInProgress(n) => n,
                    _ => 0,
                }
            }

            fn is_in_progress(&self) -> bool {
                match *self {
                    BuilderState::QueueInProgress(_) => true,
                    _ => false,
                }
            }

            fn increment(&mut self) {
                *self = BuilderState::QueueInProgress(self.count() + 1);
            }
        }
    }).unwrap();

    // update release activity everyday at 23:55
    thread::Builder::new().name("release activity updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60));
            let now = time::now();
            if now.tm_hour == 23 && now.tm_min == 55 {
                info!("Updating release activity");
                if let Err(e) = update_release_activity() {
                    error!("Failed to update release activity: {}", e);
                }
            }
        }
    }).unwrap();

    // update search index every 3 hours
    thread::Builder::new().name("search index updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 3));
            let conn = connect_db().expect("Failed to connect database");
            if let Err(e) = update_search_index(&conn) {
                error!("Failed to update search index: {}", e);
            }
        }
    }).unwrap();

    // update github stats every 6 hours
    thread::Builder::new().name("github stat updater".to_string()).spawn(move || {
        loop {
            thread::sleep(Duration::from_secs(60 * 60 * 6));
            if let Err(e) = github_updater() {
                error!("Failed to update github fields: {}", e);
            }
        }
    }).unwrap();

    // TODO: update ssl certificate every 3 months

    // at least start web server
    info!("Starting web server");
    ::Server::start(None);
}

fn opts() -> DocBuilderOptions {
    let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX")
        .expect("CRATESFYI_PREFIX environment variable not found"));
    DocBuilderOptions::from_prefix(prefix)
}
<|endoftext|>


<commit_before>//! The preprocessing we apply to doc comments.
//!
//! #[derive(Parser)] works in terms of "paragraphs". Paragraph is a sequence of
//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines.

use crate::item::Method;

use quote::{format_ident, quote};
use std::iter;

pub fn process_doc_comment(
    lines: Vec<String>,
    name: &str,
    preprocess: bool,
) -> (Option<Method>, Option<Method>) {
    // multiline comments (`/** ... */`) may have LFs (`\n`) in them,
    // we need to split so we could handle the lines correctly
    //
    // we also need to remove leading and trailing blank lines
    let mut lines: Vec<&str> = lines
        .iter()
        .skip_while(|s| is_blank(s))
        .flat_map(|s| s.split('\n'))
        .collect();

    while let Some(true) = lines.last().map(|s| is_blank(s)) {
        lines.pop();
    }

    if lines.is_empty() {
        return (None, None);
    }

    // remove one leading space no matter what
    for line in lines.iter_mut() {
        if line.starts_with(' ') {
            *line = &line[1..];
        }
    }

    let short_name = format_ident!("{}", name);
    let long_name = format_ident!("long_{}", name);

    if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) {
        let (short, long) = if preprocess {
            let paragraphs = split_paragraphs(&lines);
            let short = paragraphs[0].clone();
            let long = paragraphs.join("\n\n");
            (remove_period(short), long)
        } else {
            let short = lines[..first_blank].join("\n");
            let long = lines.join("\n");
            (short, long)
        };

        (
            Some(Method::new(short_name, quote!(#short))),
            Some(Method::new(long_name, quote!(#long))),
        )
    } else {
        let short = if preprocess {
            let s = merge_lines(&lines);
            remove_period(s)
        } else {
            lines.join("\n")
        };

        (
            Some(Method::new(short_name, quote!(#short))),
            Some(Method::new(long_name, quote!(None))),
        )
    }
}

fn split_paragraphs(lines: &[&str]) -> Vec<String> {
    let mut last_line = 0;
    iter::from_fn(|| {
        let slice = &lines[last_line..];
        let start = slice.iter().position(|s| !is_blank(s)).unwrap_or(0);

        let slice = &slice[start..];
        let len = slice
            .iter()
            .position(|s| is_blank(s))
            .unwrap_or(slice.len());

        last_line += start + len;

        if len != 0 {
            Some(merge_lines(&slice[..len]))
        } else {
            None
        }
    })
    .collect()
}

fn remove_period(mut s: String) -> String {
    if s.ends_with('.') && !s.ends_with("..") {
        s.pop();
    }
    s
}

fn is_blank(s: &str) -> bool {
    s.trim().is_empty()
}

fn merge_lines(lines: &[&str]) -> String {
    lines.iter().map(|s| s.trim()).collect::<Vec<_>>().join(" ")
}
<commit_msg>refactor(derive): Clarify leading-space removal<commit_after>//! The preprocessing we apply to doc comments.
//!
//! #[derive(Parser)] works in terms of "paragraphs". Paragraph is a sequence of
//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines.

use crate::item::Method;

use quote::{format_ident, quote};
use std::iter;

pub fn process_doc_comment(
    lines: Vec<String>,
    name: &str,
    preprocess: bool,
) -> (Option<Method>, Option<Method>) {
    // multiline comments (`/** ... */`) may have LFs (`\n`) in them,
    // we need to split so we could handle the lines correctly
    //
    // we also need to remove leading and trailing blank lines
    let mut lines: Vec<&str> = lines
        .iter()
        .skip_while(|s| is_blank(s))
        .flat_map(|s| s.split('\n'))
        .collect();

    while let Some(true) = lines.last().map(|s| is_blank(s)) {
        lines.pop();
    }

    if lines.is_empty() {
        return (None, None);
    }

    // remove one leading space no matter what
    for line in lines.iter_mut() {
        *line = line.strip_prefix(' ').unwrap_or(line);
    }

    let short_name = format_ident!("{}", name);
    let long_name = format_ident!("long_{}", name);

    if let Some(first_blank) = lines.iter().position(|s| is_blank(s)) {
        let (short, long) = if preprocess {
            let paragraphs = split_paragraphs(&lines);
            let short = paragraphs[0].clone();
            let long = paragraphs.join("\n\n");
            (remove_period(short), long)
        } else {
            let short = lines[..first_blank].join("\n");
            let long = lines.join("\n");
            (short, long)
        };

        (
            Some(Method::new(short_name, quote!(#short))),
            Some(Method::new(long_name, quote!(#long))),
        )
    } else {
        let short = if preprocess {
            let s = merge_lines(&lines);
            remove_period(s)
        } else {
            lines.join("\n")
        };

        (
            Some(Method::new(short_name, quote!(#short))),
            Some(Method::new(long_name, quote!(None))),
        )
    }
}

fn split_paragraphs(lines: &[&str]) -> Vec<String> {
    let mut last_line = 0;
    iter::from_fn(|| {
        let slice = &lines[last_line..];
        let start = slice.iter().position(|s| !is_blank(s)).unwrap_or(0);

        let slice = &slice[start..];
        let len = slice
            .iter()
            .position(|s| is_blank(s))
            .unwrap_or(slice.len());

        last_line += start + len;

        if len != 0 {
            Some(merge_lines(&slice[..len]))
        } else {
            None
        }
    })
    .collect()
}

fn remove_period(mut s: String) -> String {
    if s.ends_with('.') && !s.ends_with("..") {
        s.pop();
    }
    s
}

fn is_blank(s: &str) -> bool {
    s.trim().is_empty()
}

fn merge_lines(lines: &[&str]) -> String {
    lines.iter().map(|s| s.trim()).collect::<Vec<_>>().join(" ")
}
<|endoftext|>


<commit_before>pub fn is_positive_int(val: String) -> Result<(), String> {
    match val.parse::<u64>() {
        Ok(val) if val > 0 => Ok(()),
        // If the the value is <= 0 or can't be parsed
        _ => Err(format!("{} isn't a positive integer.", val)),
    }
}

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

    #[test]
    fn is_positive_int_should_parse_a_positive_integer_from_input_string() {
        assert_eq!(is_positive_int("1".to_string()), Ok(()))
    }

    #[test]
    fn is_positive_int_should_throw_an_error_with_zero() {
        assert_eq!(
            is_positive_int("0".to_string()),
            Err("0 isn't a positive integer.".to_string())
        )
    }

    #[test]
    fn is_positive_int_should_throw_an_error_with_negative_integer() {
        assert_eq!(
            is_positive_int("-5".to_string()),
            Err("-5 isn't a positive integer.".to_string())
        )
    }

    #[test]
    fn is_positive_int_should_throw_an_error_with_float() {
        assert_eq!(
            is_positive_int("5.2".to_string()),
            Err("5.2 isn't a positive integer.".to_string())
        )
    }
}
<commit_msg>modify is_positive_int validator to adhere to the new clap-assumed signature<commit_after>pub fn is_positive_int(val: &str) -> Result<(), String> {
    match val.parse::<u64>() {
        Ok(val) if val > 0 => Ok(()),
        // If the the value is <= 0 or can't be parsed
        _ => Err(format!("{} isn't a positive integer.", val)),
    }
}

#[cfg(test)]
mod tests {
    // use super::is_positive_int;

    // #[test]
    // fn is_positive_int_should_parse_a_positive_integer_from_input_string() {
    //     assert_eq!(is_positive_int("1"), Ok(()))
    // }

    // #[test]
    // fn is_positive_int_should_throw_an_error_with_zero() {
    //     assert_eq!(
    //         is_positive_int("0"),
    //         Err("0 isn't a positive integer.".to_string())
    //     )
    // }

    // #[test]
    // fn is_positive_int_should_throw_an_error_with_negative_integer() {
    //     assert_eq!(
    //         is_positive_int("-5"),
    //         Err("-5 isn't a positive integer.".to_string())
    //     )
    // }

    // #[test]
    // fn is_positive_int_should_throw_an_error_with_float() {
    //     assert_eq!(
    //         is_positive_int("5.2"),
    //         Err("5.2 isn't a positive integer.".to_string())
    //     )
    // }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Michael Gehring <mg@ebfe.org>
//  * (c) kwantam <kwantam@gmail.com>
//  *     * 2015-04-28 ~ created `expand` module to eliminate most allocs during setup
//  * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) allocs bset dflag cflag sflag tflag

#[macro_use]
extern crate uucore;

mod expand;

use bit_set::BitSet;
use clap::{App, Arg};
use fnv::FnvHashMap;
use std::io::{stdin, stdout, BufRead, BufWriter, Write};

use crate::expand::ExpandSet;
use uucore::InvalidEncodingHandling;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "translate or delete characters";

const BUFFER_LEN: usize = 1024;

mod options {
    pub const COMPLEMENT: &str = "complement";
    pub const DELETE: &str = "delete";
    pub const SQUEEZE: &str = "squeeze-repeats";
    pub const TRUNCATE: &str = "truncate";
    pub const SETS: &str = "sets";
}

trait SymbolTranslator {
    fn translate(&self, c: char, prev_c: char) -> Option<char>;
}

struct DeleteOperation {
    bset: BitSet,
    complement: bool,
}

impl DeleteOperation {
    fn new(set: ExpandSet, complement: bool) -> DeleteOperation {
        DeleteOperation {
            bset: set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        let uc = c as usize;
        if self.complement == self.bset.contains(uc) {
            Some(c)
        } else {
            None
        }
    }
}

struct SqueezeOperation {
    squeeze_set: BitSet,
    complement: bool,
}

impl SqueezeOperation {
    fn new(squeeze_set: ExpandSet, complement: bool) -> SqueezeOperation {
        SqueezeOperation {
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for SqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if prev_c == c && self.complement != self.squeeze_set.contains(c as usize) {
            None
        } else {
            Some(c)
        }
    }
}

struct DeleteAndSqueezeOperation {
    delete_set: BitSet,
    squeeze_set: BitSet,
    complement: bool,
}

impl DeleteAndSqueezeOperation {
    fn new(
        delete_set: ExpandSet,
        squeeze_set: ExpandSet,
        complement: bool,
    ) -> DeleteAndSqueezeOperation {
        DeleteAndSqueezeOperation {
            delete_set: delete_set.map(|c| c as usize).collect(),
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if self.complement != self.delete_set.contains(c as usize)
            || prev_c == c && self.squeeze_set.contains(c as usize)
        {
            None
        } else {
            Some(c)
        }
    }
}

struct TranslateOperation {
    translate_map: FnvHashMap<usize, char>,
    complement: bool,
    s2_last: char,
}

impl TranslateOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateOperation {
        let mut map = FnvHashMap::default();
        let mut s2_prev = '_';
        for i in set1 {
            let s2_next = set2.next();

            if s2_next.is_none() && truncate {
                map.insert(i as usize, i);
            } else {
                s2_prev = s2_next.unwrap_or(s2_prev);
                map.insert(i as usize, s2_prev);
            }
        }
        TranslateOperation {
            translate_map: map,
            complement,
            s2_last: set2.last().unwrap_or(s2_prev),
        }
    }
}

impl SymbolTranslator for TranslateOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        if self.complement {
            Some(if self.translate_map.contains_key(&(c as usize)) {
                c
            } else {
                self.s2_last
            })
        } else {
            Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
        }
    }
}

struct TranslateAndSqueezeOperation {
    translate: TranslateOperation,
    squeeze: SqueezeOperation,
}

impl TranslateAndSqueezeOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        set2_: ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateAndSqueezeOperation {
        TranslateAndSqueezeOperation {
            translate: TranslateOperation::new(set1, set2, truncate, complement),
            squeeze: SqueezeOperation::new(set2_, complement),
        }
    }
}

impl SymbolTranslator for TranslateAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        // `unwrap()` will never panic because `Translate.translate()`
        // always returns `Some`.
        self.squeeze
            .translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
    }
}

fn translate_input<T: SymbolTranslator>(
    input: &mut dyn BufRead,
    output: &mut dyn Write,
    translator: T,
) {
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut output_buf = String::with_capacity(BUFFER_LEN + 4);

    while let Ok(length) = input.read_line(&mut buf) {
        let mut prev_c = 0 as char;
        if length == 0 {
            break;
        }
        {
            // isolation to make borrow checker happy
            let filtered = buf.chars().filter_map(|c| {
                let res = translator.translate(c, prev_c);
                // Set `prev_c` to the post-translate character. This
                // allows the squeeze operation to correctly function
                // after the translate operation.
                if res.is_some() {
                    prev_c = res.unwrap();
                }
                res
            });

            output_buf.extend(filtered);
            output.write_all(output_buf.as_bytes()).unwrap();
        }
        buf.clear();
        output_buf.clear();
    }
}

fn get_usage() -> String {
    format!("{} [OPTION]... SET1 [SET2]", executable!())
}

fn get_long_usage() -> String {
    String::from(
        "Translate, squeeze, and/or delete characters from standard input,
writing to standard output.",
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(&after_help[..])
        .arg(
            Arg::with_name(options::COMPLEMENT)
                // .visible_short_alias('C')  // TODO: requires clap "3.0.0-beta.2"
                .short("c")
                .long(options::COMPLEMENT)
                .help("use the complement of SET1"),
        )
        .arg(
            Arg::with_name("C") // work around for `Arg::visible_short_alias`
                .short("C")
                .help("same as -c"),
        )
        .arg(
            Arg::with_name(options::DELETE)
                .short("d")
                .long(options::DELETE)
                .help("delete characters in SET1, do not translate"),
        )
        .arg(
            Arg::with_name(options::SQUEEZE)
                .long(options::SQUEEZE)
                .short("s")
                .help(
                    "replace each sequence  of  a  repeated  character  that  is
  listed  in the last specified SET, with a single occurrence
  of that character",
                ),
        )
        .arg(
            Arg::with_name(options::TRUNCATE)
                .long(options::TRUNCATE)
                .short("t")
                .help("first truncate SET1 to length of SET2"),
        )
        .arg(Arg::with_name(options::SETS).multiple(true))
        .get_matches_from(args);

    let delete_flag = matches.is_present(options::DELETE);
    let complement_flag = matches.is_present(options::COMPLEMENT) || matches.is_present("C");
    let squeeze_flag = matches.is_present(options::SQUEEZE);
    let truncate_flag = matches.is_present(options::TRUNCATE);

    let sets: Vec<String> = match matches.values_of(options::SETS) {
        Some(v) => v.map(|v| v.to_string()).collect(),
        None => vec![],
    };

    if sets.is_empty() {
        show_error!(
            "missing operand\nTry `{} --help` for more information.",
            executable!()
        );
        return 1;
    }

    if !(delete_flag || squeeze_flag) && sets.len() < 2 {
        show_error!(
            "missing operand after ‘{}’\nTry `{} --help` for more information.",
            sets[0],
            executable!()
        );
        return 1;
    }

    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let stdout = stdout();
    let locked_stdout = stdout.lock();
    let mut buffered_stdout = BufWriter::new(locked_stdout);

    let set1 = ExpandSet::new(sets[0].as_ref());
    if delete_flag {
        if squeeze_flag {
            let set2 = ExpandSet::new(sets[1].as_ref());
            let op = DeleteAndSqueezeOperation::new(set1, set2, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let op = DeleteOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else if squeeze_flag {
        if sets.len() < 2 {
            let op = SqueezeOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let mut set2 = ExpandSet::new(sets[1].as_ref());
            let set2_ = ExpandSet::new(sets[1].as_ref());
            let op = TranslateAndSqueezeOperation::new(
                set1,
                &mut set2,
                set2_,
                complement_flag,
                truncate_flag,
            );
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else {
        let mut set2 = ExpandSet::new(sets[1].as_ref());
        let op = TranslateOperation::new(set1, &mut set2, truncate_flag, complement_flag);
        translate_input(&mut locked_stdin, &mut buffered_stdout, op);
    }

    0
}
<commit_msg>tr: fix clippy warning<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Michael Gehring <mg@ebfe.org>
//  * (c) kwantam <kwantam@gmail.com>
//  *     * 2015-04-28 ~ created `expand` module to eliminate most allocs during setup
//  * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) allocs bset dflag cflag sflag tflag

#[macro_use]
extern crate uucore;

mod expand;

use bit_set::BitSet;
use clap::{App, Arg};
use fnv::FnvHashMap;
use std::io::{stdin, stdout, BufRead, BufWriter, Write};

use crate::expand::ExpandSet;
use uucore::InvalidEncodingHandling;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "translate or delete characters";

const BUFFER_LEN: usize = 1024;

mod options {
    pub const COMPLEMENT: &str = "complement";
    pub const DELETE: &str = "delete";
    pub const SQUEEZE: &str = "squeeze-repeats";
    pub const TRUNCATE: &str = "truncate";
    pub const SETS: &str = "sets";
}

trait SymbolTranslator {
    fn translate(&self, c: char, prev_c: char) -> Option<char>;
}

struct DeleteOperation {
    bset: BitSet,
    complement: bool,
}

impl DeleteOperation {
    fn new(set: ExpandSet, complement: bool) -> DeleteOperation {
        DeleteOperation {
            bset: set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        let uc = c as usize;
        if self.complement == self.bset.contains(uc) {
            Some(c)
        } else {
            None
        }
    }
}

struct SqueezeOperation {
    squeeze_set: BitSet,
    complement: bool,
}

impl SqueezeOperation {
    fn new(squeeze_set: ExpandSet, complement: bool) -> SqueezeOperation {
        SqueezeOperation {
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for SqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if prev_c == c && self.complement != self.squeeze_set.contains(c as usize) {
            None
        } else {
            Some(c)
        }
    }
}

struct DeleteAndSqueezeOperation {
    delete_set: BitSet,
    squeeze_set: BitSet,
    complement: bool,
}

impl DeleteAndSqueezeOperation {
    fn new(
        delete_set: ExpandSet,
        squeeze_set: ExpandSet,
        complement: bool,
    ) -> DeleteAndSqueezeOperation {
        DeleteAndSqueezeOperation {
            delete_set: delete_set.map(|c| c as usize).collect(),
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if self.complement != self.delete_set.contains(c as usize)
            || prev_c == c && self.squeeze_set.contains(c as usize)
        {
            None
        } else {
            Some(c)
        }
    }
}

struct TranslateOperation {
    translate_map: FnvHashMap<usize, char>,
    complement: bool,
    s2_last: char,
}

impl TranslateOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateOperation {
        let mut map = FnvHashMap::default();
        let mut s2_prev = '_';
        for i in set1 {
            let s2_next = set2.next();

            if s2_next.is_none() && truncate {
                map.insert(i as usize, i);
            } else {
                s2_prev = s2_next.unwrap_or(s2_prev);
                map.insert(i as usize, s2_prev);
            }
        }
        TranslateOperation {
            translate_map: map,
            complement,
            s2_last: set2.last().unwrap_or(s2_prev),
        }
    }
}

impl SymbolTranslator for TranslateOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        if self.complement {
            Some(if self.translate_map.contains_key(&(c as usize)) {
                c
            } else {
                self.s2_last
            })
        } else {
            Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
        }
    }
}

struct TranslateAndSqueezeOperation {
    translate: TranslateOperation,
    squeeze: SqueezeOperation,
}

impl TranslateAndSqueezeOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        set2_: ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateAndSqueezeOperation {
        TranslateAndSqueezeOperation {
            translate: TranslateOperation::new(set1, set2, truncate, complement),
            squeeze: SqueezeOperation::new(set2_, complement),
        }
    }
}

impl SymbolTranslator for TranslateAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        // `unwrap()` will never panic because `Translate.translate()`
        // always returns `Some`.
        self.squeeze
            .translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
    }
}

fn translate_input<T: SymbolTranslator>(
    input: &mut dyn BufRead,
    output: &mut dyn Write,
    translator: T,
) {
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut output_buf = String::with_capacity(BUFFER_LEN + 4);

    while let Ok(length) = input.read_line(&mut buf) {
        let mut prev_c = 0 as char;
        if length == 0 {
            break;
        }
        {
            // isolation to make borrow checker happy
            let filtered = buf.chars().filter_map(|c| {
                let res = translator.translate(c, prev_c);
                // Set `prev_c` to the post-translate character. This
                // allows the squeeze operation to correctly function
                // after the translate operation.
                if let Some(rc) = res {
                    prev_c = rc;
                }
                res
            });

            output_buf.extend(filtered);
            output.write_all(output_buf.as_bytes()).unwrap();
        }
        buf.clear();
        output_buf.clear();
    }
}

fn get_usage() -> String {
    format!("{} [OPTION]... SET1 [SET2]", executable!())
}

fn get_long_usage() -> String {
    String::from(
        "Translate, squeeze, and/or delete characters from standard input,
writing to standard output.",
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .after_help(&after_help[..])
        .arg(
            Arg::with_name(options::COMPLEMENT)
                // .visible_short_alias('C')  // TODO: requires clap "3.0.0-beta.2"
                .short("c")
                .long(options::COMPLEMENT)
                .help("use the complement of SET1"),
        )
        .arg(
            Arg::with_name("C") // work around for `Arg::visible_short_alias`
                .short("C")
                .help("same as -c"),
        )
        .arg(
            Arg::with_name(options::DELETE)
                .short("d")
                .long(options::DELETE)
                .help("delete characters in SET1, do not translate"),
        )
        .arg(
            Arg::with_name(options::SQUEEZE)
                .long(options::SQUEEZE)
                .short("s")
                .help(
                    "replace each sequence  of  a  repeated  character  that  is
  listed  in the last specified SET, with a single occurrence
  of that character",
                ),
        )
        .arg(
            Arg::with_name(options::TRUNCATE)
                .long(options::TRUNCATE)
                .short("t")
                .help("first truncate SET1 to length of SET2"),
        )
        .arg(Arg::with_name(options::SETS).multiple(true))
        .get_matches_from(args);

    let delete_flag = matches.is_present(options::DELETE);
    let complement_flag = matches.is_present(options::COMPLEMENT) || matches.is_present("C");
    let squeeze_flag = matches.is_present(options::SQUEEZE);
    let truncate_flag = matches.is_present(options::TRUNCATE);

    let sets: Vec<String> = match matches.values_of(options::SETS) {
        Some(v) => v.map(|v| v.to_string()).collect(),
        None => vec![],
    };

    if sets.is_empty() {
        show_error!(
            "missing operand\nTry `{} --help` for more information.",
            executable!()
        );
        return 1;
    }

    if !(delete_flag || squeeze_flag) && sets.len() < 2 {
        show_error!(
            "missing operand after ‘{}’\nTry `{} --help` for more information.",
            sets[0],
            executable!()
        );
        return 1;
    }

    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let stdout = stdout();
    let locked_stdout = stdout.lock();
    let mut buffered_stdout = BufWriter::new(locked_stdout);

    let set1 = ExpandSet::new(sets[0].as_ref());
    if delete_flag {
        if squeeze_flag {
            let set2 = ExpandSet::new(sets[1].as_ref());
            let op = DeleteAndSqueezeOperation::new(set1, set2, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let op = DeleteOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else if squeeze_flag {
        if sets.len() < 2 {
            let op = SqueezeOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let mut set2 = ExpandSet::new(sets[1].as_ref());
            let set2_ = ExpandSet::new(sets[1].as_ref());
            let op = TranslateAndSqueezeOperation::new(
                set1,
                &mut set2,
                set2_,
                complement_flag,
                truncate_flag,
            );
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else {
        let mut set2 = ExpandSet::new(sets[1].as_ref());
        let op = TranslateOperation::new(set1, &mut set2, truncate_flag, complement_flag);
        translate_input(&mut locked_stdin, &mut buffered_stdout, op);
    }

    0
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Cow;
use std::fmt::Display;
use std::path::Path;
use std::vec::Vec;
use std::rc::Rc;
use std::cell::RefCell;

use dbus;
use dbus::Connection;
use dbus::BusType;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;
use dbus::arg::Array;
use dbus::arg::IterAppend;
use dbus::tree::Access;
use dbus::tree::EmitsChangedSignal;
use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MTFn;
use dbus::tree::MethodResult;
use dbus::tree::MethodInfo;
use dbus::tree::PropInfo;
use dbus::tree::Tree;
use dbus::ConnectionItem;

use engine::{Engine, Redundancy};
use stratis::VERSION;

use super::pool::create_dbus_pool;
use super::types::{DeferredAction, DbusContext, DbusErrorEnum, TData};
use super::util::STRATIS_BASE_PATH;
use super::util::STRATIS_BASE_SERVICE;
use super::util::code_to_message_items;
use super::util::default_object_path;
use super::util::engine_to_dbus_err;
use super::util::get_next_arg;
use super::util::ok_message_items;
use super::util::tuple_to_option;

fn create_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let name: &str = try!(get_next_arg(&mut iter, 0));
    let redundancy: (bool, u16) = try!(get_next_arg(&mut iter, 1));
    let force: bool = try!(get_next_arg(&mut iter, 2));
    let devs: Array<&str, _> = try!(get_next_arg(&mut iter, 3));

    let blockdevs = devs.map(|x| Path::new(x)).collect::<Vec<&Path>>();

    let object_path = m.path.get_name();
    let dbus_context = m.tree.get_data();
    let result = dbus_context
        .engine
        .borrow_mut()
        .create_pool(name, &blockdevs, tuple_to_option(redundancy), force);

    let return_message = message.method_return();

    let msg = match result {
        Ok((uuid, devnodes)) => {
            let pool_object_path: dbus::Path =
                create_dbus_pool(dbus_context, object_path.clone(), uuid);
            let paths = devnodes
                .iter()
                .map(|d| {
                         d.to_str()
                             .expect("'d' originated in the 'devs' D-Bus argument.")
                             .into()
                     });
            let paths = paths.map(|x| MessageItem::Str(x)).collect();
            let return_path = MessageItem::ObjectPath(pool_object_path);
            let return_list = MessageItem::Array(paths, "s".into());
            let return_value = MessageItem::Struct(vec![return_path, return_list]);
            let (rc, rs) = ok_message_items();
            return_message.append3(return_value, rc, rs)
        }
        Err(x) => {
            let return_path = MessageItem::ObjectPath(default_object_path());
            let return_list = MessageItem::Array(vec![], "s".into());
            let return_value = MessageItem::Struct(vec![return_path, return_list]);
            let (rc, rs) = engine_to_dbus_err(&x);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append3(return_value, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn destroy_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {

    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let object_path: dbus::Path<'static> = try!(get_next_arg(&mut iter, 0));

    let dbus_context = m.tree.get_data();

    let default_return = MessageItem::Bool(false);
    let return_message = message.method_return();

    let pool_uuid = match m.tree.get(&object_path) {
        Some(pool_path) => get_data!(pool_path; default_return; return_message).uuid,
        None => {
            let (rc, rs) = ok_message_items();
            return Ok(vec![return_message.append3(default_return, rc, rs)]);
        }
    };

    let msg = match dbus_context
              .engine
              .borrow_mut()
              .destroy_pool(&pool_uuid) {
        Ok(action) => {
            dbus_context
                .actions
                .borrow_mut()
                .push_remove(object_path);
            let (rc, rs) = ok_message_items();
            return_message.append3(MessageItem::Bool(action), rc, rs)
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err(&err);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append3(default_return, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_list_items<T, I>(i: &mut IterAppend, iter: I) -> Result<(), MethodErr>
    where T: Display + Into<u16>,
          I: Iterator<Item = T>
{
    let msg_vec = iter.map(|item| {
                               MessageItem::Struct(vec![MessageItem::Str(format!("{}", item)),
                                                        MessageItem::UInt16(item.into())])
                           })
        .collect::<Vec<MessageItem>>();
    i.append(MessageItem::Array(msg_vec, Cow::Borrowed("(sq)")));
    Ok(())
}

fn get_error_values(i: &mut IterAppend,
                    _p: &PropInfo<MTFn<TData>, TData>)
                    -> Result<(), MethodErr> {
    get_list_items(i, DbusErrorEnum::iter_variants())
}

fn get_redundancy_values(i: &mut IterAppend,
                         _p: &PropInfo<MTFn<TData>, TData>)
                         -> Result<(), MethodErr> {
    get_list_items(i, Redundancy::iter_variants())
}

fn get_version(i: &mut IterAppend, _p: &PropInfo<MTFn<TData>, TData>) -> Result<(), MethodErr> {
    i.append(VERSION);
    Ok(())
}

fn configure_simulator(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message = m.msg;
    let mut iter = message.iter_init();

    let denominator: u32 = try!(get_next_arg(&mut iter, 0));

    let dbus_context = m.tree.get_data();
    let result = dbus_context
        .engine
        .borrow_mut()
        .configure_simulator(denominator);

    let return_message = message.method_return();

    let msg = match result {
        Ok(_) => {
            let (rc, rs) = ok_message_items();
            return_message.append2(rc, rs)
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err(&err);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append2(rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_base_tree<'a>(dbus_context: DbusContext) -> Tree<MTFn<TData>, TData> {

    let f = Factory::new_fn();

    let base_tree = f.tree(dbus_context);

    let create_pool_method = f.method("CreatePool", (), create_pool)
        .in_arg(("name", "s"))
        .in_arg(("redundancy", "(bq)"))
        .in_arg(("force", "b"))
        .in_arg(("devices", "as"))
        .out_arg(("result", "(oas)"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let destroy_pool_method = f.method("DestroyPool", (), destroy_pool)
        .in_arg(("pool", "o"))
        .out_arg(("action", "b"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let configure_simulator_method = f.method("ConfigureSimulator", (), configure_simulator)
        .in_arg(("denominator", "u"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let redundancy_values_property =
        f.property::<Array<(&str, u16), &Iterator<Item = (&str, u16)>>, _>("RedundancyValues", ())
            .access(Access::Read)
            .emits_changed(EmitsChangedSignal::Const)
            .on_get(get_redundancy_values);

    let error_values_property =
        f.property::<Array<(&str, u16), &Iterator<Item = (&str, u16)>>, _>("ErrorValues", ())
            .access(Access::Read)
            .emits_changed(EmitsChangedSignal::Const)
            .on_get(get_error_values);

    let version_property = f.property::<&str, _>("Version", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_version);

    let interface_name = format!("{}.{}", STRATIS_BASE_SERVICE, "Manager");

    let obj_path = f.object_path(STRATIS_BASE_PATH, None)
        .introspectable()
        .object_manager()
        .add(f.interface(interface_name, ())
                 .add_m(create_pool_method)
                 .add_m(destroy_pool_method)
                 .add_m(configure_simulator_method)
                 .add_p(error_values_property)
                 .add_p(redundancy_values_property)
                 .add_p(version_property));

    base_tree.add(obj_path)
}

#[allow(type_complexity)]
pub fn connect(engine: Rc<RefCell<Engine>>)
               -> Result<(Connection, Tree<MTFn<TData>, TData>, DbusContext), dbus::Error> {
    let c = try!(Connection::get_private(BusType::System));

    let tree = get_base_tree(DbusContext::new(engine));
    let dbus_context = tree.get_data().clone();
    try!(tree.set_registered(&c, true));

    try!(c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32));

    Ok((c, tree, dbus_context))
}

pub fn handle(c: &Connection,
              item: ConnectionItem,
              tree: &mut Tree<MTFn<TData>, TData>,
              dbus_context: &DbusContext)
              -> Result<(), dbus::Error> {
    if let ConnectionItem::MethodCall(ref msg) = item {
        if let Some(v) = tree.handle(&msg) {
            // Probably the wisest is to ignore any send errors here -
            // maybe the remote has disconnected during our processing.
            for m in v {
                let _ = c.send(m);
            }
        }

        let mut b_actions = dbus_context.actions.borrow_mut();
        for action in b_actions.drain() {
            match action {
                DeferredAction::Add(path) => {
                    try!(c.register_object_path(path.get_name()));
                    tree.insert(path);
                }
                DeferredAction::Remove(path) => {
                    c.unregister_object_path(&path);
                    tree.remove(&path);
                }
            }
        }
    }

    Ok(())
}
<commit_msg>Get rid of a redundant closure<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::borrow::Cow;
use std::fmt::Display;
use std::path::Path;
use std::vec::Vec;
use std::rc::Rc;
use std::cell::RefCell;

use dbus;
use dbus::Connection;
use dbus::BusType;
use dbus::Message;
use dbus::MessageItem;
use dbus::NameFlag;
use dbus::arg::Array;
use dbus::arg::IterAppend;
use dbus::tree::Access;
use dbus::tree::EmitsChangedSignal;
use dbus::tree::Factory;
use dbus::tree::MethodErr;
use dbus::tree::MTFn;
use dbus::tree::MethodResult;
use dbus::tree::MethodInfo;
use dbus::tree::PropInfo;
use dbus::tree::Tree;
use dbus::ConnectionItem;

use engine::{Engine, Redundancy};
use stratis::VERSION;

use super::pool::create_dbus_pool;
use super::types::{DeferredAction, DbusContext, DbusErrorEnum, TData};
use super::util::STRATIS_BASE_PATH;
use super::util::STRATIS_BASE_SERVICE;
use super::util::code_to_message_items;
use super::util::default_object_path;
use super::util::engine_to_dbus_err;
use super::util::get_next_arg;
use super::util::ok_message_items;
use super::util::tuple_to_option;

fn create_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let name: &str = try!(get_next_arg(&mut iter, 0));
    let redundancy: (bool, u16) = try!(get_next_arg(&mut iter, 1));
    let force: bool = try!(get_next_arg(&mut iter, 2));
    let devs: Array<&str, _> = try!(get_next_arg(&mut iter, 3));

    let blockdevs = devs.map(|x| Path::new(x)).collect::<Vec<&Path>>();

    let object_path = m.path.get_name();
    let dbus_context = m.tree.get_data();
    let result = dbus_context
        .engine
        .borrow_mut()
        .create_pool(name, &blockdevs, tuple_to_option(redundancy), force);

    let return_message = message.method_return();

    let msg = match result {
        Ok((uuid, devnodes)) => {
            let pool_object_path: dbus::Path =
                create_dbus_pool(dbus_context, object_path.clone(), uuid);
            let paths = devnodes
                .iter()
                .map(|d| {
                         d.to_str()
                             .expect("'d' originated in the 'devs' D-Bus argument.")
                             .into()
                     });
            let paths = paths.map(MessageItem::Str).collect();
            let return_path = MessageItem::ObjectPath(pool_object_path);
            let return_list = MessageItem::Array(paths, "s".into());
            let return_value = MessageItem::Struct(vec![return_path, return_list]);
            let (rc, rs) = ok_message_items();
            return_message.append3(return_value, rc, rs)
        }
        Err(x) => {
            let return_path = MessageItem::ObjectPath(default_object_path());
            let return_list = MessageItem::Array(vec![], "s".into());
            let return_value = MessageItem::Struct(vec![return_path, return_list]);
            let (rc, rs) = engine_to_dbus_err(&x);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append3(return_value, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn destroy_pool(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {

    let message: &Message = m.msg;
    let mut iter = message.iter_init();

    let object_path: dbus::Path<'static> = try!(get_next_arg(&mut iter, 0));

    let dbus_context = m.tree.get_data();

    let default_return = MessageItem::Bool(false);
    let return_message = message.method_return();

    let pool_uuid = match m.tree.get(&object_path) {
        Some(pool_path) => get_data!(pool_path; default_return; return_message).uuid,
        None => {
            let (rc, rs) = ok_message_items();
            return Ok(vec![return_message.append3(default_return, rc, rs)]);
        }
    };

    let msg = match dbus_context
              .engine
              .borrow_mut()
              .destroy_pool(&pool_uuid) {
        Ok(action) => {
            dbus_context
                .actions
                .borrow_mut()
                .push_remove(object_path);
            let (rc, rs) = ok_message_items();
            return_message.append3(MessageItem::Bool(action), rc, rs)
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err(&err);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append3(default_return, rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_list_items<T, I>(i: &mut IterAppend, iter: I) -> Result<(), MethodErr>
    where T: Display + Into<u16>,
          I: Iterator<Item = T>
{
    let msg_vec = iter.map(|item| {
                               MessageItem::Struct(vec![MessageItem::Str(format!("{}", item)),
                                                        MessageItem::UInt16(item.into())])
                           })
        .collect::<Vec<MessageItem>>();
    i.append(MessageItem::Array(msg_vec, Cow::Borrowed("(sq)")));
    Ok(())
}

fn get_error_values(i: &mut IterAppend,
                    _p: &PropInfo<MTFn<TData>, TData>)
                    -> Result<(), MethodErr> {
    get_list_items(i, DbusErrorEnum::iter_variants())
}

fn get_redundancy_values(i: &mut IterAppend,
                         _p: &PropInfo<MTFn<TData>, TData>)
                         -> Result<(), MethodErr> {
    get_list_items(i, Redundancy::iter_variants())
}

fn get_version(i: &mut IterAppend, _p: &PropInfo<MTFn<TData>, TData>) -> Result<(), MethodErr> {
    i.append(VERSION);
    Ok(())
}

fn configure_simulator(m: &MethodInfo<MTFn<TData>, TData>) -> MethodResult {
    let message = m.msg;
    let mut iter = message.iter_init();

    let denominator: u32 = try!(get_next_arg(&mut iter, 0));

    let dbus_context = m.tree.get_data();
    let result = dbus_context
        .engine
        .borrow_mut()
        .configure_simulator(denominator);

    let return_message = message.method_return();

    let msg = match result {
        Ok(_) => {
            let (rc, rs) = ok_message_items();
            return_message.append2(rc, rs)
        }
        Err(err) => {
            let (rc, rs) = engine_to_dbus_err(&err);
            let (rc, rs) = code_to_message_items(rc, rs);
            return_message.append2(rc, rs)
        }
    };
    Ok(vec![msg])
}

fn get_base_tree<'a>(dbus_context: DbusContext) -> Tree<MTFn<TData>, TData> {

    let f = Factory::new_fn();

    let base_tree = f.tree(dbus_context);

    let create_pool_method = f.method("CreatePool", (), create_pool)
        .in_arg(("name", "s"))
        .in_arg(("redundancy", "(bq)"))
        .in_arg(("force", "b"))
        .in_arg(("devices", "as"))
        .out_arg(("result", "(oas)"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let destroy_pool_method = f.method("DestroyPool", (), destroy_pool)
        .in_arg(("pool", "o"))
        .out_arg(("action", "b"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let configure_simulator_method = f.method("ConfigureSimulator", (), configure_simulator)
        .in_arg(("denominator", "u"))
        .out_arg(("return_code", "q"))
        .out_arg(("return_string", "s"));

    let redundancy_values_property =
        f.property::<Array<(&str, u16), &Iterator<Item = (&str, u16)>>, _>("RedundancyValues", ())
            .access(Access::Read)
            .emits_changed(EmitsChangedSignal::Const)
            .on_get(get_redundancy_values);

    let error_values_property =
        f.property::<Array<(&str, u16), &Iterator<Item = (&str, u16)>>, _>("ErrorValues", ())
            .access(Access::Read)
            .emits_changed(EmitsChangedSignal::Const)
            .on_get(get_error_values);

    let version_property = f.property::<&str, _>("Version", ())
        .access(Access::Read)
        .emits_changed(EmitsChangedSignal::Const)
        .on_get(get_version);

    let interface_name = format!("{}.{}", STRATIS_BASE_SERVICE, "Manager");

    let obj_path = f.object_path(STRATIS_BASE_PATH, None)
        .introspectable()
        .object_manager()
        .add(f.interface(interface_name, ())
                 .add_m(create_pool_method)
                 .add_m(destroy_pool_method)
                 .add_m(configure_simulator_method)
                 .add_p(error_values_property)
                 .add_p(redundancy_values_property)
                 .add_p(version_property));

    base_tree.add(obj_path)
}

#[allow(type_complexity)]
pub fn connect(engine: Rc<RefCell<Engine>>)
               -> Result<(Connection, Tree<MTFn<TData>, TData>, DbusContext), dbus::Error> {
    let c = try!(Connection::get_private(BusType::System));

    let tree = get_base_tree(DbusContext::new(engine));
    let dbus_context = tree.get_data().clone();
    try!(tree.set_registered(&c, true));

    try!(c.register_name(STRATIS_BASE_SERVICE, NameFlag::ReplaceExisting as u32));

    Ok((c, tree, dbus_context))
}

pub fn handle(c: &Connection,
              item: ConnectionItem,
              tree: &mut Tree<MTFn<TData>, TData>,
              dbus_context: &DbusContext)
              -> Result<(), dbus::Error> {
    if let ConnectionItem::MethodCall(ref msg) = item {
        if let Some(v) = tree.handle(&msg) {
            // Probably the wisest is to ignore any send errors here -
            // maybe the remote has disconnected during our processing.
            for m in v {
                let _ = c.send(m);
            }
        }

        let mut b_actions = dbus_context.actions.borrow_mut();
        for action in b_actions.drain() {
            match action {
                DeferredAction::Add(path) => {
                    try!(c.register_object_path(path.get_name()));
                    tree.insert(path);
                }
                DeferredAction::Remove(path) => {
                    c.unregister_object_path(&path);
                    tree.remove(&path);
                }
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct RafDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> RafDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> RafDecoder<'a> {
    RafDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for RafDecoder<'a> {
  fn image(&self) -> Result<RawImage,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let raw = fetch_ifd!(&self.tiff, Tag::RafOffsets);
    let (width,height) = if raw.has_entry(Tag::RafImageWidth) {
      (fetch_tag!(raw, Tag::RafImageWidth).get_usize(0),
       fetch_tag!(raw, Tag::RafImageLength).get_usize(0))
    } else {
      let sizes = fetch_tag!(raw, Tag::ImageWidth);
      (sizes.get_usize(1), sizes.get_usize(0))
    };
    let offset = fetch_tag!(raw, Tag::RafOffsets).get_usize(0) + raw.start_offset();
    let bps = match raw.find_entry(Tag::RafBitsPerSample) {
      Some(val) => val.get_u32(0),
      None      => 16,
    };
    let src = &self.buffer[offset..];

    let image = if camera.find_hint("double_width") {
      // Some fuji SuperCCD cameras include a second raw image next to the first one
      // that is identical but darker to the first. The two combined can produce
      // a higher dynamic range image. Right now we're ignoring it.
      decode_16le_skiplines(src, width, height)
    } else if camera.find_hint("jpeg32") {
      decode_12be_msb32(src, width, height)
    } else {
      match bps {
        12 => decode_12le(src, width, height),
        14 => decode_14le_unpacked(src, width, height),
        16 => {
          if self.tiff.little_endian() {
            decode_16le(src, width, height)
          } else {
            decode_16be(src, width, height)
          }
        },
        _ => {return Err(format!("RAF: Don't know how to decode bps {}", bps).to_string());},
      }
    };

    if camera.find_hint("fuji_rotation") || camera.find_hint("fuji_rotation_alt") {
      let (width, height, image) = RafDecoder::rotate_image(&image, &camera, width, height);
      Ok(RawImage {
        make: camera.make.clone(),
        model: camera.model.clone(),
        clean_make: camera.clean_make.clone(),
        clean_model: camera.clean_model.clone(),
        width: width,
        height: height,
        cpp: 1,
        wb_coeffs: try!(self.get_wb()),
        data: image,
        blacklevels: camera.blacklevels,
        whitelevels: camera.whitelevels,
        xyz_to_cam: camera.xyz_to_cam,
        cfa: camera.cfa.clone(),
        crops: [0,0,0,0],
        orientation: camera.orientation,
      })
    } else {
      ok_image(camera, width, height, try!(self.get_wb()), image)
    }
  }
}

impl<'a> RafDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    match self.tiff.find_entry(Tag::RafWBGRB) {
      Some(levels) => Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(2), NAN]),
      None => {
        let levels = fetch_tag!(self.tiff, Tag::RafOldWB);
        Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(3), NAN])
      },
    }
  }

  fn rotate_image(src: &[u16], camera: &Camera, width: usize, height: usize) -> (usize, usize, Vec<u16>) {
    let x = camera.crops[3];
    let y = camera.crops[0];
    let cropwidth = width - camera.crops[1] - x;
    let cropheight = height - camera.crops[2] - y;

    if camera.find_hint("fuji_rotation_alt") {
      let rotatedwidth = cropheight + cropwidth/2;
      let rotatedheight = rotatedwidth-1;

      let mut out: Vec<u16> = vec![0; rotatedwidth * rotatedheight];
      for row in 0..cropheight {
        let inb = &src[(row+y)*width+x..];
        for col in 0..cropwidth {
          let out_row = rotatedwidth - (cropheight + 1 - row + (col >> 1));
          let out_col = ((col+1) >> 1) + row;
          out[out_row*rotatedwidth+out_col] = inb[col];
        }
      }

      (rotatedwidth, rotatedheight, out)
    } else {
      let rotatedwidth = cropwidth + cropheight/2;
      let rotatedheight = rotatedwidth-1;

      let mut out: Vec<u16> = vec![0; rotatedwidth * rotatedheight];
      for row in 0..cropheight {
        let inb = &src[(row+y)*width+x..];
        for col in 0..cropwidth {
          let out_row = cropwidth - 1 - col + (row>>1);
          let out_col = ((row+1) >> 1) + col;
          out[out_row*rotatedwidth+out_col] = inb[col];
        }
      }

      (rotatedwidth, rotatedheight, out)
    }
  }
}
<commit_msg>RAF: Exit gracefully on compressed files<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct RafDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> RafDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> RafDecoder<'a> {
    RafDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for RafDecoder<'a> {
  fn image(&self) -> Result<RawImage,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let raw = fetch_ifd!(&self.tiff, Tag::RafOffsets);
    let (width,height) = if raw.has_entry(Tag::RafImageWidth) {
      (fetch_tag!(raw, Tag::RafImageWidth).get_usize(0),
       fetch_tag!(raw, Tag::RafImageLength).get_usize(0))
    } else {
      let sizes = fetch_tag!(raw, Tag::ImageWidth);
      (sizes.get_usize(1), sizes.get_usize(0))
    };
    let offset = fetch_tag!(raw, Tag::RafOffsets).get_usize(0) + raw.start_offset();
    let bps = match raw.find_entry(Tag::RafBitsPerSample) {
      Some(val) => val.get_u32(0) as usize,
      None      => 16,
    };
    let src = &self.buffer[offset..];

    let image = if camera.find_hint("double_width") {
      // Some fuji SuperCCD cameras include a second raw image next to the first one
      // that is identical but darker to the first. The two combined can produce
      // a higher dynamic range image. Right now we're ignoring it.
      decode_16le_skiplines(src, width, height)
    } else if camera.find_hint("jpeg32") {
      decode_12be_msb32(src, width, height)
    } else {
      if src.len() < bps*width*height/8 {
        return Err("RAF: Don't know how to decode compressed yet".to_string())
      }
      match bps {
        12 => decode_12le(src, width, height),
        14 => decode_14le_unpacked(src, width, height),
        16 => {
          if self.tiff.little_endian() {
            decode_16le(src, width, height)
          } else {
            decode_16be(src, width, height)
          }
        },
        _ => {return Err(format!("RAF: Don't know how to decode bps {}", bps).to_string());},
      }
    };

    if camera.find_hint("fuji_rotation") || camera.find_hint("fuji_rotation_alt") {
      let (width, height, image) = RafDecoder::rotate_image(&image, &camera, width, height);
      Ok(RawImage {
        make: camera.make.clone(),
        model: camera.model.clone(),
        clean_make: camera.clean_make.clone(),
        clean_model: camera.clean_model.clone(),
        width: width,
        height: height,
        cpp: 1,
        wb_coeffs: try!(self.get_wb()),
        data: image,
        blacklevels: camera.blacklevels,
        whitelevels: camera.whitelevels,
        xyz_to_cam: camera.xyz_to_cam,
        cfa: camera.cfa.clone(),
        crops: [0,0,0,0],
        orientation: camera.orientation,
      })
    } else {
      ok_image(camera, width, height, try!(self.get_wb()), image)
    }
  }
}

impl<'a> RafDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    match self.tiff.find_entry(Tag::RafWBGRB) {
      Some(levels) => Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(2), NAN]),
      None => {
        let levels = fetch_tag!(self.tiff, Tag::RafOldWB);
        Ok([levels.get_f32(1), levels.get_f32(0), levels.get_f32(3), NAN])
      },
    }
  }

  fn rotate_image(src: &[u16], camera: &Camera, width: usize, height: usize) -> (usize, usize, Vec<u16>) {
    let x = camera.crops[3];
    let y = camera.crops[0];
    let cropwidth = width - camera.crops[1] - x;
    let cropheight = height - camera.crops[2] - y;

    if camera.find_hint("fuji_rotation_alt") {
      let rotatedwidth = cropheight + cropwidth/2;
      let rotatedheight = rotatedwidth-1;

      let mut out: Vec<u16> = vec![0; rotatedwidth * rotatedheight];
      for row in 0..cropheight {
        let inb = &src[(row+y)*width+x..];
        for col in 0..cropwidth {
          let out_row = rotatedwidth - (cropheight + 1 - row + (col >> 1));
          let out_col = ((col+1) >> 1) + row;
          out[out_row*rotatedwidth+out_col] = inb[col];
        }
      }

      (rotatedwidth, rotatedheight, out)
    } else {
      let rotatedwidth = cropwidth + cropheight/2;
      let rotatedheight = rotatedwidth-1;

      let mut out: Vec<u16> = vec![0; rotatedwidth * rotatedheight];
      for row in 0..cropheight {
        let inb = &src[(row+y)*width+x..];
        for col in 0..cropwidth {
          let out_row = cropwidth - 1 - col + (row>>1);
          let out_col = ((row+1) >> 1) + col;
          out[out_row*rotatedwidth+out_col] = inb[col];
        }
      }

      (rotatedwidth, rotatedheight, out)
    }
  }
}
<|endoftext|>


<commit_before>use super::write_code;
use crate::html::format::Buffer;
use expect_test::expect_file;
use rustc_span::edition::Edition;

const STYLE: &str = r#"

"#;

#[test]
fn test_html_highlighting() {
    let src = include_str!("fixtures/sample.rs");
    let html = {
        let mut out = Buffer::new();
        write_code(&mut out, src, Edition::Edition2018);
        format!("{}
{}
\n", STYLE, out.into_inner())
    };
    expect_file!["fixtures/sample.html"].assert_eq(&html);
}

#[test]
fn test_dos_backline() {
    let src = "pub fn foo() {\r\n\
    println!(\"foo\");\r\n\
}\r\n";
    let mut html = Buffer::new();
    write_code(&mut html, src, Edition::Edition2018);
    expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
}
<commit_msg>Update highlight tests<commit_after>use super::write_code;
use crate::html::format::Buffer;
use expect_test::expect_file;
use rustc_span::edition::Edition;
use rustc_span::with_default_session_globals;

const STYLE: &str = r#"

"#;

#[test]
fn test_html_highlighting() {
    with_default_session_globals(|| {
        let src = include_str!("fixtures/sample.rs");
        let html = {
            let mut out = Buffer::new();
            write_code(&mut out, src, Edition::Edition2018);
            format!("{}
{}
\n", STYLE, out.into_inner())
        };
        expect_file!["fixtures/sample.html"].assert_eq(&html);
    });
}

#[test]
fn test_dos_backline() {
    with_default_session_globals(|| {
        let src = "pub fn foo() {\r\n\
    println!(\"foo\");\r\n\
}\r\n";
        let mut html = Buffer::new();
        write_code(&mut html, src, Edition::Edition2018);
        expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
    });
}
<|endoftext|>


<commit_before>use sodiumoxide::crypto::{
    hash::sha256::DIGESTBYTES,
    sign::{PUBLICKEYBYTES, SIGNATUREBYTES},
};
use std::io::{Cursor, Error, ErrorKind, Read};

use crate::asset::Asset;
use crate::crypto::{PublicKey, ScriptHash, SigPair, Signature};

macro_rules! read_exact_bytes {
    ($self:expr, $len:expr) => {{
        let mut buf = Vec::with_capacity($len);
        unsafe {
            buf.set_len($len);
        }
        $self.read_exact(&mut buf)?;
        buf
    }};
}

#[inline]
fn zigzag_encode(from: i64) -> u64 {
    ((from << 1) ^ (from >> 63)) as u64
}

#[inline]
fn zigzag_decode(from: u64) -> i64 {
    ((from >> 1) ^ (-((from & 1) as i64)) as u64) as i64
}

pub trait BufWrite {
    fn push_u16(&mut self, num: u16);
    fn push_u32(&mut self, num: u32);
    fn push_i64(&mut self, num: i64);
    fn push_var_i64(&mut self, num: i64);
    fn push_u64(&mut self, num: u64);
    fn push_bytes(&mut self, slice: &[u8]);
    fn push_pub_key(&mut self, key: &PublicKey);
    fn push_script_hash(&mut self, hash: &ScriptHash);
    fn push_sig_pair(&mut self, pair: &SigPair);
    fn push_asset(&mut self, asset: Asset);
}

impl BufWrite for Vec<u8> {
    fn push_u16(&mut self, num: u16) {
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_u32(&mut self, num: u32) {
        self.push((num >> 24) as u8);
        self.push((num >> 16) as u8);
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_i64(&mut self, num: i64) {
        self.push((num >> 56) as u8);
        self.push((num >> 48) as u8);
        self.push((num >> 40) as u8);
        self.push((num >> 32) as u8);
        self.push((num >> 24) as u8);
        self.push((num >> 16) as u8);
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_var_i64(&mut self, num: i64) {
        let mut more = true;
        let mut num = zigzag_encode(num);

        while more {
            let mut byte: u8 = (num & 0x7F) as u8;
            num >>= 7;

            if num == 0 {
                more = false;
            } else {
                byte |= 0x80;
            }

            self.push(byte);
        }
    }

    fn push_u64(&mut self, num: u64) {
        self.push((num >> 56) as u8);
        self.push((num >> 48) as u8);
        self.push((num >> 40) as u8);
        self.push((num >> 32) as u8);
        self.push((num >> 24) as u8);
        self.push((num >> 16) as u8);
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_bytes(&mut self, other: &[u8]) {
        if other.is_empty() {
            self.push_u32(0);
            return;
        }
        self.push_u32(other.len() as u32);
        self.extend_from_slice(other);
    }

    fn push_pub_key(&mut self, key: &PublicKey) {
        self.extend_from_slice(key.as_ref());
    }

    fn push_script_hash(&mut self, hash: &ScriptHash) {
        self.extend_from_slice(hash.as_ref());
    }

    fn push_sig_pair(&mut self, pair: &SigPair) {
        self.push_pub_key(&pair.pub_key);
        self.extend_from_slice(pair.signature.as_ref());
    }

    fn push_asset(&mut self, asset: Asset) {
        self.push_i64(asset.amount);
    }
}

pub trait BufRead {
    fn take_u8(&mut self) -> Result<u8, Error>;
    fn take_u16(&mut self) -> Result<u16, Error>;
    fn take_u32(&mut self) -> Result<u32, Error>;
    fn take_i64(&mut self) -> Result<i64, Error>;
    fn take_var_i64(&mut self) -> Result<i64, Error>;
    fn take_u64(&mut self) -> Result<u64, Error>;
    fn take_bytes(&mut self) -> Result<Vec<u8>, Error>;
    fn take_pub_key(&mut self) -> Result<PublicKey, Error>;
    fn take_script_hash(&mut self) -> Result<ScriptHash, Error>;
    fn take_sig_pair(&mut self) -> Result<SigPair, Error>;
    fn take_asset(&mut self) -> Result<Asset, Error>;
}

impl<T: AsRef<[u8]> + Read> BufRead for Cursor<T> {
    fn take_u8(&mut self) -> Result<u8, Error> {
        let mut buf = [0u8; 1];
        self.read_exact(&mut buf)?;
        Ok(buf[0])
    }

    fn take_u16(&mut self) -> Result<u16, Error> {
        let mut buf = [0u8; 2];
        self.read_exact(&mut buf)?;
        Ok((u16::from(buf[0]) << 8) | u16::from(buf[1]))
    }

    fn take_u32(&mut self) -> Result<u32, Error> {
        let mut buf = [0u8; 4];
        self.read_exact(&mut buf)?;
        Ok(u32_from_buf!(buf))
    }

    fn take_i64(&mut self) -> Result<i64, Error> {
        let mut buf = [0u8; 8];
        self.read_exact(&mut buf)?;
        Ok((i64::from(buf[0]) << 56)
            | (i64::from(buf[1]) << 48)
            | (i64::from(buf[2]) << 40)
            | (i64::from(buf[3]) << 32)
            | (i64::from(buf[4]) << 24)
            | (i64::from(buf[5]) << 16)
            | (i64::from(buf[6]) << 8)
            | i64::from(buf[7]))
    }

    fn take_var_i64(&mut self) -> Result<i64, Error> {
        let mut result: u64 = 0;
        let mut shift = 0;
        let mut buf = [0u8; 1];
        loop {
            if shift > 63 {
                return Err(Error::new(ErrorKind::Other, "overflow taking varint"));
            }

            self.read_exact(&mut buf)?;
            let byte = buf[0];

            result |= ((byte & 0x7F) as u64) << shift;
            if byte & 0x80 == 0 {
                break;
            }

            shift += 7;
        }

        Ok(zigzag_decode(result))
    }

    fn take_u64(&mut self) -> Result<u64, Error> {
        let mut buf = [0u8; 8];
        self.read_exact(&mut buf)?;
        Ok(u64_from_buf!(buf))
    }

    fn take_bytes(&mut self) -> Result<Vec<u8>, Error> {
        let len = self.take_u32()? as usize;
        let buf = read_exact_bytes!(self, len);
        Ok(buf)
    }

    fn take_pub_key(&mut self) -> Result<PublicKey, Error> {
        let buf = read_exact_bytes!(self, PUBLICKEYBYTES);
        PublicKey::from_slice(&buf)
            .ok_or_else(|| Error::new(ErrorKind::Other, "incorrect public key length"))
    }

    fn take_script_hash(&mut self) -> Result<ScriptHash, Error> {
        let buf = read_exact_bytes!(self, DIGESTBYTES);
        ScriptHash::from_slice(&buf)
            .ok_or_else(|| Error::new(ErrorKind::Other, "incorrect script hash length"))
    }

    fn take_sig_pair(&mut self) -> Result<SigPair, Error> {
        let pub_key = self.take_pub_key()?;
        let signature = {
            let buf = read_exact_bytes!(self, SIGNATUREBYTES);
            Signature::from_slice(&buf)
                .ok_or_else(|| Error::new(ErrorKind::Other, "incorrect signature length"))?
        };
        Ok(SigPair { pub_key, signature })
    }

    fn take_asset(&mut self) -> Result<Asset, Error> {
        let amount = self.take_i64()?;
        Ok(Asset::new(amount))
    }
}

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

    #[test]
    fn u32_serialization() {
        let num: u32 = 0x0A0B0C0D;
        let mut v = Vec::with_capacity(4);
        v.push_u32(num);
        assert_eq!(v, [0x0A, 0x0B, 0x0C, 0x0D]);
    }

    #[test]
    fn u64_serialization() {
        let num: u64 = 0x0A0B0C0D_0A0B0C0D;
        let mut v = Vec::with_capacity(8);
        v.push_u64(num);

        assert_eq!(v, [0x0A, 0x0B, 0x0C, 0x0D, 0x0A, 0x0B, 0x0C, 0x0D]);
        let dec = Cursor::<&[u8]>::new(&v).take_u64().unwrap();
        assert_eq!(num, dec);
    }

    #[test]
    fn asset_serialization() {
        let a = "12.34567 GRAEL".parse().unwrap();
        let mut v = vec![];
        v.push_asset(a);

        let mut c = Cursor::<&[u8]>::new(&v);
        let b = c.take_asset().unwrap();
        assert_eq!(a.to_string(), b.to_string());
    }

    #[test]
    fn zigzag() {
        fn cmp(decoded: i64, encoded: u64) {
            assert_eq!(decoded, zigzag_decode(encoded));
            assert_eq!(encoded, zigzag_encode(decoded));
        }

        cmp(0, 0);
        cmp(-1, 1);
        cmp(1, 2);
        cmp(-2, 3);
        cmp(2147483647, 4294967294);
        cmp(-2147483648, 4294967295);
        cmp(9223372036854775807, 18446744073709551614);
        cmp(-9223372036854775808, 18446744073709551615);
    }

    #[test]
    fn var_i64_serialization() {
        let mut buf = vec![];
        buf.push_var_i64(0);
        buf.push_var_i64(300);
        buf.push_var_i64(-300);
        buf.push_var_i64(i64::max_value());
        buf.push_var_i64(i64::min_value());
        buf.extend(vec![
            0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01,
        ]);

        let mut c = Cursor::<&[u8]>::new(&buf);
        assert_eq!(c.take_var_i64().unwrap(), 0);
        assert_eq!(c.take_var_i64().unwrap(), 300);
        assert_eq!(c.take_var_i64().unwrap(), -300);
        assert_eq!(c.take_var_i64().unwrap(), i64::max_value());
        assert_eq!(c.take_var_i64().unwrap(), i64::min_value());
        assert_eq!(c.take_var_i64().unwrap(), 1 << 62);
    }

    #[test]
    fn var_i64_serialization_overflow() {
        use std::error;

        let buf = vec![
            0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0,
        ];
        let mut c = Cursor::<&[u8]>::new(&buf);
        assert_eq!(
            error::Error::description(&c.take_var_i64().unwrap_err()),
            "overflow taking varint"
        );
    }

    #[test]
    fn var_i64_serialization_eof() {
        let buf = vec![0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80];
        let mut c = Cursor::<&[u8]>::new(&buf);
        assert_eq!(
            c.take_var_i64().unwrap_err().kind(),
            ErrorKind::UnexpectedEof
        );
    }
}
<commit_msg>Add more var i64 serialization tests<commit_after>use sodiumoxide::crypto::{
    hash::sha256::DIGESTBYTES,
    sign::{PUBLICKEYBYTES, SIGNATUREBYTES},
};
use std::io::{Cursor, Error, ErrorKind, Read};

use crate::asset::Asset;
use crate::crypto::{PublicKey, ScriptHash, SigPair, Signature};

macro_rules! read_exact_bytes {
    ($self:expr, $len:expr) => {{
        let mut buf = Vec::with_capacity($len);
        unsafe {
            buf.set_len($len);
        }
        $self.read_exact(&mut buf)?;
        buf
    }};
}

#[inline]
fn zigzag_encode(from: i64) -> u64 {
    ((from << 1) ^ (from >> 63)) as u64
}

#[inline]
fn zigzag_decode(from: u64) -> i64 {
    ((from >> 1) ^ (-((from & 1) as i64)) as u64) as i64
}

pub trait BufWrite {
    fn push_u16(&mut self, num: u16);
    fn push_u32(&mut self, num: u32);
    fn push_i64(&mut self, num: i64);
    fn push_var_i64(&mut self, num: i64);
    fn push_u64(&mut self, num: u64);
    fn push_bytes(&mut self, slice: &[u8]);
    fn push_pub_key(&mut self, key: &PublicKey);
    fn push_script_hash(&mut self, hash: &ScriptHash);
    fn push_sig_pair(&mut self, pair: &SigPair);
    fn push_asset(&mut self, asset: Asset);
}

impl BufWrite for Vec<u8> {
    fn push_u16(&mut self, num: u16) {
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_u32(&mut self, num: u32) {
        self.push((num >> 24) as u8);
        self.push((num >> 16) as u8);
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_i64(&mut self, num: i64) {
        self.push((num >> 56) as u8);
        self.push((num >> 48) as u8);
        self.push((num >> 40) as u8);
        self.push((num >> 32) as u8);
        self.push((num >> 24) as u8);
        self.push((num >> 16) as u8);
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_var_i64(&mut self, num: i64) {
        let mut more = true;
        let mut num = zigzag_encode(num);

        while more {
            let mut byte: u8 = (num & 0x7F) as u8;
            num >>= 7;

            if num == 0 {
                more = false;
            } else {
                byte |= 0x80;
            }

            self.push(byte);
        }
    }

    fn push_u64(&mut self, num: u64) {
        self.push((num >> 56) as u8);
        self.push((num >> 48) as u8);
        self.push((num >> 40) as u8);
        self.push((num >> 32) as u8);
        self.push((num >> 24) as u8);
        self.push((num >> 16) as u8);
        self.push((num >> 8) as u8);
        self.push(num as u8);
    }

    fn push_bytes(&mut self, other: &[u8]) {
        if other.is_empty() {
            self.push_u32(0);
            return;
        }
        self.push_u32(other.len() as u32);
        self.extend_from_slice(other);
    }

    fn push_pub_key(&mut self, key: &PublicKey) {
        self.extend_from_slice(key.as_ref());
    }

    fn push_script_hash(&mut self, hash: &ScriptHash) {
        self.extend_from_slice(hash.as_ref());
    }

    fn push_sig_pair(&mut self, pair: &SigPair) {
        self.push_pub_key(&pair.pub_key);
        self.extend_from_slice(pair.signature.as_ref());
    }

    fn push_asset(&mut self, asset: Asset) {
        self.push_i64(asset.amount);
    }
}

pub trait BufRead {
    fn take_u8(&mut self) -> Result<u8, Error>;
    fn take_u16(&mut self) -> Result<u16, Error>;
    fn take_u32(&mut self) -> Result<u32, Error>;
    fn take_i64(&mut self) -> Result<i64, Error>;
    fn take_var_i64(&mut self) -> Result<i64, Error>;
    fn take_u64(&mut self) -> Result<u64, Error>;
    fn take_bytes(&mut self) -> Result<Vec<u8>, Error>;
    fn take_pub_key(&mut self) -> Result<PublicKey, Error>;
    fn take_script_hash(&mut self) -> Result<ScriptHash, Error>;
    fn take_sig_pair(&mut self) -> Result<SigPair, Error>;
    fn take_asset(&mut self) -> Result<Asset, Error>;
}

impl<T: AsRef<[u8]> + Read> BufRead for Cursor<T> {
    fn take_u8(&mut self) -> Result<u8, Error> {
        let mut buf = [0u8; 1];
        self.read_exact(&mut buf)?;
        Ok(buf[0])
    }

    fn take_u16(&mut self) -> Result<u16, Error> {
        let mut buf = [0u8; 2];
        self.read_exact(&mut buf)?;
        Ok((u16::from(buf[0]) << 8) | u16::from(buf[1]))
    }

    fn take_u32(&mut self) -> Result<u32, Error> {
        let mut buf = [0u8; 4];
        self.read_exact(&mut buf)?;
        Ok(u32_from_buf!(buf))
    }

    fn take_i64(&mut self) -> Result<i64, Error> {
        let mut buf = [0u8; 8];
        self.read_exact(&mut buf)?;
        Ok((i64::from(buf[0]) << 56)
            | (i64::from(buf[1]) << 48)
            | (i64::from(buf[2]) << 40)
            | (i64::from(buf[3]) << 32)
            | (i64::from(buf[4]) << 24)
            | (i64::from(buf[5]) << 16)
            | (i64::from(buf[6]) << 8)
            | i64::from(buf[7]))
    }

    fn take_var_i64(&mut self) -> Result<i64, Error> {
        let mut result: u64 = 0;
        let mut shift = 0;
        let mut buf = [0u8; 1];
        loop {
            if shift > 63 {
                return Err(Error::new(ErrorKind::Other, "overflow taking varint"));
            }

            self.read_exact(&mut buf)?;
            let byte = buf[0];

            result |= ((byte & 0x7F) as u64) << shift;
            if byte & 0x80 == 0 {
                break;
            }

            shift += 7;
        }

        Ok(zigzag_decode(result))
    }

    fn take_u64(&mut self) -> Result<u64, Error> {
        let mut buf = [0u8; 8];
        self.read_exact(&mut buf)?;
        Ok(u64_from_buf!(buf))
    }

    fn take_bytes(&mut self) -> Result<Vec<u8>, Error> {
        let len = self.take_u32()? as usize;
        let buf = read_exact_bytes!(self, len);
        Ok(buf)
    }

    fn take_pub_key(&mut self) -> Result<PublicKey, Error> {
        let buf = read_exact_bytes!(self, PUBLICKEYBYTES);
        PublicKey::from_slice(&buf)
            .ok_or_else(|| Error::new(ErrorKind::Other, "incorrect public key length"))
    }

    fn take_script_hash(&mut self) -> Result<ScriptHash, Error> {
        let buf = read_exact_bytes!(self, DIGESTBYTES);
        ScriptHash::from_slice(&buf)
            .ok_or_else(|| Error::new(ErrorKind::Other, "incorrect script hash length"))
    }

    fn take_sig_pair(&mut self) -> Result<SigPair, Error> {
        let pub_key = self.take_pub_key()?;
        let signature = {
            let buf = read_exact_bytes!(self, SIGNATUREBYTES);
            Signature::from_slice(&buf)
                .ok_or_else(|| Error::new(ErrorKind::Other, "incorrect signature length"))?
        };
        Ok(SigPair { pub_key, signature })
    }

    fn take_asset(&mut self) -> Result<Asset, Error> {
        let amount = self.take_i64()?;
        Ok(Asset::new(amount))
    }
}

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

    #[test]
    fn u32_serialization() {
        let num: u32 = 0x0A0B0C0D;
        let mut v = Vec::with_capacity(4);
        v.push_u32(num);
        assert_eq!(v, [0x0A, 0x0B, 0x0C, 0x0D]);
    }

    #[test]
    fn u64_serialization() {
        let num: u64 = 0x0A0B0C0D_0A0B0C0D;
        let mut v = Vec::with_capacity(8);
        v.push_u64(num);

        assert_eq!(v, [0x0A, 0x0B, 0x0C, 0x0D, 0x0A, 0x0B, 0x0C, 0x0D]);
        let dec = Cursor::<&[u8]>::new(&v).take_u64().unwrap();
        assert_eq!(num, dec);
    }

    #[test]
    fn asset_serialization() {
        let a = "12.34567 GRAEL".parse().unwrap();
        let mut v = vec![];
        v.push_asset(a);

        let mut c = Cursor::<&[u8]>::new(&v);
        let b = c.take_asset().unwrap();
        assert_eq!(a.to_string(), b.to_string());
    }

    #[test]
    fn zigzag() {
        fn cmp(decoded: i64, encoded: u64) {
            assert_eq!(decoded, zigzag_decode(encoded));
            assert_eq!(encoded, zigzag_encode(decoded));
        }

        cmp(0, 0);
        cmp(-1, 1);
        cmp(1, 2);
        cmp(-2, 3);
        cmp(2147483647, 4294967294);
        cmp(-2147483648, 4294967295);
        cmp(9223372036854775807, 18446744073709551614);
        cmp(-9223372036854775808, 18446744073709551615);
    }

    #[test]
    fn var_i64_serialization() {
        let mut buf = vec![];
        buf.push_var_i64(0);
        buf.push_var_i64(300);
        buf.push_var_i64(-300);
        buf.push_var_i64(i64::max_value());
        buf.push_var_i64(i64::min_value());
        // Outputs 0 as only the first bit is checked on the final byte with a shift of 63
        buf.extend(vec![
            0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7E,
        ]);
        // Outputs 1 << 62 as bit 62 is set
        buf.extend(vec![
            0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01,
        ]);

        let mut c = Cursor::<&[u8]>::new(&buf);
        assert_eq!(c.take_var_i64().unwrap(), 0);
        assert_eq!(c.take_var_i64().unwrap(), 300);
        assert_eq!(c.take_var_i64().unwrap(), -300);
        assert_eq!(c.take_var_i64().unwrap(), i64::max_value());
        assert_eq!(c.take_var_i64().unwrap(), i64::min_value());
        assert_eq!(c.take_var_i64().unwrap(), 0);
        assert_eq!(c.take_var_i64().unwrap(), 1 << 62);
    }

    #[test]
    fn var_i64_serialization_overflow() {
        use std::error;

        let buf = vec![
            0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0,
        ];
        let mut c = Cursor::<&[u8]>::new(&buf);
        assert_eq!(
            error::Error::description(&c.take_var_i64().unwrap_err()),
            "overflow taking varint"
        );
    }

    #[test]
    fn var_i64_serialization_eof() {
        let buf = vec![0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80];
        let mut c = Cursor::<&[u8]>::new(&buf);
        assert_eq!(
            c.take_var_i64().unwrap_err().kind(),
            ErrorKind::UnexpectedEof
        );
    }
}
<|endoftext|>