<commit_before>//! Initialization logic for a generic instance of the `Allocate` channel allocation trait.

use std::thread;
#[cfg(feature = "arg_parse")]
use std::io::BufRead;
#[cfg(feature = "arg_parse")]
use getopts;
use std::sync::Arc;

use std::any::Any;

use allocator::{AllocateBuilder, Thread, Process, Generic, GenericBuilder};
// use allocator::zero_copy::allocator_process::ProcessBuilder;
use allocator::zero_copy::initialize::initialize_networking;

/// Possible configurations for the communication infrastructure.
pub enum Configuration {
    /// Use one thread.
    Thread,
    /// Use one process with an indicated number of threads.
    Process(usize),
    /// Expect multiple processes indicated by `(threads, process, host_list, report)`.
    Cluster(usize, usize, Vec<String>, bool)
}

#[cfg(feature = "arg_parse")]
impl Configuration {

    /// Constructs a new configuration by parsing supplied text arguments.
    ///
    /// Most commonly, this uses `std::env::Args()` as the supplied iterator.
    pub fn from_args<I: Iterator<Item=String>>(args: I) -> Result<Configuration,String> {

        let mut opts = getopts::Options::new();
        opts.optopt("w", "threads", "number of per-process worker threads", "NUM");
        opts.optopt("p", "process", "identity of this process", "IDX");
        opts.optopt("n", "processes", "number of processes", "NUM");
        opts.optopt("h", "hostfile", "text file whose lines are process addresses", "FILE");
        opts.optflag("r", "report", "reports connection progress");

        opts.parse(args)
            .map_err(|e| format!("{:?}", e))
            .map(|matches| {

            // let mut config = Configuration::new(1, 0, Vec::new());
            let threads = matches.opt_str("w").map(|x| x.parse().unwrap_or(1)).unwrap_or(1);
            let process = matches.opt_str("p").map(|x| x.parse().unwrap_or(0)).unwrap_or(0);
            let processes = matches.opt_str("n").map(|x| x.parse().unwrap_or(1)).unwrap_or(1);
            let report = matches.opt_present("report");

            assert!(process < processes);

            if processes > 1 {
                let mut addresses = Vec::new();
                if let Some(hosts) = matches.opt_str("h") {
                    let reader = ::std::io::BufReader::new(::std::fs::File::open(hosts.clone()).unwrap());
                    for x in reader.lines().take(processes) {
                        addresses.push(x.unwrap());
                    }
                    if addresses.len() < processes {
                        panic!("could only read {} addresses from {}, but -n: {}", addresses.len(), hosts, processes);
                    }
                }
                else {
                    for index in 0..processes {
                        addresses.push(format!("localhost:{}", 2101 + index));
                    }
                }

                assert!(processes == addresses.len());
                Configuration::Cluster(threads, process, addresses, report)
            }
            else if threads > 1 { Configuration::Process(threads) }
            else { Configuration::Thread }
        })
    }

    /// Attempts to assemble the described communication infrastructure.
    pub fn try_build(self, logger: Option<LogBuilder>) -> Result<(Vec<GenericBuilder>, Box<Any>), String> {
        let logger = logger.unwrap_or_else()
        match self {
            Configuration::Thread => {
                Ok((vec![GenericBuilder::Thread(Thread)], Box::new(())))
            },
            Configuration::Process(threads) => {
                Ok((Process::new_vector(threads).into_iter().map(|x| GenericBuilder::Process(x)).collect(), Box::new(())))
            },
            Configuration::Cluster(threads, process, addresses, report) => {
                if let Ok((stuff, guard)) = initialize_networking(addresses, process, threads, report, logger) {
                    Ok((stuff.into_iter().map(|x| GenericBuilder::ZeroCopy(x)).collect(), Box::new(guard)))
                }
                else {
                    Err("failed to initialize networking".to_owned())
                }
            },
        }
    }
}

type LogBuilder = Arc<Fn(::logging::CommsSetup)->::logging::CommsLogger+Send+Sync>;

/// Initializes communication and executes a distributed computation.
///
/// This method allocates an `allocator::Generic` for each thread, spawns local worker threads,
/// and invokes the supplied function with the allocator.
/// The method returns a `WorkerGuards<T>` which can be `join`ed to retrieve the return values
/// (or errors) of the workers.
///
///
/// #Examples
/// ```
/// // configure for two threads, just one process.
/// let config = timely_communication::Configuration::Process(2);
///
/// // create a source of inactive loggers.
/// let logger = ::std::sync::Arc::new(|_| timely_communication::logging::BufferingLogger::new_inactive());
///
/// // initializes communication, spawns workers
/// let guards = timely_communication::initialize(config, logger, |mut allocator| {
///     println!("worker {} started", allocator.index());
///
///     // allocates pair of senders list and one receiver.
///     let (mut senders, mut receiver, _) = allocator.allocate();
///
///     // send typed data along each channel
///     use timely_communication::Message;
///     senders[0].send(Message::from_typed(format!("hello, {}", 0)));
///     senders[1].send(Message::from_typed(format!("hello, {}", 1)));
///
///     // no support for termination notification,
///     // we have to count down ourselves.
///     let mut expecting = 2;
///     while expecting > 0 {
///         allocator.pre_work();
///         if let Some(message) = receiver.recv() {
///             use std::ops::Deref;
///             println!("worker {}: received: <{}>", allocator.index(), message.deref());
///             expecting -= 1;
///         }
///         allocator.post_work();
///     }
///
///     // optionally, return something
///     allocator.index()
/// });
///
/// // computation runs until guards are joined or dropped.
/// if let Ok(guards) = guards {
///     for guard in guards.join() {
///         println!("result: {:?}", guard);
///     }
/// }
/// else { println!("error in computation"); }
/// ```
///
/// The should produce output like:
///
/// ```ignore
/// worker 0 started
/// worker 1 started
/// worker 0: received: <hello, 0>
/// worker 1: received: <hello, 1>
/// worker 0: received: <hello, 0>
/// worker 1: received: <hello, 1>
/// result: Ok(0)
/// result: Ok(1)
/// ```
pub fn initialize<T:Send+'static, F: Fn(Generic)->T+Send+Sync+'static>(
    config: Configuration,
    log_sender: LogBuilder,
    func: F,
) -> Result<WorkerGuards<T>,String> {
    let (allocators, others) = try!(config.try_build(log_sender));
    initialize_from(allocators, others, func)
}

/// Initializes computation and runs a distributed computation.
///
/// This version of `initialize` allows you to explicitly specify the allocators that
/// you want to use, by providing an explicit list of allocator builders. Additionally,
/// you provide `others`, a `Box<Any>` which will be held by the resulting worker guard
/// and dropped when it is dropped, which allows you to join communication threads.
///
/// #Examples
/// ```
/// use timely_communication::Allocate;
/// // configure for two threads, just one process.
/// let builders = timely_communication::allocator::process::Process::new_vector(2);
///
/// // initializes communication, spawns workers
/// let guards = timely_communication::initialize_from(builders, Box::new(()), |mut allocator| {
///     println!("worker {} started", allocator.index());
///
///     // allocates pair of senders list and one receiver.
///     let (mut senders, mut receiver, _) = allocator.allocate();
///
///     // send typed data along each channel
///     use timely_communication::Message;
///     senders[0].send(Message::from_typed(format!("hello, {}", 0)));
///     senders[1].send(Message::from_typed(format!("hello, {}", 1)));
///
///     // no support for termination notification,
///     // we have to count down ourselves.
///     let mut expecting = 2;
///     while expecting > 0 {
///         allocator.pre_work();
///         if let Some(message) = receiver.recv() {
///             use std::ops::Deref;
///             println!("worker {}: received: <{}>", allocator.index(), message.deref());
///             expecting -= 1;
///         }
///         allocator.post_work();
///     }
///
///     // optionally, return something
///     allocator.index()
/// });
///
/// // computation runs until guards are joined or dropped.
/// if let Ok(guards) = guards {
///     for guard in guards.join() {
///         println!("result: {:?}", guard);
///     }
/// }
/// else { println!("error in computation"); }
/// ```
pub fn initialize_from<A, T, F>(
    builders: Vec<A>,
    others: Box<Any>,
    func: F,
) -> Result<WorkerGuards<T>,String>
where
    A: AllocateBuilder+'static,
    T: Send+'static,
    F: Fn(<A as AllocateBuilder>::Allocator)->T+Send+Sync+'static
{
    let logic = Arc::new(func);
    let mut guards = Vec::new();
    for (index, builder) in builders.into_iter().enumerate() {
        let clone = logic.clone();
        guards.push(try!(thread::Builder::new()
                            .name(format!("worker thread {}", index))
                            .spawn(move || {
                                let communicator = builder.build();
                                (*clone)(communicator)
                            })
                            .map_err(|e| format!("{:?}", e))));
    }

    Ok(WorkerGuards { guards, others })
}

/// Maintains `JoinHandle`s for worker threads.
pub struct WorkerGuards<T:Send+'static> {
    guards: Vec<::std::thread::JoinHandle<T>>,
    others: Box<Any>,
}

impl<T:Send+'static> WorkerGuards<T> {
    /// Waits on the worker threads and returns the results they produce.
    pub fn join(mut self) -> Vec<Result<T, String>> {
        self.guards.drain(..)
                   .map(|guard| guard.join().map_err(|e| format!("{:?}", e)))
                   .collect()
    }
}

impl<T:Send+'static> Drop for WorkerGuards<T> {
    fn drop(&mut self) {
        for guard in self.guards.drain(..) {
            guard.join().expect("Worker panic");
        }
        // println!("WORKER THREADS JOINED");
    }
}
<commit_msg>stray line; oops<commit_after>//! Initialization logic for a generic instance of the `Allocate` channel allocation trait.

use std::thread;
#[cfg(feature = "arg_parse")]
use std::io::BufRead;
#[cfg(feature = "arg_parse")]
use getopts;
use std::sync::Arc;

use std::any::Any;

use allocator::{AllocateBuilder, Thread, Process, Generic, GenericBuilder};
// use allocator::zero_copy::allocator_process::ProcessBuilder;
use allocator::zero_copy::initialize::initialize_networking;

/// Possible configurations for the communication infrastructure.
pub enum Configuration {
    /// Use one thread.
    Thread,
    /// Use one process with an indicated number of threads.
    Process(usize),
    /// Expect multiple processes indicated by `(threads, process, host_list, report)`.
    Cluster(usize, usize, Vec<String>, bool)
}

#[cfg(feature = "arg_parse")]
impl Configuration {

    /// Constructs a new configuration by parsing supplied text arguments.
    ///
    /// Most commonly, this uses `std::env::Args()` as the supplied iterator.
    pub fn from_args<I: Iterator<Item=String>>(args: I) -> Result<Configuration,String> {

        let mut opts = getopts::Options::new();
        opts.optopt("w", "threads", "number of per-process worker threads", "NUM");
        opts.optopt("p", "process", "identity of this process", "IDX");
        opts.optopt("n", "processes", "number of processes", "NUM");
        opts.optopt("h", "hostfile", "text file whose lines are process addresses", "FILE");
        opts.optflag("r", "report", "reports connection progress");

        opts.parse(args)
            .map_err(|e| format!("{:?}", e))
            .map(|matches| {

            // let mut config = Configuration::new(1, 0, Vec::new());
            let threads = matches.opt_str("w").map(|x| x.parse().unwrap_or(1)).unwrap_or(1);
            let process = matches.opt_str("p").map(|x| x.parse().unwrap_or(0)).unwrap_or(0);
            let processes = matches.opt_str("n").map(|x| x.parse().unwrap_or(1)).unwrap_or(1);
            let report = matches.opt_present("report");

            assert!(process < processes);

            if processes > 1 {
                let mut addresses = Vec::new();
                if let Some(hosts) = matches.opt_str("h") {
                    let reader = ::std::io::BufReader::new(::std::fs::File::open(hosts.clone()).unwrap());
                    for x in reader.lines().take(processes) {
                        addresses.push(x.unwrap());
                    }
                    if addresses.len() < processes {
                        panic!("could only read {} addresses from {}, but -n: {}", addresses.len(), hosts, processes);
                    }
                }
                else {
                    for index in 0..processes {
                        addresses.push(format!("localhost:{}", 2101 + index));
                    }
                }

                assert!(processes == addresses.len());
                Configuration::Cluster(threads, process, addresses, report)
            }
            else if threads > 1 { Configuration::Process(threads) }
            else { Configuration::Thread }
        })
    }

    /// Attempts to assemble the described communication infrastructure.
    pub fn try_build(self, logger: LogBuilder) -> Result<(Vec<GenericBuilder>, Box<Any>), String> {
        // let logger = logger.unwrap_or_else()
        match self {
            Configuration::Thread => {
                Ok((vec![GenericBuilder::Thread(Thread)], Box::new(())))
            },
            Configuration::Process(threads) => {
                Ok((Process::new_vector(threads).into_iter().map(|x| GenericBuilder::Process(x)).collect(), Box::new(())))
            },
            Configuration::Cluster(threads, process, addresses, report) => {
                if let Ok((stuff, guard)) = initialize_networking(addresses, process, threads, report, logger) {
                    Ok((stuff.into_iter().map(|x| GenericBuilder::ZeroCopy(x)).collect(), Box::new(guard)))
                }
                else {
                    Err("failed to initialize networking".to_owned())
                }
            },
        }
    }
}

type LogBuilder = Arc<Fn(::logging::CommsSetup)->::logging::CommsLogger+Send+Sync>;

/// Initializes communication and executes a distributed computation.
///
/// This method allocates an `allocator::Generic` for each thread, spawns local worker threads,
/// and invokes the supplied function with the allocator.
/// The method returns a `WorkerGuards<T>` which can be `join`ed to retrieve the return values
/// (or errors) of the workers.
///
///
/// #Examples
/// ```
/// // configure for two threads, just one process.
/// let config = timely_communication::Configuration::Process(2);
///
/// // create a source of inactive loggers.
/// let logger = ::std::sync::Arc::new(|_| timely_communication::logging::BufferingLogger::new_inactive());
///
/// // initializes communication, spawns workers
/// let guards = timely_communication::initialize(config, logger, |mut allocator| {
///     println!("worker {} started", allocator.index());
///
///     // allocates pair of senders list and one receiver.
///     let (mut senders, mut receiver, _) = allocator.allocate();
///
///     // send typed data along each channel
///     use timely_communication::Message;
///     senders[0].send(Message::from_typed(format!("hello, {}", 0)));
///     senders[1].send(Message::from_typed(format!("hello, {}", 1)));
///
///     // no support for termination notification,
///     // we have to count down ourselves.
///     let mut expecting = 2;
///     while expecting > 0 {
///         allocator.pre_work();
///         if let Some(message) = receiver.recv() {
///             use std::ops::Deref;
///             println!("worker {}: received: <{}>", allocator.index(), message.deref());
///             expecting -= 1;
///         }
///         allocator.post_work();
///     }
///
///     // optionally, return something
///     allocator.index()
/// });
///
/// // computation runs until guards are joined or dropped.
/// if let Ok(guards) = guards {
///     for guard in guards.join() {
///         println!("result: {:?}", guard);
///     }
/// }
/// else { println!("error in computation"); }
/// ```
///
/// The should produce output like:
///
/// ```ignore
/// worker 0 started
/// worker 1 started
/// worker 0: received: <hello, 0>
/// worker 1: received: <hello, 1>
/// worker 0: received: <hello, 0>
/// worker 1: received: <hello, 1>
/// result: Ok(0)
/// result: Ok(1)
/// ```
pub fn initialize<T:Send+'static, F: Fn(Generic)->T+Send+Sync+'static>(
    config: Configuration,
    log_sender: LogBuilder,
    func: F,
) -> Result<WorkerGuards<T>,String> {
    let (allocators, others) = try!(config.try_build(log_sender));
    initialize_from(allocators, others, func)
}

/// Initializes computation and runs a distributed computation.
///
/// This version of `initialize` allows you to explicitly specify the allocators that
/// you want to use, by providing an explicit list of allocator builders. Additionally,
/// you provide `others`, a `Box<Any>` which will be held by the resulting worker guard
/// and dropped when it is dropped, which allows you to join communication threads.
///
/// #Examples
/// ```
/// use timely_communication::Allocate;
/// // configure for two threads, just one process.
/// let builders = timely_communication::allocator::process::Process::new_vector(2);
///
/// // initializes communication, spawns workers
/// let guards = timely_communication::initialize_from(builders, Box::new(()), |mut allocator| {
///     println!("worker {} started", allocator.index());
///
///     // allocates pair of senders list and one receiver.
///     let (mut senders, mut receiver, _) = allocator.allocate();
///
///     // send typed data along each channel
///     use timely_communication::Message;
///     senders[0].send(Message::from_typed(format!("hello, {}", 0)));
///     senders[1].send(Message::from_typed(format!("hello, {}", 1)));
///
///     // no support for termination notification,
///     // we have to count down ourselves.
///     let mut expecting = 2;
///     while expecting > 0 {
///         allocator.pre_work();
///         if let Some(message) = receiver.recv() {
///             use std::ops::Deref;
///             println!("worker {}: received: <{}>", allocator.index(), message.deref());
///             expecting -= 1;
///         }
///         allocator.post_work();
///     }
///
///     // optionally, return something
///     allocator.index()
/// });
///
/// // computation runs until guards are joined or dropped.
/// if let Ok(guards) = guards {
///     for guard in guards.join() {
///         println!("result: {:?}", guard);
///     }
/// }
/// else { println!("error in computation"); }
/// ```
pub fn initialize_from<A, T, F>(
    builders: Vec<A>,
    others: Box<Any>,
    func: F,
) -> Result<WorkerGuards<T>,String>
where
    A: AllocateBuilder+'static,
    T: Send+'static,
    F: Fn(<A as AllocateBuilder>::Allocator)->T+Send+Sync+'static
{
    let logic = Arc::new(func);
    let mut guards = Vec::new();
    for (index, builder) in builders.into_iter().enumerate() {
        let clone = logic.clone();
        guards.push(try!(thread::Builder::new()
                            .name(format!("worker thread {}", index))
                            .spawn(move || {
                                let communicator = builder.build();
                                (*clone)(communicator)
                            })
                            .map_err(|e| format!("{:?}", e))));
    }

    Ok(WorkerGuards { guards, others })
}

/// Maintains `JoinHandle`s for worker threads.
pub struct WorkerGuards<T:Send+'static> {
    guards: Vec<::std::thread::JoinHandle<T>>,
    others: Box<Any>,
}

impl<T:Send+'static> WorkerGuards<T> {
    /// Waits on the worker threads and returns the results they produce.
    pub fn join(mut self) -> Vec<Result<T, String>> {
        self.guards.drain(..)
                   .map(|guard| guard.join().map_err(|e| format!("{:?}", e)))
                   .collect()
    }
}

impl<T:Send+'static> Drop for WorkerGuards<T> {
    fn drop(&mut self) {
        for guard in self.guards.drain(..) {
            guard.join().expect("Worker panic");
        }
        // println!("WORKER THREADS JOINED");
    }
}
<|endoftext|>


<commit_before>use num_traits::{FromPrimitive, Signed};
use std::fmt::Debug;

pub trait FFTnum: Copy + FromPrimitive + Signed + Debug + 'static {}

impl FFTnum for f32 {}
impl FFTnum for f64 {}

#[inline(always)]
pub fn verify_length<T>(input: &[T], output: &[T], expected: usize) {
	assert_eq!(input.len(), expected, "Input is the wrong length. Expected {}, got {}", expected, input.len());
	assert_eq!(output.len(), expected, "Output is the wrong length. Expected {}, got {}", expected, output.len());
}

#[inline(always)]
pub fn verify_length_divisible<T>(input: &[T], output: &[T], expected: usize) {
	assert_eq!(input.len() % expected, 0, "Input is the wrong length. Expected multiple of {}, got {}", expected, input.len());
	assert_eq!(input.len(), output.len(), "Input and output must have the same length. Expected {}, got {}", input.len(), output.len());
}
<commit_msg>Revert "FFTnum now requires Debug"<commit_after>use num_traits::{FromPrimitive, Signed};

pub trait FFTnum: Copy + FromPrimitive + Signed + 'static {}

impl FFTnum for f32 {}
impl FFTnum for f64 {}

#[inline(always)]
pub fn verify_length<T>(input: &[T], output: &[T], expected: usize) {
	assert_eq!(input.len(), expected, "Input is the wrong length. Expected {}, got {}", expected, input.len());
	assert_eq!(output.len(), expected, "Output is the wrong length. Expected {}, got {}", expected, output.len());
}

#[inline(always)]
pub fn verify_length_divisible<T>(input: &[T], output: &[T], expected: usize) {
	assert_eq!(input.len() % expected, 0, "Input is the wrong length. Expected multiple of {}, got {}", expected, input.len());
	assert_eq!(input.len(), output.len(), "Input and output must have the same length. Expected {}, got {}", input.len(), output.len());
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// 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 ast::*;

pub fn optimize(rules: Vec<Rule>) -> Vec<Rule> {
    rules.into_iter().map(|rule| {
        let rotate_right = |expr| {
            // TODO: Use box syntax when it gets stabilized.
            match expr {
                Expr::Seq(lhs, rhs) => {
                    let lhs = *lhs;
                    match lhs {
                        Expr::Seq(ll, lr) => {
                            Expr::Seq(
                                ll,
                                Box::new(Expr::Seq(lr, rhs))
                            )
                        }
                        lhs => Expr::Seq(Box::new(lhs), rhs)
                    }
                }
                Expr::Choice(lhs, rhs) => {
                    let lhs = *lhs;
                    match lhs {
                        Expr::Choice(ll, lr) => {
                            Expr::Choice(
                                ll,
                                Box::new(Expr::Choice(lr, rhs))
                            )
                        }
                        lhs => Expr::Choice(Box::new(lhs), rhs)
                    }
                }
                expr => expr
            }
        };

        let unpack_repetitions = |expr| {
            match expr {
                Expr::RepOnce(expr) => {
                    Expr::Seq(
                        expr.clone(),
                        Box::new(Expr::Rep(expr))
                    )
                }
                Expr::RepExact(expr, num) => {
                    (1..num + 1).map(|_| {
                                    *expr.clone()
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                Expr::RepMin(expr, min) => {
                    (1..min + 2).map(|i| {
                                    if i <= min {
                                        *expr.clone()
                                    } else {
                                        Expr::Rep(expr.clone())
                                    }
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                Expr::RepMax(expr, max) => {
                    (1..max + 1).map(|_| {
                                    Expr::Opt(expr.clone())
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                Expr::RepMinMax(expr, min, max) => {
                    (1..max + 1).map(|i| {
                                    if i <= min {
                                        *expr.clone()
                                    } else {
                                        Expr::Opt(expr.clone())
                                    }
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                expr => expr
            }
        };

        match rule {
            Rule { name, ty, expr } => Rule {
                name,
                ty,
                expr: expr.map_bottom_up(rotate_right)
                          .map_bottom_up(unpack_repetitions)
                          .map_bottom_up(|expr| {
                              if ty == RuleType::Atomic {
                                  // TODO: Use box syntax when it gets stabilized.
                                  match expr {
                                      Expr::Seq(lhs, rhs) => {
                                          match (*lhs, *rhs) {
                                              (Expr::Str(lhs), Expr::Str(rhs)) => {
                                                  Expr::Str(lhs + &rhs)
                                              }
                                              (Expr::Insens(lhs), Expr::Insens(rhs)) => {
                                                  Expr::Insens(lhs + &rhs)
                                              }
                                              (lhs, rhs) => Expr::Seq(Box::new(lhs), Box::new(rhs))
                                          }
                                      }
                                      expr => expr
                                  }
                              } else {
                                  expr
                              }
                          })
                          .map_top_down(|expr| {
                              // TODO: Use box syntax when it gets stabilized.
                              match expr {
                                  Expr::Choice(lhs, rhs) => {
                                      match (*lhs, *rhs) {
                                          (Expr::Seq(l1, r1), Expr::Seq(l2, r2)) => {
                                              if l1 == l2 {
                                                  Expr::Seq(
                                                      l1,
                                                      Box::new(Expr::Choice(
                                                          r1,
                                                          r2
                                                      ))
                                                  )
                                              } else {
                                                  Expr::Choice(
                                                      Box::new(Expr::Seq(l1, r1)),
                                                      Box::new(Expr::Seq(l2, r2))
                                                  )
                                              }
                                          }
                                          (lhs, rhs) => Expr::Choice(Box::new(lhs), Box::new(rhs))
                                      }
                                  }
                                  expr => expr
                              }
                          })
            }
        }
    }).collect()
}

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

    use quote::Ident;

    #[test]
    fn concat_strings() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("a".to_owned())),
                        Box::new(Expr::Str("b".to_owned()))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("c".to_owned())),
                        Box::new(Expr::Str("d".to_owned()))
                    ))
                )
            }
        ];
        let concatenated = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Str("abcd".to_owned())
            }
        ];

        assert_eq!(optimize(rules), concatenated);
    }

    #[test]
    fn unroll_loop_exact() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepExact(
                    Box::new(Expr::Ident(Ident::new("a"))),
                    3
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Ident(Ident::new("a"))),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Ident(Ident::new("a"))),
                        Box::new(Expr::Ident(Ident::new("a")))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn unroll_loop_max() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepMax(
                    Box::new(Expr::Str("a".to_owned())),
                    3
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Opt(
                        Box::new(Expr::Str("a".to_owned()))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Opt(
                            Box::new(Expr::Str("a".to_owned()))
                        )),
                        Box::new(Expr::Opt(
                            Box::new(Expr::Str("a".to_owned()))
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn unroll_loop_min() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepMin(
                    Box::new(Expr::Str("a".to_owned())),
                    2
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Str("a".to_owned())),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("a".to_owned())),
                        Box::new(Expr::Rep(
                            Box::new(Expr::Str("a".to_owned()))
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn unroll_loop_min_max() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepMinMax(
                    Box::new(Expr::Str("a".to_owned())),
                    2,
                    3
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    /* TODO possible room for improvement here:
                     * if the sequences were rolled out in the opposite
                     * order, we could further optimize the strings
                     * in cases like this.
                    Box::new(Expr::Str("aa".to_owned())),
                    Box::new(Expr::Opt(
                        Box::new(Expr::Str("a".to_owned()))
                    ))
                    */
                    Box::new(Expr::Str("a".to_owned())),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("a".to_owned())),
                        Box::new(Expr::Opt(
                            Box::new(Expr::Str("a".to_owned())),
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn concat_insensitive_strings() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Seq(
                        Box::new(Expr::Insens("a".to_owned())),
                        Box::new(Expr::Insens("b".to_owned()))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Insens("c".to_owned())),
                        Box::new(Expr::Insens("d".to_owned()))
                    ))
                )
            }
        ];
        let concatenated = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Insens("abcd".to_owned())
            }
        ];

        assert_eq!(optimize(rules), concatenated);
    }

    #[test]
    fn long_common_sequence() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Silent,
                expr: Expr::Choice(
                    Box::new(Expr::Seq(
                        Box::new(Expr::Ident(Ident::new("a"))),
                        Box::new(Expr::Seq(
                            Box::new(Expr::Ident(Ident::new("b"))),
                            Box::new(Expr::Ident(Ident::new("c")))
                        ))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Seq(
                            Box::new(Expr::Ident(Ident::new("a"))),
                            Box::new(Expr::Ident(Ident::new("b")))
                        )),
                        Box::new(Expr::Ident(Ident::new("d")))
                    ))
                )
            }
        ];
        let optimized = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Silent,
                expr: Expr::Seq(
                    Box::new(Expr::Ident(Ident::new("a"))),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Ident(Ident::new("b"))),
                        Box::new(Expr::Choice(
                            Box::new(Expr::Ident(Ident::new("c"))),
                            Box::new(Expr::Ident(Ident::new("d")))
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), optimized);
    }
}
<commit_msg>Renamed closure.<commit_after>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// 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 ast::*;

pub fn optimize(rules: Vec<Rule>) -> Vec<Rule> {
    rules.into_iter().map(|rule| {
        let rotate_right = |expr| {
            // TODO: Use box syntax when it gets stabilized.
            match expr {
                Expr::Seq(lhs, rhs) => {
                    let lhs = *lhs;
                    match lhs {
                        Expr::Seq(ll, lr) => {
                            Expr::Seq(
                                ll,
                                Box::new(Expr::Seq(lr, rhs))
                            )
                        }
                        lhs => Expr::Seq(Box::new(lhs), rhs)
                    }
                }
                Expr::Choice(lhs, rhs) => {
                    let lhs = *lhs;
                    match lhs {
                        Expr::Choice(ll, lr) => {
                            Expr::Choice(
                                ll,
                                Box::new(Expr::Choice(lr, rhs))
                            )
                        }
                        lhs => Expr::Choice(Box::new(lhs), rhs)
                    }
                }
                expr => expr
            }
        };

        let unroll_loops = |expr| {
            match expr {
                Expr::RepOnce(expr) => {
                    Expr::Seq(
                        expr.clone(),
                        Box::new(Expr::Rep(expr))
                    )
                }
                Expr::RepExact(expr, num) => {
                    (1..num + 1).map(|_| {
                                    *expr.clone()
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                Expr::RepMin(expr, min) => {
                    (1..min + 2).map(|i| {
                                    if i <= min {
                                        *expr.clone()
                                    } else {
                                        Expr::Rep(expr.clone())
                                    }
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                Expr::RepMax(expr, max) => {
                    (1..max + 1).map(|_| {
                                    Expr::Opt(expr.clone())
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                Expr::RepMinMax(expr, min, max) => {
                    (1..max + 1).map(|i| {
                                    if i <= min {
                                        *expr.clone()
                                    } else {
                                        Expr::Opt(expr.clone())
                                    }
                                })
                                .rev()
                                .fold(None, |rep, expr| {
                                    match rep {
                                        None => Some(expr),
                                        Some(rep) => {
                                            Some(
                                                Expr::Seq(
                                                    Box::new(expr),
                                                    Box::new(rep)
                                                )
                                            )
                                        }
                                    }
                                })
                                .unwrap()
                }
                expr => expr
            }
        };

        match rule {
            Rule { name, ty, expr } => Rule {
                name,
                ty,
                expr: expr.map_bottom_up(rotate_right)
                          .map_bottom_up(unroll_loops)
                          .map_bottom_up(|expr| {
                              if ty == RuleType::Atomic {
                                  // TODO: Use box syntax when it gets stabilized.
                                  match expr {
                                      Expr::Seq(lhs, rhs) => {
                                          match (*lhs, *rhs) {
                                              (Expr::Str(lhs), Expr::Str(rhs)) => {
                                                  Expr::Str(lhs + &rhs)
                                              }
                                              (Expr::Insens(lhs), Expr::Insens(rhs)) => {
                                                  Expr::Insens(lhs + &rhs)
                                              }
                                              (lhs, rhs) => Expr::Seq(Box::new(lhs), Box::new(rhs))
                                          }
                                      }
                                      expr => expr
                                  }
                              } else {
                                  expr
                              }
                          })
                          .map_top_down(|expr| {
                              // TODO: Use box syntax when it gets stabilized.
                              match expr {
                                  Expr::Choice(lhs, rhs) => {
                                      match (*lhs, *rhs) {
                                          (Expr::Seq(l1, r1), Expr::Seq(l2, r2)) => {
                                              if l1 == l2 {
                                                  Expr::Seq(
                                                      l1,
                                                      Box::new(Expr::Choice(
                                                          r1,
                                                          r2
                                                      ))
                                                  )
                                              } else {
                                                  Expr::Choice(
                                                      Box::new(Expr::Seq(l1, r1)),
                                                      Box::new(Expr::Seq(l2, r2))
                                                  )
                                              }
                                          }
                                          (lhs, rhs) => Expr::Choice(Box::new(lhs), Box::new(rhs))
                                      }
                                  }
                                  expr => expr
                              }
                          })
            }
        }
    }).collect()
}

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

    use quote::Ident;

    #[test]
    fn concat_strings() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("a".to_owned())),
                        Box::new(Expr::Str("b".to_owned()))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("c".to_owned())),
                        Box::new(Expr::Str("d".to_owned()))
                    ))
                )
            }
        ];
        let concatenated = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Str("abcd".to_owned())
            }
        ];

        assert_eq!(optimize(rules), concatenated);
    }

    #[test]
    fn unroll_loop_exact() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepExact(
                    Box::new(Expr::Ident(Ident::new("a"))),
                    3
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Ident(Ident::new("a"))),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Ident(Ident::new("a"))),
                        Box::new(Expr::Ident(Ident::new("a")))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn unroll_loop_max() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepMax(
                    Box::new(Expr::Str("a".to_owned())),
                    3
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Opt(
                        Box::new(Expr::Str("a".to_owned()))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Opt(
                            Box::new(Expr::Str("a".to_owned()))
                        )),
                        Box::new(Expr::Opt(
                            Box::new(Expr::Str("a".to_owned()))
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn unroll_loop_min() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepMin(
                    Box::new(Expr::Str("a".to_owned())),
                    2
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Str("a".to_owned())),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("a".to_owned())),
                        Box::new(Expr::Rep(
                            Box::new(Expr::Str("a".to_owned()))
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn unroll_loop_min_max() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::RepMinMax(
                    Box::new(Expr::Str("a".to_owned())),
                    2,
                    3
                )
            }
        ];
        let unrolled = vec![
            Rule {
                name: Ident::new("rule"),
                ty: RuleType::Atomic,
                expr: Expr::Seq(
                    /* TODO possible room for improvement here:
                     * if the sequences were rolled out in the opposite
                     * order, we could further optimize the strings
                     * in cases like this.
                    Box::new(Expr::Str("aa".to_owned())),
                    Box::new(Expr::Opt(
                        Box::new(Expr::Str("a".to_owned()))
                    ))
                    */
                    Box::new(Expr::Str("a".to_owned())),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Str("a".to_owned())),
                        Box::new(Expr::Opt(
                            Box::new(Expr::Str("a".to_owned())),
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), unrolled);
    }

    #[test]
    fn concat_insensitive_strings() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Seq(
                    Box::new(Expr::Seq(
                        Box::new(Expr::Insens("a".to_owned())),
                        Box::new(Expr::Insens("b".to_owned()))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Insens("c".to_owned())),
                        Box::new(Expr::Insens("d".to_owned()))
                    ))
                )
            }
        ];
        let concatenated = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Atomic,
                expr: Expr::Insens("abcd".to_owned())
            }
        ];

        assert_eq!(optimize(rules), concatenated);
    }

    #[test]
    fn long_common_sequence() {
        let rules = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Silent,
                expr: Expr::Choice(
                    Box::new(Expr::Seq(
                        Box::new(Expr::Ident(Ident::new("a"))),
                        Box::new(Expr::Seq(
                            Box::new(Expr::Ident(Ident::new("b"))),
                            Box::new(Expr::Ident(Ident::new("c")))
                        ))
                    )),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Seq(
                            Box::new(Expr::Ident(Ident::new("a"))),
                            Box::new(Expr::Ident(Ident::new("b")))
                        )),
                        Box::new(Expr::Ident(Ident::new("d")))
                    ))
                )
            }
        ];
        let optimized = vec![
            Rule {
                name: Ident::new("rule"),
                ty:   RuleType::Silent,
                expr: Expr::Seq(
                    Box::new(Expr::Ident(Ident::new("a"))),
                    Box::new(Expr::Seq(
                        Box::new(Expr::Ident(Ident::new("b"))),
                        Box::new(Expr::Choice(
                            Box::new(Expr::Ident(Ident::new("c"))),
                            Box::new(Expr::Ident(Ident::new("d")))
                        ))
                    ))
                )
            }
        ];

        assert_eq!(optimize(rules), optimized);
    }
}
<|endoftext|>


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

extern crate heapsize;

mod alloc;
pub mod hash_map;
pub mod hash_set;
mod shim;
mod table;

pub mod fake;

use std::{error, fmt};

trait Recover<Q: ?Sized> {
    type Key;

    fn get(&self, key: &Q) -> Option<&Self::Key>;
    fn take(&mut self, key: &Q) -> Option<Self::Key>;
    fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}

#[derive(Debug)]
pub struct FailedAllocationError {
    reason: &'static str,
}

impl FailedAllocationError {
    pub fn new(reason: &'static str) -> Self {
        Self { reason }
    }
}

impl error::Error for FailedAllocationError {
    fn description(&self) -> &str {
        self.reason
    }
}

impl fmt::Display for FailedAllocationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.reason.fmt(f)
    }
}
<commit_msg>hashglobe: Inline error constructor so we don't pay a function call even when there's no error.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate heapsize;

mod alloc;
pub mod hash_map;
pub mod hash_set;
mod shim;
mod table;

pub mod fake;

use std::{error, fmt};

trait Recover<Q: ?Sized> {
    type Key;

    fn get(&self, key: &Q) -> Option<&Self::Key>;
    fn take(&mut self, key: &Q) -> Option<Self::Key>;
    fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}

#[derive(Debug)]
pub struct FailedAllocationError {
    reason: &'static str,
}

impl FailedAllocationError {
    #[inline]
    pub fn new(reason: &'static str) -> Self {
        Self { reason }
    }
}

impl error::Error for FailedAllocationError {
    fn description(&self) -> &str {
        self.reason
    }
}

impl fmt::Display for FailedAllocationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.reason.fmt(f)
    }
}
<|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/.

extern crate devicemapper;
extern crate libstratis;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate clap;
#[cfg(feature="dbus_enabled")]
extern crate dbus;
extern crate libc;
extern crate libudev;
extern crate nix;

#[cfg(test)]
extern crate quickcheck;

use std::cell::RefCell;
use std::env;
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::exit;
use std::rc::Rc;

use clap::{App, Arg};
use env_logger::LogBuilder;
use libc::pid_t;
use log::{LogLevelFilter, SetLoggerError};
use nix::fcntl::{flock, FlockArg};
use nix::unistd::getpid;

#[cfg(feature="dbus_enabled")]
use dbus::WatchEvent;

use devicemapper::Device;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/var/run/stratisd.pid";

/// If writing a program error to stderr fails, panic.
fn print_err(err: StratisError) -> () {
    eprintln!("{}", err.description());
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else {
        if let Ok(s) = env::var("RUST_LOG") {
            builder.parse(&s);
        }
    };

    builder.init()
}

/// Given a udev event check to see if it's an add and if it is return the device node and
/// devicemapper::Device.
fn handle_udev_add(event: &libudev::Event) -> Option<(PathBuf, Device)> {
    if event.event_type() == libudev::EventType::Add {
        let device = event.device();
        return device
                   .devnode()
                   .and_then(|devnode| {
                                 device
                                     .devnum()
                                     .and_then(|devnum| {
                                                   Some((PathBuf::from(devnode),
                                                         Device::from(devnum)))
                                               })
                             });
    }
    None
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn create_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write(format!("{}\n", getpid()).as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;
            // pidfile is supposed to contain pid of holder. But you never
            // know so be paranoid.
            let pid_str = buf.split_whitespace()
                .next()
                .and_then(|s| s.parse::<pid_t>().ok())
                .map(|pid| format!("{}", pid))
                .unwrap_or_else(|| "<unknown>".into());
            Err(StratisError::Error(format!("Daemon already running with pid: {}", pid_str)))
        }
    }
}

fn run() -> StratisResult<()> {

    // Exit immediately if stratisd is already running
    let _ = create_pid_file()?;

    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .help("Print additional output for debugging"))
        .arg(Arg::with_name("sim")
                 .long("sim")
                 .help("Use simulator engine"))
        .get_matches();

    initialize_log(matches.is_present("debug"))
        .expect("This is the first and only invocation of this method; it must succeed.");

    // We must setup a udev listener before we initialize the
    // engine. It is possible that a device may appear after the engine has read the
    // /dev directory but before it has completed initialization. Unless the udev
    // event has been recorded, the engine will be unaware of the existence of the
    // device.
    // This is especially important since stratisd is required to be able to run
    // during early boot.
    let context = libudev::Context::new()?;
    let mut monitor = libudev::Monitor::new(&context)?;
    monitor.match_subsystem_devtype("block", "disk")?;
    let mut udev = monitor.listen()?;

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are laid out in the following:

    0   == Always udev fd index
    1   == engine index if eventable
    1/2 == Start of dbus client file descriptor(s), 1 if engine is not eventable, else 2
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_ENGINE: usize = 1;

    let mut fds = Vec::new();

    fds.push(libc::pollfd {
                 fd: udev.as_raw_fd(),
                 revents: 0,
                 events: libc::POLLIN,
             });

    let eventable = engine.borrow().get_eventable()?;

    // The variable _dbus_client_index_start is only used when dbus support is compiled in, thus
    // we denote the value as not needed to compile when dbus support is not included.
    let (engine_eventable, poll_timeout, _dbus_client_index_start) = match eventable {
        Some(ref evt) => {
            fds.push(libc::pollfd {
                         fd: evt.get_pollable_fd(),
                         revents: 0,
                         events: libc::POLLIN,
                     });

            // Don't timeout if eventable, we are event driven
            (true, -1, FD_INDEX_ENGINE + 1)
        }

        // We periodically need to timeout as we are not event driven
        None => (false, 10000, FD_INDEX_ENGINE),
    };

    #[cfg(feature="dbus_enabled")]
    let (mut dbus_conn, mut tree, base_object_path, mut dbus_context) =
        libstratis::dbus_api::connect(Rc::clone(&engine))?;

    loop {
        // Process any udev block events
        if fds[FD_INDEX_UDEV].revents != 0 {
            loop {
                match udev.receive_event() {
                    Some(event) => {
                        if let Some((devnode, device)) = handle_udev_add(&event) {

                            // If block evaluate returns an error we are going to ignore it as
                            // there is nothing we can do for a device we are getting errors with.
                            let pool_uuid = engine
                                .borrow_mut()
                                .block_evaluate(devnode, device)
                                .unwrap_or(None);

                            // We need to pretend that we aren't using the variable _pool_uuid so
                            // that we can conditionally compile out the register_pool when dbus
                            // is not enabled.
                            if let Some(_pool_uuid) = pool_uuid {
                                #[cfg(feature="dbus_enabled")]
                                libstratis::dbus_api::register_pool(&mut dbus_conn,
                                                                    Rc::clone(&engine),
                                                                    &mut dbus_context,
                                                                    &mut tree,
                                                                    _pool_uuid,
                                                                    &base_object_path)?;
                            }
                        }
                    }
                    None => {
                        break;
                    }
                };
            }
        }

        // Handle engine events, if the engine is eventable
        if engine_eventable {
            if fds[FD_INDEX_ENGINE].revents != 0 {
                fds[FD_INDEX_ENGINE].revents = 0;

                eventable
                    .as_ref()
                    .expect("eventable.is_some()")
                    .clear_event()?;

                engine.borrow_mut().evented()?;
            }
        } else {
            // Unconditionally call evented() if engine has no eventable.
            // This looks like a bad idea, but the only engine that has
            // no eventable is the sim engine, and for that engine, evented()
            // is essentially a no-op.
            engine.borrow_mut().evented()?;
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature="dbus_enabled")]
        {
            for pfd in fds[_dbus_client_index_start..]
                    .iter()
                    .filter(|pfd| pfd.revents != 0) {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) = libstratis::dbus_api::handle(&dbus_conn,
                                                                 &item,
                                                                 &mut tree,
                                                                 &dbus_context) {
                        print_err(From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(_dbus_client_index_start);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let error_code = match run() {
        Ok(_) => 0,
        Err(err) => {
            print_err(err);
            1
        }
    };
    exit(error_code);
}
<commit_msg>Use StratisError's Display trait instead of calling Error::description()<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/.

extern crate devicemapper;
extern crate libstratis;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate clap;
#[cfg(feature="dbus_enabled")]
extern crate dbus;
extern crate libc;
extern crate libudev;
extern crate nix;

#[cfg(test)]
extern crate quickcheck;

use std::cell::RefCell;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::exit;
use std::rc::Rc;

use clap::{App, Arg};
use env_logger::LogBuilder;
use libc::pid_t;
use log::{LogLevelFilter, SetLoggerError};
use nix::fcntl::{flock, FlockArg};
use nix::unistd::getpid;

#[cfg(feature="dbus_enabled")]
use dbus::WatchEvent;

use devicemapper::Device;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/var/run/stratisd.pid";

/// If writing a program error to stderr fails, panic.
fn print_err(err: StratisError) -> () {
    eprintln!("{}", err);
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else {
        if let Ok(s) = env::var("RUST_LOG") {
            builder.parse(&s);
        }
    };

    builder.init()
}

/// Given a udev event check to see if it's an add and if it is return the device node and
/// devicemapper::Device.
fn handle_udev_add(event: &libudev::Event) -> Option<(PathBuf, Device)> {
    if event.event_type() == libudev::EventType::Add {
        let device = event.device();
        return device
                   .devnode()
                   .and_then(|devnode| {
                                 device
                                     .devnum()
                                     .and_then(|devnum| {
                                                   Some((PathBuf::from(devnode),
                                                         Device::from(devnum)))
                                               })
                             });
    }
    None
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn create_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write(format!("{}\n", getpid()).as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;
            // pidfile is supposed to contain pid of holder. But you never
            // know so be paranoid.
            let pid_str = buf.split_whitespace()
                .next()
                .and_then(|s| s.parse::<pid_t>().ok())
                .map(|pid| format!("{}", pid))
                .unwrap_or_else(|| "<unknown>".into());
            Err(StratisError::Error(format!("Daemon already running with pid: {}", pid_str)))
        }
    }
}

fn run() -> StratisResult<()> {

    // Exit immediately if stratisd is already running
    let _ = create_pid_file()?;

    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .help("Print additional output for debugging"))
        .arg(Arg::with_name("sim")
                 .long("sim")
                 .help("Use simulator engine"))
        .get_matches();

    initialize_log(matches.is_present("debug"))
        .expect("This is the first and only invocation of this method; it must succeed.");

    // We must setup a udev listener before we initialize the
    // engine. It is possible that a device may appear after the engine has read the
    // /dev directory but before it has completed initialization. Unless the udev
    // event has been recorded, the engine will be unaware of the existence of the
    // device.
    // This is especially important since stratisd is required to be able to run
    // during early boot.
    let context = libudev::Context::new()?;
    let mut monitor = libudev::Monitor::new(&context)?;
    monitor.match_subsystem_devtype("block", "disk")?;
    let mut udev = monitor.listen()?;

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are laid out in the following:

    0   == Always udev fd index
    1   == engine index if eventable
    1/2 == Start of dbus client file descriptor(s), 1 if engine is not eventable, else 2
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_ENGINE: usize = 1;

    let mut fds = Vec::new();

    fds.push(libc::pollfd {
                 fd: udev.as_raw_fd(),
                 revents: 0,
                 events: libc::POLLIN,
             });

    let eventable = engine.borrow().get_eventable()?;

    // The variable _dbus_client_index_start is only used when dbus support is compiled in, thus
    // we denote the value as not needed to compile when dbus support is not included.
    let (engine_eventable, poll_timeout, _dbus_client_index_start) = match eventable {
        Some(ref evt) => {
            fds.push(libc::pollfd {
                         fd: evt.get_pollable_fd(),
                         revents: 0,
                         events: libc::POLLIN,
                     });

            // Don't timeout if eventable, we are event driven
            (true, -1, FD_INDEX_ENGINE + 1)
        }

        // We periodically need to timeout as we are not event driven
        None => (false, 10000, FD_INDEX_ENGINE),
    };

    #[cfg(feature="dbus_enabled")]
    let (mut dbus_conn, mut tree, base_object_path, mut dbus_context) =
        libstratis::dbus_api::connect(Rc::clone(&engine))?;

    loop {
        // Process any udev block events
        if fds[FD_INDEX_UDEV].revents != 0 {
            loop {
                match udev.receive_event() {
                    Some(event) => {
                        if let Some((devnode, device)) = handle_udev_add(&event) {

                            // If block evaluate returns an error we are going to ignore it as
                            // there is nothing we can do for a device we are getting errors with.
                            let pool_uuid = engine
                                .borrow_mut()
                                .block_evaluate(devnode, device)
                                .unwrap_or(None);

                            // We need to pretend that we aren't using the variable _pool_uuid so
                            // that we can conditionally compile out the register_pool when dbus
                            // is not enabled.
                            if let Some(_pool_uuid) = pool_uuid {
                                #[cfg(feature="dbus_enabled")]
                                libstratis::dbus_api::register_pool(&mut dbus_conn,
                                                                    Rc::clone(&engine),
                                                                    &mut dbus_context,
                                                                    &mut tree,
                                                                    _pool_uuid,
                                                                    &base_object_path)?;
                            }
                        }
                    }
                    None => {
                        break;
                    }
                };
            }
        }

        // Handle engine events, if the engine is eventable
        if engine_eventable {
            if fds[FD_INDEX_ENGINE].revents != 0 {
                fds[FD_INDEX_ENGINE].revents = 0;

                eventable
                    .as_ref()
                    .expect("eventable.is_some()")
                    .clear_event()?;

                engine.borrow_mut().evented()?;
            }
        } else {
            // Unconditionally call evented() if engine has no eventable.
            // This looks like a bad idea, but the only engine that has
            // no eventable is the sim engine, and for that engine, evented()
            // is essentially a no-op.
            engine.borrow_mut().evented()?;
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature="dbus_enabled")]
        {
            for pfd in fds[_dbus_client_index_start..]
                    .iter()
                    .filter(|pfd| pfd.revents != 0) {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) = libstratis::dbus_api::handle(&dbus_conn,
                                                                 &item,
                                                                 &mut tree,
                                                                 &dbus_context) {
                        print_err(From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(_dbus_client_index_start);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let error_code = match run() {
        Ok(_) => 0,
        Err(err) => {
            print_err(err);
            1
        }
    };
    exit(error_code);
}
<|endoftext|>


<commit_before>use std::error::Error;
use yaml_rust::yaml::YamlLoader;

pub struct Config {
    source_dir: String,
    output_dir: String,
}

impl Config {
    pub fn from_string(config_string: String) -> Self {
        let yaml = match YamlLoader::load_from_str(&config_string) {
            Ok(yaml) => yaml,
            Err(what) => panic!("Config file couldn't be read: {}", Error::description(&what))
        };

        let mut config = Self::default();
        if let Some(yaml) = yaml.get(0) {
            if let Some(source) = yaml["source"].as_str() {
                config.source_dir = source.to_string();
            }

            if let Some(output) = yaml["output"].as_str() {
                config.output_dir = output.to_string();
            }
        }

        config
    }

    pub fn get_output_dir(&self) -> &str {
        &self.output_dir
    }

    pub fn get_source_dir(&self) -> &str {
        &self.source_dir
    }
}

impl Default for Config {
    fn default() -> Self {
        Config {
            source_dir: "./pages".to_string(),
            output_dir: "./_site".to_string(),
        }
    }
}

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

    fn setup() -> String {
        String::from("source: pages\n\
            output: _site")
    }

    #[test]
    fn it_parses_input_directory_option_in_config() {
        let config_string = setup();

        let config = Config::from_string(config_string);

        assert_eq!("pages", config.source_dir);
    }

    #[test]
    fn it_parses_output_directory_option_in_config() {
        let config_string = setup();

        let config = Config::from_string(config_string);

        assert_eq!("_site", config.output_dir);
    }
}
<commit_msg>chore: improve code coverage on Config.rs<commit_after>use std::error::Error;
use yaml_rust::yaml::YamlLoader;

pub struct Config {
    source_dir: String,
    output_dir: String,
}

impl Config {
    pub fn from_string(config_string: String) -> Self {
        let yaml = match YamlLoader::load_from_str(&config_string) {
            Ok(yaml) => yaml,
            Err(what) => panic!("Config file couldn't be read: {}", Error::description(&what))
        };

        let mut config = Self::default();
        if let Some(yaml) = yaml.get(0) {
            if let Some(source) = yaml["source"].as_str() {
                config.source_dir = source.to_string();
            }

            if let Some(output) = yaml["output"].as_str() {
                config.output_dir = output.to_string();
            }
        }

        config
    }

    pub fn get_output_dir(&self) -> &str {
        &self.output_dir
    }

    pub fn get_source_dir(&self) -> &str {
        &self.source_dir
    }
}

impl Default for Config {
    fn default() -> Self {
        Config {
            source_dir: "./pages".to_string(),
            output_dir: "./_site".to_string(),
        }
    }
}

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

    fn good_setup() -> String {
        "source: pages\n\
         output: _site".to_string()
    }

    fn bad_setup() -> String {
        "source: pages\n\
         \t\toutput: _site".to_string()
    }

    #[test]
    fn it_creates_sensible_defaults() {
        let config = Config::default();

        assert_eq!("./pages", config.get_source_dir());
        assert_eq!("./_site", config.get_output_dir());
    }

    #[test]
    fn it_parses_input_directory_option_in_config() {
        let config_string = good_setup();

        let config = Config::from_string(config_string);

        assert_eq!("pages", config.source_dir);
    }

    #[test]
    fn it_parses_output_directory_option_in_config() {
        let config_string = good_setup();

        let config = Config::from_string(config_string);

        assert_eq!("_site", config.output_dir);
    }

    #[test]
    #[should_panic]
    fn it_panics_on_poorly_formed_file() {
        let config_string = bad_setup();

        let config = Config::from_string(config_string);
    }
}
<|endoftext|>