<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 basedir::default_config_dir;
use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    pub static ref PREFS: Preferences = {
        let prefs = read_prefs().unwrap_or_else(|_| HashMap::new());
        Preferences(Arc::new(Mutex::new(prefs)))
    };
}

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Number(f64),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            Json::F64(x) => PrefValue::Number(x),
            Json::I64(x) => PrefValue::Number(x as f64),
            Json::U64(x) => PrefValue::Number(x as f64),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }

    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            PrefValue::Number(x) => Some(x as i64),
            _ => None,
        }
    }

    pub fn as_u64(&self) -> Option<u64> {
        match *self {
            PrefValue::Number(x) => Some(x as u64),
            _ => None,
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            },
            PrefValue::Number(x) => {
                Json::F64(x)
            },
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
            }
        }
    }
    Ok(prefs)
}

pub fn add_user_prefs() {
    match opts::get().config_dir {
        Some(ref config_path) => {
            let mut path = PathBuf::from(config_path);
            init_user_prefs(&mut path);
        }
        None => {
            let mut path = default_config_dir().unwrap();
            if path.join("prefs.json").exists() {
                init_user_prefs(&mut path);
            }
        }
    }
}

fn init_user_prefs(path: &mut PathBuf) {
    path.push("prefs.json");
    if let Ok(file) = File::open(path) {
        if let Ok(prefs) = read_prefs_from_file(file) {
            PREFS.extend(prefs);
        }
    } else {
    writeln!(&mut stderr(), "Error opening prefs.json from config directory")
        .expect("failed printing to stderr");
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub struct Preferences(Arc<Mutex<HashMap<String, Pref>>>);

impl Preferences {
    pub fn get(&self, name: &str) -> Arc<PrefValue> {
        self.0.lock().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
    }

    pub fn cloned(&self) -> HashMap<String, Pref> {
        self.0.lock().unwrap().clone()
    }

    pub fn is_mozbrowser_enabled(&self) -> bool {
        self.get("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
    }

    pub fn set(&self, name: &str, value: PrefValue) {
        let mut prefs = self.0.lock().unwrap();
        if let Some(pref) = prefs.get_mut(name) {
            pref.set(value);
            return;
        }
        prefs.insert(name.to_owned(), Pref::new(value));
    }

    pub fn reset(&self, name: &str) -> Arc<PrefValue> {
        let mut prefs = self.0.lock().unwrap();
        let result = match prefs.get_mut(name) {
            None => return Arc::new(PrefValue::Missing),
            Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
            Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
                *set_value = None;
                default.clone()
            },
        };
        if *result == PrefValue::Missing {
            prefs.remove(name);
        }
        result
    }

    pub fn reset_all(&self) {
        let names = {
            self.0.lock().unwrap().keys().cloned().collect::<Vec<String>>()
        };
        for name in names.iter() {
            self.reset(name);
        }
    }

    pub fn extend(&self, extension: HashMap<String, Pref>) {
        self.0.lock().unwrap().extend(extension);
    }
}
<commit_msg>Auto merge of #12275 - emilio:prefs-rwlock, r=jdm<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 basedir::default_config_dir;
use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, RwLock};

lazy_static! {
    pub static ref PREFS: Preferences = {
        let prefs = read_prefs().ok().unwrap_or_else(HashMap::new);
        Preferences(Arc::new(RwLock::new(prefs)))
    };
}

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Number(f64),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            Json::F64(x) => PrefValue::Number(x),
            Json::I64(x) => PrefValue::Number(x as f64),
            Json::U64(x) => PrefValue::Number(x as f64),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }

    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            PrefValue::Number(x) => Some(x as i64),
            _ => None,
        }
    }

    pub fn as_u64(&self) -> Option<u64> {
        match *self {
            PrefValue::Number(x) => Some(x as u64),
            _ => None,
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            },
            PrefValue::Number(x) => {
                Json::F64(x)
            },
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
            }
        }
    }
    Ok(prefs)
}

pub fn add_user_prefs() {
    match opts::get().config_dir {
        Some(ref config_path) => {
            let mut path = PathBuf::from(config_path);
            init_user_prefs(&mut path);
        }
        None => {
            let mut path = default_config_dir().unwrap();
            if path.join("prefs.json").exists() {
                init_user_prefs(&mut path);
            }
        }
    }
}

fn init_user_prefs(path: &mut PathBuf) {
    path.push("prefs.json");
    if let Ok(file) = File::open(path) {
        if let Ok(prefs) = read_prefs_from_file(file) {
            PREFS.extend(prefs);
        }
    } else {
    writeln!(&mut stderr(), "Error opening prefs.json from config directory")
        .expect("failed printing to stderr");
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub struct Preferences(Arc<RwLock<HashMap<String, Pref>>>);

impl Preferences {
    pub fn get(&self, name: &str) -> Arc<PrefValue> {
        self.0.read().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
    }

    pub fn cloned(&self) -> HashMap<String, Pref> {
        self.0.read().unwrap().clone()
    }

    pub fn is_mozbrowser_enabled(&self) -> bool {
        self.get("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
    }

    pub fn set(&self, name: &str, value: PrefValue) {
        let mut prefs = self.0.write().unwrap();
        if let Some(pref) = prefs.get_mut(name) {
            pref.set(value);
            return;
        }
        prefs.insert(name.to_owned(), Pref::new(value));
    }

    pub fn reset(&self, name: &str) -> Arc<PrefValue> {
        let mut prefs = self.0.write().unwrap();
        let result = match prefs.get_mut(name) {
            None => return Arc::new(PrefValue::Missing),
            Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
            Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
                *set_value = None;
                default.clone()
            },
        };
        if *result == PrefValue::Missing {
            prefs.remove(name);
        }
        result
    }

    pub fn reset_all(&self) {
        let names = {
            self.0.read().unwrap().keys().cloned().collect::<Vec<String>>()
        };
        for name in names.iter() {
            self.reset(name);
        }
    }

    pub fn extend(&self, extension: HashMap<String, Pref>) {
        self.0.write().unwrap().extend(extension);
    }
}
<|endoftext|>


<commit_before>#![allow(clippy::eq_op, clippy::shadow_unrelated, clippy::wildcard_imports)]

mod common;

use self::common::*;
use anyhow::{anyhow, ensure};
use std::future;

#[test]
fn test_messages() {
    assert_eq!("oh no!", bail_literal().unwrap_err().to_string());
    assert_eq!("oh no!", bail_fmt().unwrap_err().to_string());
    assert_eq!("oh no!", bail_error().unwrap_err().to_string());
}

#[test]
fn test_ensure() {
    let f = || {
        ensure!(1 + 1 == 2, "This is correct");
        Ok(())
    };
    assert!(f().is_ok());

    let v = 1;
    let f = || {
        ensure!(v + v == 2, "This is correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_ok());

    let f = || {
        ensure!(v + v == 1, "This is not correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_err());

    let f = || {
        ensure!(v + v == 1);
        Ok(())
    };
    assert_eq!(
        f().unwrap_err().to_string(),
        "Condition failed: `v + v == 1`",
    );
}

#[test]
fn test_temporaries() {
    fn require_send_sync(_: impl Send + Sync) {}

    require_send_sync(async {
        // If anyhow hasn't dropped any temporary format_args it creates by the
        // time it's done evaluating, those will stick around until the
        // semicolon, which is on the other side of the await point, making the
        // enclosing future non-Send.
        future::ready(anyhow!("...")).await;
    });
}

#[test]
fn test_brace_escape() {
    let err = anyhow!("unterminated ${{..}} expression");
    assert_eq!("unterminated ${..} expression", err.to_string());
}
<commit_msg>Ignore items_after_statements Clippy pedantic lint in test suite<commit_after>#![allow(
    clippy::eq_op,
    clippy::items_after_statements,
    clippy::shadow_unrelated,
    clippy::wildcard_imports
)]

mod common;

use self::common::*;
use anyhow::{anyhow, ensure};
use std::future;

#[test]
fn test_messages() {
    assert_eq!("oh no!", bail_literal().unwrap_err().to_string());
    assert_eq!("oh no!", bail_fmt().unwrap_err().to_string());
    assert_eq!("oh no!", bail_error().unwrap_err().to_string());
}

#[test]
fn test_ensure() {
    let f = || {
        ensure!(1 + 1 == 2, "This is correct");
        Ok(())
    };
    assert!(f().is_ok());

    let v = 1;
    let f = || {
        ensure!(v + v == 2, "This is correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_ok());

    let f = || {
        ensure!(v + v == 1, "This is not correct, v: {}", v);
        Ok(())
    };
    assert!(f().is_err());

    let f = || {
        ensure!(v + v == 1);
        Ok(())
    };
    assert_eq!(
        f().unwrap_err().to_string(),
        "Condition failed: `v + v == 1`",
    );
}

#[test]
fn test_temporaries() {
    fn require_send_sync(_: impl Send + Sync) {}

    require_send_sync(async {
        // If anyhow hasn't dropped any temporary format_args it creates by the
        // time it's done evaluating, those will stick around until the
        // semicolon, which is on the other side of the await point, making the
        // enclosing future non-Send.
        future::ready(anyhow!("...")).await;
    });
}

#[test]
fn test_brace_escape() {
    let err = anyhow!("unterminated ${{..}} expression");
    assert_eq!("unterminated ${..} expression", err.to_string());
}
<|endoftext|>


<commit_before>//!
//! # Scheduler
//!

use std::mem;
use std::sync::*;
use std::thread::*;
use std::sync::mpsc::*;
use std::collections::vec_deque::*;

lazy_static! {
    static ref SCHEDULER: Arc<Scheduler> = Arc::new(Scheduler::new());
}

///
/// Trait implemented by things that can be scheduled as a job
///
trait ScheduledJob : Send {
    /// Runs this particular job
    fn run(&mut self);
}

///
/// Basic job is just a FnOnce
///
struct Job<TFn>
where TFn: Send+FnOnce() -> () {
    action: Option<TFn>
}

impl<TFn> Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn new(action: TFn) -> Job<TFn> {
        Job { action: Some(action) }
    }
}

impl<TFn> ScheduledJob for Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn run(&mut self) {
        // Consume the action when it's run
        let mut action = None;
        mem::swap(&mut action, &mut self.action);

        if let Some(action) = action {
            action();
        } else {
            panic!("Cannot schedule an action twice");
        }
    }
}

///
/// The scheduler is used to schedule tasks onto a pool of threads
///
pub struct Scheduler {
    /// The queues that are active in the scheduler
    queues: Arc<Mutex<Vec<Weak<JobQueue>>>>,

    /// Active threads
    threads: Mutex<Vec<SchedulerThread>>
}

///
/// A job queue provides a list of jobs to perform in order
///
pub struct JobQueue {
    /// Jobs scheduled on this queue
    queue: Mutex<VecDeque<Box<ScheduledJob>>>,

    /// True while this queue is running
    running: Mutex<bool>
}

///
/// A scheduler thread reads from the scheduler queue
///
struct SchedulerThread {
    /// The jobs that this thread should run
    jobs: Sender<Box<ScheduledJob>>,

    /// The thread itself
    thread: JoinHandle<()>,

    /// Flag that indicates that this thread is busy
    busy: Arc<Mutex<bool>>
}

impl SchedulerThread {
    ///
    /// Creates a new scheduler thread
    ///
    fn new() -> SchedulerThread {
        // All the thread does is run jobs from its channel
        let (jobs_in, jobs_out): (Sender<Box<ScheduledJob>>, Receiver<Box<ScheduledJob>>) = channel();
        let thread = spawn(move || {
            while let Ok(mut job) = jobs_out.recv() {
                job.run();
            }
        });

        SchedulerThread {
            jobs:   jobs_in,
            thread: thread,
            busy:   Arc::new(Mutex::new(false))
        }
    }

    ///
    /// Schedules a job to be run on this thread
    ///
    fn run<Job: 'static+ScheduledJob>(&self, job: Job) {
        self.jobs.send(Box::new(job)).unwrap();
    }
}

impl JobQueue {
    ///
    /// Creates a new job queue
    ///
    fn new() -> JobQueue {
        JobQueue {
            queue:      Mutex::new(VecDeque::new()),
            running:    Mutex::new(false)
        }
    }

    ///
    /// Adds a new job to this queue, returns true if the queue is dormant and needs to be started
    ///
    fn queue<TJob: 'static+ScheduledJob>(&self, job: TJob) -> bool {
        let mut queue   = self.queue.lock().unwrap();
        let running     = self.running.lock().unwrap();

        queue.push_back(Box::new(job));

        !*running
    }

    ///
    /// If there are any jobs waiting, dequeues the next one
    ///
    fn dequeue(&self) -> Option<Box<ScheduledJob>> {
        let mut queue = self.queue.lock().unwrap();

        queue.pop_front()
    }

    ///
    /// Runs jobs on this queue until there are none left, marking the job as inactive when done
    ///
    fn drain(&self) {
        let mut done = false;

        while !done {
            // Run jobs until the queue is drained
            while let Some(mut job) = self.dequeue() {
                job.run();
            }

            // Mark as not running any more
            {
                let queue       = self.queue.lock().unwrap();
                let mut running = self.running.lock().unwrap();

                // If the queue is empty at the point where we obtain the 'running' lock, we can deactivate ourselves
                if queue.len() == 0 {
                    *running    = false;
                    done        = true;
                }
            }
        }
    }
}

impl Scheduler {
    ///
    /// Creates a new scheduler
    ///
    /// (There's only actually one scheduler)
    ///
    fn new() -> Scheduler {
        let result = Scheduler {
            queues:     Arc::new(Mutex::new(vec![])),
            threads:    Mutex::new(vec![])
        };
        result.spawn_thread();

        result
    }

    ///
    /// Finds the next queue that should be run. If this returns successfully, the queue will
    /// be marked as running.
    ///
    fn next_to_run(queues: &Arc<Mutex<Vec<Weak<JobQueue>>>>) -> Option<Arc<JobQueue>> {
        // Search the queues...
        let queues = queues.lock().unwrap();

        // Find a queue where is_running is false
        for q in queues.iter() {
            // Queue is a weak ref, check that it's still in use
            if let Some(q) = q.upgrade() {
                // If the queue is not running, then mark it as running and return it
                let mut is_running = q.running.lock().unwrap();
                if !*is_running {
                    // Clone here is necessary because the is_running update is borrowing q
                    *is_running = true;
                    return Some(q.clone());
                }
            }
        }

        None
    }

    ///
    /// Attempts to schedule a task on a dormant thread
    ///
    fn schedule_dormant<TFn>(&self, job: TFn) -> bool
    where TFn: 'static+Send+FnOnce() -> () {
        let threads = self.threads.lock().unwrap();

        for thread in threads.iter() {
            let mut busy = thread.busy.lock().unwrap();

            if !*busy {
                let also_busy = thread.busy.clone();

                *busy = true;
                thread.run(Job::new(move || {
                    // Run the job
                    job();

                    // Thread is dormant again once this job completes
                    let mut busy = also_busy.lock().unwrap();
                    *busy = false;
                }));

                return true;
            }
        }

        // No dormant threads were found
        false
    }

    ///
    /// Wakes a thread to run a dormant queue. Returns true if a thread was woken up
    ///
    fn schedule_thread(&self) -> bool {
        // Find a dormant thread and activate it
        let queues = self.queues.clone();

        self.schedule_dormant(move || {
            // Run queues until there are no more to run, then become dormant again
            while let Some(work) = Self::next_to_run(&queues) {
                work.drain();
            }

            // TODO: if there are no dormant threads, there's a race here at the moment as this thread won't get rescheduled while it's 'dying'
        })
    }

    ///
    /// Spawns a thread in this scheduler
    ///
    pub fn spawn_thread(&self) {
        let new_thread = SchedulerThread::new();
        self.threads.lock().unwrap().push(new_thread);
    }

    ///
    /// Creates a new job queue for this scheduler
    ///
    pub fn create_job_queue(&self) -> Arc<JobQueue> {
        let new_queue = Arc::new(JobQueue::new());

        self.queues.lock().unwrap().push(Arc::downgrade(&new_queue));

        new_queue
    }

    ///
    /// Schedules a job on this scheduler
    ///
    pub fn async<TFn: 'static+Send+FnOnce() -> ()>(&self, queue: &Arc<JobQueue>, job: TFn) {
        if queue.queue(Job::new(job)) {
            // A true result indicates that the job was scheduled but the queue is not running. Try to schedule a thread if this occurs.
            self.schedule_thread();
        }
    }
}

///
/// Retrieves the global scheduler
///
pub fn scheduler<'a>() -> &'a Scheduler {
    &SCHEDULER
}

///
/// Creates a scheduler queue
///
pub fn queue() -> Arc<JobQueue> {
    scheduler().create_job_queue()
}

///
/// Creates a scheduler queue
///
pub fn async<TFn: 'static+Send+FnOnce() -> ()>(queue: &Arc<JobQueue>, job: TFn) {
    scheduler().async(queue, job)
}

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

    #[test]
    fn can_schedule_async() {
        let (tx, rx)    = channel();
        let queue       = queue();

        async(&queue, move || {
            tx.send(42).unwrap();
        });

        assert!(rx.recv().unwrap() == 42);
    }

    #[test]
    fn will_schedule_in_order() {
        let (tx, rx)    = channel();
        let queue       = queue();

        let (tx1, tx2)  = (tx.clone(), tx.clone());

        async(&queue, move || {
            sleep(Duration::from_millis(100));
            tx1.send(1).unwrap();
        });
        async(&queue, move || {
            tx2.send(2).unwrap();
        });

        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv().unwrap() == 2);
    }

    #[test]
    fn will_schedule_separate_queues_in_parallel() {
        let (tx, rx)        = channel();
        let queue1          = queue();
        let queue2          = queue();
        let queue2_has_run  = Arc::new(Mutex::new(false));

        let queue1_check = queue2_has_run.clone();

        async(&queue1, move || {
            sleep(Duration::from_millis(100));
            tx.send(*queue1_check.lock().unwrap()).unwrap();
        });
        async(&queue2, move || {
            *queue2_has_run.lock().unwrap() = true;
        });

        assert!(rx.recv().unwrap() == true);
    }
}
<commit_msg>Spawn some extra threads<commit_after>//!
//! # Scheduler
//!

use std::mem;
use std::sync::*;
use std::thread::*;
use std::sync::mpsc::*;
use std::collections::vec_deque::*;

lazy_static! {
    static ref SCHEDULER: Arc<Scheduler> = Arc::new(Scheduler::new());
}

///
/// Trait implemented by things that can be scheduled as a job
///
trait ScheduledJob : Send {
    /// Runs this particular job
    fn run(&mut self);
}

///
/// Basic job is just a FnOnce
///
struct Job<TFn>
where TFn: Send+FnOnce() -> () {
    action: Option<TFn>
}

impl<TFn> Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn new(action: TFn) -> Job<TFn> {
        Job { action: Some(action) }
    }
}

impl<TFn> ScheduledJob for Job<TFn>
where TFn: Send+FnOnce() -> () {
    fn run(&mut self) {
        // Consume the action when it's run
        let mut action = None;
        mem::swap(&mut action, &mut self.action);

        if let Some(action) = action {
            action();
        } else {
            panic!("Cannot schedule an action twice");
        }
    }
}

///
/// The scheduler is used to schedule tasks onto a pool of threads
///
pub struct Scheduler {
    /// The queues that are active in the scheduler
    queues: Arc<Mutex<Vec<Weak<JobQueue>>>>,

    /// Active threads
    threads: Mutex<Vec<SchedulerThread>>
}

///
/// A job queue provides a list of jobs to perform in order
///
pub struct JobQueue {
    /// Jobs scheduled on this queue
    queue: Mutex<VecDeque<Box<ScheduledJob>>>,

    /// True while this queue is running
    running: Mutex<bool>
}

///
/// A scheduler thread reads from the scheduler queue
///
struct SchedulerThread {
    /// The jobs that this thread should run
    jobs: Sender<Box<ScheduledJob>>,

    /// The thread itself
    thread: JoinHandle<()>,

    /// Flag that indicates that this thread is busy
    busy: Arc<Mutex<bool>>
}

impl SchedulerThread {
    ///
    /// Creates a new scheduler thread
    ///
    fn new() -> SchedulerThread {
        // All the thread does is run jobs from its channel
        let (jobs_in, jobs_out): (Sender<Box<ScheduledJob>>, Receiver<Box<ScheduledJob>>) = channel();
        let thread = spawn(move || {
            while let Ok(mut job) = jobs_out.recv() {
                job.run();
            }
        });

        SchedulerThread {
            jobs:   jobs_in,
            thread: thread,
            busy:   Arc::new(Mutex::new(false))
        }
    }

    ///
    /// Schedules a job to be run on this thread
    ///
    fn run<Job: 'static+ScheduledJob>(&self, job: Job) {
        self.jobs.send(Box::new(job)).unwrap();
    }
}

impl JobQueue {
    ///
    /// Creates a new job queue
    ///
    fn new() -> JobQueue {
        JobQueue {
            queue:      Mutex::new(VecDeque::new()),
            running:    Mutex::new(false)
        }
    }

    ///
    /// Adds a new job to this queue, returns true if the queue is dormant and needs to be started
    ///
    fn queue<TJob: 'static+ScheduledJob>(&self, job: TJob) -> bool {
        let mut queue   = self.queue.lock().unwrap();
        let running     = self.running.lock().unwrap();

        queue.push_back(Box::new(job));

        !*running
    }

    ///
    /// If there are any jobs waiting, dequeues the next one
    ///
    fn dequeue(&self) -> Option<Box<ScheduledJob>> {
        let mut queue = self.queue.lock().unwrap();

        queue.pop_front()
    }

    ///
    /// Runs jobs on this queue until there are none left, marking the job as inactive when done
    ///
    fn drain(&self) {
        let mut done = false;

        while !done {
            // Run jobs until the queue is drained
            while let Some(mut job) = self.dequeue() {
                job.run();
            }

            // Mark as not running any more
            {
                let queue       = self.queue.lock().unwrap();
                let mut running = self.running.lock().unwrap();

                // If the queue is empty at the point where we obtain the 'running' lock, we can deactivate ourselves
                if queue.len() == 0 {
                    *running    = false;
                    done        = true;
                }
            }
        }
    }
}

impl Scheduler {
    ///
    /// Creates a new scheduler
    ///
    /// (There's only actually one scheduler)
    ///
    fn new() -> Scheduler {
        let result = Scheduler {
            queues:     Arc::new(Mutex::new(vec![])),
            threads:    Mutex::new(vec![])
        };

        result.spawn_thread();
        result.spawn_thread();
        result.spawn_thread();
        result.spawn_thread();

        result
    }

    ///
    /// Finds the next queue that should be run. If this returns successfully, the queue will
    /// be marked as running.
    ///
    fn next_to_run(queues: &Arc<Mutex<Vec<Weak<JobQueue>>>>) -> Option<Arc<JobQueue>> {
        // Search the queues...
        let queues = queues.lock().unwrap();

        // Find a queue where is_running is false
        for q in queues.iter() {
            // Queue is a weak ref, check that it's still in use
            if let Some(q) = q.upgrade() {
                // If the queue is not running, then mark it as running and return it
                let mut is_running = q.running.lock().unwrap();
                if !*is_running {
                    // Clone here is necessary because the is_running update is borrowing q
                    *is_running = true;
                    return Some(q.clone());
                }
            }
        }

        None
    }

    ///
    /// Attempts to schedule a task on a dormant thread
    ///
    fn schedule_dormant<TFn>(&self, job: TFn) -> bool
    where TFn: 'static+Send+FnOnce() -> () {
        let threads = self.threads.lock().unwrap();

        for thread in threads.iter() {
            let mut busy = thread.busy.lock().unwrap();

            if !*busy {
                let also_busy = thread.busy.clone();

                *busy = true;
                thread.run(Job::new(move || {
                    // Run the job
                    job();

                    // Thread is dormant again once this job completes
                    let mut busy = also_busy.lock().unwrap();
                    *busy = false;
                }));

                return true;
            }
        }

        // No dormant threads were found
        false
    }

    ///
    /// Wakes a thread to run a dormant queue. Returns true if a thread was woken up
    ///
    fn schedule_thread(&self) -> bool {
        // Find a dormant thread and activate it
        let queues = self.queues.clone();

        self.schedule_dormant(move || {
            // Run queues until there are no more to run, then become dormant again
            while let Some(work) = Self::next_to_run(&queues) {
                work.drain();
            }

            // TODO: if there are no dormant threads, there's a race here at the moment as this thread won't get rescheduled while it's 'dying'
        })
    }

    ///
    /// Spawns a thread in this scheduler
    ///
    pub fn spawn_thread(&self) {
        let new_thread = SchedulerThread::new();
        self.threads.lock().unwrap().push(new_thread);
    }

    ///
    /// Creates a new job queue for this scheduler
    ///
    pub fn create_job_queue(&self) -> Arc<JobQueue> {
        let new_queue = Arc::new(JobQueue::new());

        self.queues.lock().unwrap().push(Arc::downgrade(&new_queue));

        new_queue
    }

    ///
    /// Schedules a job on this scheduler
    ///
    pub fn async<TFn: 'static+Send+FnOnce() -> ()>(&self, queue: &Arc<JobQueue>, job: TFn) {
        if queue.queue(Job::new(job)) {
            // A true result indicates that the job was scheduled but the queue is not running. Try to schedule a thread if this occurs.
            self.schedule_thread();
        }
    }
}

///
/// Retrieves the global scheduler
///
pub fn scheduler<'a>() -> &'a Scheduler {
    &SCHEDULER
}

///
/// Creates a scheduler queue
///
pub fn queue() -> Arc<JobQueue> {
    scheduler().create_job_queue()
}

///
/// Creates a scheduler queue
///
pub fn async<TFn: 'static+Send+FnOnce() -> ()>(queue: &Arc<JobQueue>, job: TFn) {
    scheduler().async(queue, job)
}

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

    #[test]
    fn can_schedule_async() {
        let (tx, rx)    = channel();
        let queue       = queue();

        async(&queue, move || {
            tx.send(42).unwrap();
        });

        assert!(rx.recv().unwrap() == 42);
    }

    #[test]
    fn will_schedule_in_order() {
        let (tx, rx)    = channel();
        let queue       = queue();

        let (tx1, tx2)  = (tx.clone(), tx.clone());

        async(&queue, move || {
            sleep(Duration::from_millis(100));
            tx1.send(1).unwrap();
        });
        async(&queue, move || {
            tx2.send(2).unwrap();
        });

        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv().unwrap() == 2);
    }

    #[test]
    fn will_schedule_separate_queues_in_parallel() {
        let (tx, rx)        = channel();
        let queue1          = queue();
        let queue2          = queue();
        let queue2_has_run  = Arc::new(Mutex::new(false));

        let queue1_check = queue2_has_run.clone();

        async(&queue1, move || {
            // The other task needs to start within 100ms for this to work
            sleep(Duration::from_millis(100));
            tx.send(*queue1_check.lock().unwrap()).unwrap();
        });
        async(&queue2, move || {
            *queue2_has_run.lock().unwrap() = true;
        });

        assert!(rx.recv().unwrap() == true);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "shuf"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;
extern crate libc;

use std::cmp;
use std::from_str::from_str;
use std::io;
use std::io::IoResult;
use std::iter::{range_inclusive, RangeInclusive};
use std::rand;
use std::uint;

#[path = "../common/util.rs"]
mod util;

enum Mode {
    Default,
    Echo,
    InputRange(RangeInclusive<uint>)
}

static NAME: &'static str = "shuf";
static VERSION: &'static str = "0.0.1";

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();

    let opts = [
        getopts::optflag("e", "echo", "treat each ARG as an input line"),
        getopts::optopt("i", "input-range", "treat each number LO through HI as an input line", "LO-HI"),
        getopts::optopt("n", "head-count", "output at most COUNT lines", "COUNT"),
        getopts::optopt("o", "output", "write result to FILE instead of standard output", "FILE"),
        getopts::optopt("", "random-source", "get random bytes from FILE", "FILE"),
        getopts::optflag("r", "repeat", "output lines can be repeated"),
        getopts::optflag("z", "zero-terminated", "end lines with 0 byte, not newline"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];
    let mut matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "{}", f)
        }
    };
    if matches.opt_present("help") {
        println!("{name} v{version}

Usage:
  {prog} [OPTION]... [FILE]
  {prog} -e [OPTION]... [ARG]...
  {prog} -i LO-HI [OPTION]...\n
{usage}
With no FILE, or when FILE is -, read standard input.",
                 name = NAME, version = VERSION, prog = program,
                 usage = getopts::usage("Write a random permutation of the input lines to standard output.", opts));
    } else if matches.opt_present("version") {
        println!("{} v{}", NAME, VERSION);
    } else {
        let echo = matches.opt_present("echo");
        let mode = match matches.opt_str("input-range") {
            Some(range) => {
                if echo {
                    show_error!("cannot specify more than one mode");
                    return 1;
                }
                match parse_range(range) {
                    Ok(m) => InputRange(m),
                    Err((msg, code)) => {
                        show_error!("{}", msg);
                        return code;
                    }
                }
            }
            None => {
                if echo {
                    Echo
                } else {
                    if matches.free.len() == 0 {
                        matches.free.push("-".to_string());
                    }
                    Default
                }
            }
        };
        let repeat = matches.opt_present("repeat");
        let zero = matches.opt_present("zero-terminated");
        let count = match matches.opt_str("head-count") {
            Some(cnt) => match from_str::<uint>(cnt.as_slice()) {
                Some(val) => val,
                None => {
                    show_error!("'{}' is not a valid count", cnt);
                    return 1;
                }
            },
            None => uint::MAX
        };
        let output = matches.opt_str("output");
        let random = matches.opt_str("random-source");
        match shuf(matches.free, mode, repeat, zero, count, output, random) {
            Err(f) => {
                show_error!("{}", f);
                return 1;
            },
            _ => {}
        }
    }

    0
}

fn shuf(input: Vec<String>, mode: Mode, repeat: bool, zero: bool, count: uint, output: Option<String>, random: Option<String>) -> IoResult<()> {
    match mode {
        Echo => shuf_lines(input, repeat, zero, count, output, random),
        InputRange(range) => shuf_lines(range.map(|num| num.to_string()).collect(), repeat, zero, count, output, random),
        Default => {
            let lines: Vec<String> = input.into_iter().flat_map(|filename| {
                let slice = filename.as_slice();
                let mut file_buf;
                let mut stdin_buf;
                let mut file = io::BufferedReader::new(
                    if slice == "-" {
                        stdin_buf = io::stdio::stdin_raw();
                        &mut stdin_buf as &mut Reader
                    } else {
                        file_buf = crash_if_err!(1, io::File::open(&Path::new(slice)));
                        &mut file_buf as &mut Reader
                    }
                );
                let mut lines = vec!();
                for line in file.lines() {
                    let mut line = crash_if_err!(1, line);
                    line.pop();
                    lines.push(line);
                }
                lines.into_iter()
            }).collect();
            shuf_lines(lines, repeat, zero, count, output, random)
        }
    }
}

fn shuf_lines(mut lines: Vec<String>, repeat: bool, zero: bool, count: uint, outname: Option<String>, random: Option<String>) -> IoResult<()> {
    let mut output = match outname {
        Some(name) => box io::BufferedWriter::new(try!(io::File::create(&Path::new(name)))) as Box<Writer>,
        None => box io::stdout() as Box<Writer>
    };
    let mut rng = match random {
        Some(name) => box rand::reader::ReaderRng::new(try!(io::File::open(&Path::new(name)))) as Box<rand::Rng>,
        None => box rand::task_rng() as Box<rand::Rng>
    };
    let mut len = lines.len();
    let max = if repeat { count } else { cmp::min(count, len) };
    for _ in range(0, max) {
        let idx = rng.next_u32() as uint % len;
        try!(write!(output, "{}{}", lines[idx], if zero { '\0' } else { '\n' }));
        if !repeat {
            lines.remove(idx);
            len -= 1;
        }
    }
    Ok(())
}

fn parse_range(input_range: String) -> Result<RangeInclusive<uint>, (String, int)> {
    let split: Vec<&str> = input_range.as_slice().split('-').collect();
    if split.len() != 2 {
        Err(("invalid range format".to_string(), 1))
    } else {
        let begin = match from_str::<uint>(split[0]) {
            Some(m) => m,
            None => return Err((format!("{} is not a valid number", split[0]), 1))
        };
        let end = match from_str::<uint>(split[1]) {
            Some(m) => m,
            None => return Err((format!("{} is not a valid number", split[1]), 1))
        };
        Ok(range_inclusive(begin, end))
    }
}
<commit_msg>shuf: fix build<commit_after>#![crate_name = "shuf"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Arcterus <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;
extern crate libc;

use std::cmp;
use std::from_str::from_str;
use std::io;
use std::io::IoResult;
use std::iter::{range_inclusive, RangeInclusive};
use std::rand::{mod, Rng};
use std::uint;

#[path = "../common/util.rs"]
mod util;

enum Mode {
    Default,
    Echo,
    InputRange(RangeInclusive<uint>)
}

static NAME: &'static str = "shuf";
static VERSION: &'static str = "0.0.1";

pub fn uumain(args: Vec<String>) -> int {
    let program = args[0].clone();

    let opts = [
        getopts::optflag("e", "echo", "treat each ARG as an input line"),
        getopts::optopt("i", "input-range", "treat each number LO through HI as an input line", "LO-HI"),
        getopts::optopt("n", "head-count", "output at most COUNT lines", "COUNT"),
        getopts::optopt("o", "output", "write result to FILE instead of standard output", "FILE"),
        getopts::optopt("", "random-source", "get random bytes from FILE", "FILE"),
        getopts::optflag("r", "repeat", "output lines can be repeated"),
        getopts::optflag("z", "zero-terminated", "end lines with 0 byte, not newline"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit")
    ];
    let mut matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            crash!(1, "{}", f)
        }
    };
    if matches.opt_present("help") {
        println!("{name} v{version}

Usage:
  {prog} [OPTION]... [FILE]
  {prog} -e [OPTION]... [ARG]...
  {prog} -i LO-HI [OPTION]...\n
{usage}
With no FILE, or when FILE is -, read standard input.",
                 name = NAME, version = VERSION, prog = program,
                 usage = getopts::usage("Write a random permutation of the input lines to standard output.", opts));
    } else if matches.opt_present("version") {
        println!("{} v{}", NAME, VERSION);
    } else {
        let echo = matches.opt_present("echo");
        let mode = match matches.opt_str("input-range") {
            Some(range) => {
                if echo {
                    show_error!("cannot specify more than one mode");
                    return 1;
                }
                match parse_range(range) {
                    Ok(m) => InputRange(m),
                    Err((msg, code)) => {
                        show_error!("{}", msg);
                        return code;
                    }
                }
            }
            None => {
                if echo {
                    Echo
                } else {
                    if matches.free.len() == 0 {
                        matches.free.push("-".to_string());
                    }
                    Default
                }
            }
        };
        let repeat = matches.opt_present("repeat");
        let zero = matches.opt_present("zero-terminated");
        let count = match matches.opt_str("head-count") {
            Some(cnt) => match from_str::<uint>(cnt.as_slice()) {
                Some(val) => val,
                None => {
                    show_error!("'{}' is not a valid count", cnt);
                    return 1;
                }
            },
            None => uint::MAX
        };
        let output = matches.opt_str("output");
        let random = matches.opt_str("random-source");
        match shuf(matches.free, mode, repeat, zero, count, output, random) {
            Err(f) => {
                show_error!("{}", f);
                return 1;
            },
            _ => {}
        }
    }

    0
}

fn shuf(input: Vec<String>, mode: Mode, repeat: bool, zero: bool, count: uint, output: Option<String>, random: Option<String>) -> IoResult<()> {
    match mode {
        Echo => shuf_lines(input, repeat, zero, count, output, random),
        InputRange(range) => shuf_lines(range.map(|num| num.to_string()).collect(), repeat, zero, count, output, random),
        Default => {
            let lines: Vec<String> = input.into_iter().flat_map(|filename| {
                let slice = filename.as_slice();
                let mut file_buf;
                let mut stdin_buf;
                let mut file = io::BufferedReader::new(
                    if slice == "-" {
                        stdin_buf = io::stdio::stdin_raw();
                        &mut stdin_buf as &mut Reader
                    } else {
                        file_buf = crash_if_err!(1, io::File::open(&Path::new(slice)));
                        &mut file_buf as &mut Reader
                    }
                );
                let mut lines = vec!();
                for line in file.lines() {
                    let mut line = crash_if_err!(1, line);
                    line.pop();
                    lines.push(line);
                }
                lines.into_iter()
            }).collect();
            shuf_lines(lines, repeat, zero, count, output, random)
        }
    }
}

enum WrappedRng {
    RngFile(rand::reader::ReaderRng<io::File>),
    RngDefault(rand::TaskRng),
}

impl WrappedRng {
    fn next_u32(&mut self) -> u32 {
        match self {
            &RngFile(ref mut r) => r.next_u32(),
            &RngDefault(ref mut r) => r.next_u32(),
        }
    }
}

fn shuf_lines(mut lines: Vec<String>, repeat: bool, zero: bool, count: uint, outname: Option<String>, random: Option<String>) -> IoResult<()> {
    let mut output = match outname {
        Some(name) => box io::BufferedWriter::new(try!(io::File::create(&Path::new(name)))) as Box<Writer>,
        None => box io::stdout() as Box<Writer>
    };
    let mut rng = match random {
        Some(name) => RngFile(rand::reader::ReaderRng::new(try!(io::File::open(&Path::new(name))))),
        None => RngDefault(rand::task_rng()),
    };
    let mut len = lines.len();
    let max = if repeat { count } else { cmp::min(count, len) };
    for _ in range(0, max) {
        let idx = rng.next_u32() as uint % len;
        try!(write!(output, "{}{}", lines[idx], if zero { '\0' } else { '\n' }));
        if !repeat {
            lines.remove(idx);
            len -= 1;
        }
    }
    Ok(())
}

fn parse_range(input_range: String) -> Result<RangeInclusive<uint>, (String, int)> {
    let split: Vec<&str> = input_range.as_slice().split('-').collect();
    if split.len() != 2 {
        Err(("invalid range format".to_string(), 1))
    } else {
        let begin = match from_str::<uint>(split[0]) {
            Some(m) => m,
            None => return Err((format!("{} is not a valid number", split[0]), 1))
        };
        let end = match from_str::<uint>(split[1]) {
            Some(m) => m,
            None => return Err((format!("{} is not a valid number", split[1]), 1))
        };
        Ok(range_inclusive(begin, end))
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_sort"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Yin <mikeyin@mikeyin.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![allow(dead_code)]

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use std::cmp::Ordering;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, stdin, Write};
use std::path::Path;
use uucore::fs::is_stdin_interactive;

static NAME: &'static str = "sort";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflag("n", "numeric-sort", "compare according to string numerical value");
    opts.optflag("H", "human-readable-sort", "compare according to human readable sizes, eg 1M > 100k");
    opts.optflag("r", "reverse", "reverse the output");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
 {0} [OPTION]... [FILE]...

Write the sorted concatenation of all FILE(s) to standard output.

Mandatory arguments for long options are mandatory for short options too.

With no FILE, or when FILE is -, read standard input.", NAME, VERSION);
        print!("{}", opts.usage(&msg));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let numeric = matches.opt_present("numeric-sort");
    let human_readable = matches.opt_present("human-readable-sort");
    let reverse = matches.opt_present("reverse");

    let mut files = matches.free;
    if files.is_empty() {
        /* if no file, default to stdin */
        files.push("-".to_owned());
    }

    exec(files, numeric, human_readable, reverse);

    0
}

fn exec(files: Vec<String>, numeric: bool, human_readable: bool, reverse: bool) {
    for path in &files {
        let (reader, _) = match open(path) {
            Some(x) => x,
            None => continue,
        };

        let buf_reader = BufReader::new(reader);
        let mut lines = Vec::new();

        for line in buf_reader.lines() {
            match line {
                Ok(n) => {
                    lines.push(n);
                },
                _ => break
            }
        }

        if numeric {
            lines.sort_by(numeric_compare);
        } else if human_readable {
            lines.sort_by(human_readable_size_compare);
        } else {
            lines.sort();
        }

        let iter = lines.iter();
        if reverse {
            print_sorted(iter.rev());
        } else {
            print_sorted(iter)
        };
    }
}

/// Parse the beginning string into an f64, returning -inf instead of NaN on errors.
fn permissive_f64_parse(a: &str) -> f64{
    //Maybe should be split on non-digit, but then 10e100 won't parse properly.
    //On the flip side, this will give NEG_INFINITY for "1,234", which might be OK
    //because there's no way to handle both CSV and thousands separators without a new flag.
    //GNU sort treats "1,234" as "1" in numeric, so maybe it's fine.
    let sa: &str = a.split_whitespace().next().unwrap();
    match sa.parse::<f64>() {
        Ok(a) => a,
        Err(_) => std::f64::NEG_INFINITY
    }
}

/// Compares two floating point numbers, with errors being assumned to be -inf.
/// Stops coercing at the first whitespace char, so 1e2 will parse as 100 but
/// 1,000 will parse as -inf.
fn numeric_compare(a: &String, b: &String) -> Ordering {
    let fa = permissive_f64_parse(a);
    let fb = permissive_f64_parse(b);
    //f64::cmp isn't implemented because NaN messes with it
    //but we sidestep that with permissive_f64_parse so just fake it
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

fn human_readable_convert(a: &String) -> f64 {
    let int_iter = a.chars();
    let suffix_iter = a.chars();
    let int_str: String = int_iter.take_while(|c| c.is_numeric()).collect();
    let suffix = suffix_iter.skip_while(|c| c.is_numeric()).next();
    let int_part = match int_str.parse::<f64>() {
        Ok(i) => i,
        Err(_) => -1f64
    } as f64;
    let suffix: f64 = match suffix.unwrap_or('\0') {
        'K' => 1000f64,
        'M' => 1E6,
        'G' => 1E9,
        'T' => 1E12,
        'P' => 1E15,
        _ => 1f64
    };
    int_part * suffix
}

/// Compare two strings as if they are human readable sizes.
/// AKA 1M > 100k
fn human_readable_size_compare(a: &String, b: &String) -> Ordering {
    let fa = human_readable_convert(a);
    let fb = human_readable_convert(b);
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }

}

fn print_sorted<S, T: Iterator<Item=S>>(iter: T) where S: std::fmt::Display {
    for line in iter {
        println!("{}", line);
    }
}

// from cat.rs
fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(Path::new(path)) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            show_error!("sort: {0}: {1}", path, e.to_string());
            None
        },
    }
}
<commit_msg>sort: Implement -o switch<commit_after>#![crate_name = "uu_sort"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Yin <mikeyin@mikeyin.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![allow(dead_code)]

extern crate getopts;
extern crate libc;

#[macro_use]
extern crate uucore;

use std::cmp::Ordering;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Read, stdin, stdout, Write};
use std::path::Path;
use uucore::fs::is_stdin_interactive;

static NAME: &'static str = "sort";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflag("n", "numeric-sort", "compare according to string numerical value");
    opts.optflag("H", "human-readable-sort", "compare according to human readable sizes, eg 1M > 100k");
    opts.optflag("r", "reverse", "reverse the output");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");
    opts.optopt("o", "output", "write output to FILENAME instead of stdout", "FILENAME");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        let msg = format!("{0} {1}

Usage:
 {0} [OPTION]... [FILE]...

Write the sorted concatenation of all FILE(s) to standard output.

Mandatory arguments for long options are mandatory for short options too.

With no FILE, or when FILE is -, read standard input.", NAME, VERSION);
        print!("{}", opts.usage(&msg));
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    let numeric = matches.opt_present("numeric-sort");
    let human_readable = matches.opt_present("human-readable-sort");
    let reverse = matches.opt_present("reverse");
    let outfile = matches.opt_str("output");

    let mut files = matches.free;
    if files.is_empty() {
        /* if no file, default to stdin */
        files.push("-".to_owned());
    }

    exec(files, numeric, human_readable, reverse, outfile);

    0
}

fn exec(files: Vec<String>, numeric: bool, human_readable: bool, reverse: bool, outfile: Option<String>) {
    for path in &files {
        let (reader, _) = match open(path) {
            Some(x) => x,
            None => continue,
        };

        let buf_reader = BufReader::new(reader);
        let mut lines = Vec::new();

        for line in buf_reader.lines() {
            match line {
                Ok(n) => {
                    lines.push(n);
                },
                _ => break
            }
        }

        if numeric {
            lines.sort_by(numeric_compare);
        } else if human_readable {
            lines.sort_by(human_readable_size_compare);
        } else {
            lines.sort();
        }

        let iter = lines.iter();
        if reverse {
            print_sorted(iter.rev(), &outfile);
        } else {
            print_sorted(iter, &outfile)
        };
    }
}

/// Parse the beginning string into an f64, returning -inf instead of NaN on errors.
fn permissive_f64_parse(a: &str) -> f64{
    //Maybe should be split on non-digit, but then 10e100 won't parse properly.
    //On the flip side, this will give NEG_INFINITY for "1,234", which might be OK
    //because there's no way to handle both CSV and thousands separators without a new flag.
    //GNU sort treats "1,234" as "1" in numeric, so maybe it's fine.
    let sa: &str = a.split_whitespace().next().unwrap();
    match sa.parse::<f64>() {
        Ok(a) => a,
        Err(_) => std::f64::NEG_INFINITY
    }
}

/// Compares two floating point numbers, with errors being assumned to be -inf.
/// Stops coercing at the first whitespace char, so 1e2 will parse as 100 but
/// 1,000 will parse as -inf.
fn numeric_compare(a: &String, b: &String) -> Ordering {
    let fa = permissive_f64_parse(a);
    let fb = permissive_f64_parse(b);
    //f64::cmp isn't implemented because NaN messes with it
    //but we sidestep that with permissive_f64_parse so just fake it
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }
}

fn human_readable_convert(a: &String) -> f64 {
    let int_iter = a.chars();
    let suffix_iter = a.chars();
    let int_str: String = int_iter.take_while(|c| c.is_numeric()).collect();
    let suffix = suffix_iter.skip_while(|c| c.is_numeric()).next();
    let int_part = match int_str.parse::<f64>() {
        Ok(i) => i,
        Err(_) => -1f64
    } as f64;
    let suffix: f64 = match suffix.unwrap_or('\0') {
        'K' => 1000f64,
        'M' => 1E6,
        'G' => 1E9,
        'T' => 1E12,
        'P' => 1E15,
        _ => 1f64
    };
    int_part * suffix
}

/// Compare two strings as if they are human readable sizes.
/// AKA 1M > 100k
fn human_readable_size_compare(a: &String, b: &String) -> Ordering {
    let fa = human_readable_convert(a);
    let fb = human_readable_convert(b);
    if fa > fb {
        Ordering::Greater
    }
    else if fa < fb {
        Ordering::Less
    }
    else {
        Ordering::Equal
    }

}

fn print_sorted<S, T: Iterator<Item=S>>(iter: T, outfile: &Option<String>) where S: std::fmt::Display {
    let mut file: Box<Write> = match *outfile {
        Some(ref filename) => {
            match File::create(Path::new(&filename)) {
                Ok(f) => Box::new(BufWriter::new(f)) as Box<Write>,
                Err(e) => {
                    show_error!("sort: {0}: {1}", filename, e.to_string());
                    panic!("Could not open output file");
                },
            }
        },
        None => Box::new(stdout()) as Box<Write>,
    };

    for line in iter {
        let str = format!("{}\n", line);
        match file.write_all(str.as_bytes()) {
            Err(e) => {
                show_error!("sort: {0}", e.to_string());
                panic!("Write failed");
            },
            Ok(_) => (),
        }
    }
}

// from cat.rs
fn open(path: &str) -> Option<(Box<Read>, bool)> {
    if path == "-" {
        let stdin = stdin();
        return Some((Box::new(stdin) as Box<Read>, is_stdin_interactive()));
    }

    match File::open(Path::new(path)) {
        Ok(f) => Some((Box::new(f) as Box<Read>, false)),
        Err(e) => {
            show_error!("sort: {0}: {1}", path, e.to_string());
            None
        },
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2020 Fabian Schuiki

//! This crate implements SystemVerilog for the moore compiler.

#[macro_use]
extern crate moore_common;
#[macro_use]
extern crate log;

pub extern crate moore_svlog_syntax as syntax;
pub(crate) use moore_common as common;

// Inline the salsa crate as a module, since we use a very esoteric branch for
// now.
// TODO(fschuiki): Remove this once salsa is regular dep again
#[macro_use]
mod salsa;

/// Assert that a condition holds, or emit a bug diagnostic and panic.
#[macro_export]
macro_rules! assert_span {
    ($cond:expr, $span:expr, $emitter:expr) => ({
        $crate::assert_span!(@IMPL $cond, $span, $emitter, "assertion failed: {}", stringify!($cond))
    });
    ($cond:expr, $span:expr, $emitter:expr,) => ({
        $crate::assert_span!(@IMPL $cond, $span, $emitter, "assertion failed: {}", stringify!($cond))
    });
    ($cond:expr, $span:expr, $emitter:expr, $($arg:tt)+) => ({
        $crate::assert_span!(@IMPL $cond, $span, $emitter, $($arg)+)
    });
    (@IMPL $cond:expr, $span:expr, $emitter:expr, $($arg:tt)*) => ({
        if !$cond {
            let msg = format!($($arg)*);
            $emitter.emit(
                moore_common::errors::DiagBuilder2::bug(&msg)
                .span($span)
                .add_note(format!("Assertion failed: {}", stringify!($cond)))
                .add_note(format!("Encountered at {}:{}", file!(), line!()))
            );
            panic!("{}", msg);
        }
    });
}

/// Emit a bug diagnostic and panic.
#[macro_export]
macro_rules! bug_span {
    ($span:expr, $emitter:expr, $($arg:tt)+) => ({
        let msg = format!($($arg)*);
        $emitter.emit(
            moore_common::errors::DiagBuilder2::bug(&msg)
            .span($span)
            .add_note(format!("Encountered at {}:{}", file!(), line!()))
        );
        panic!("{}", msg);
    });
}

/// Assert that two types are identical, or emit a bug diagnostic and panic.
#[macro_export]
macro_rules! assert_type {
    ($lhs:expr, $rhs:expr, $span:expr, $emitter:expr) => ({
        $crate::assert_type!($lhs, $rhs, $span, $emitter,)
    });
    ($lhs:expr, $rhs:expr, $span:expr, $emitter:expr,) => ({
        $crate::assert_type!($lhs, $rhs, $span, $emitter, "type assertion failed: `{}` != `{}`", $lhs, $rhs)
    });
    ($lhs:expr, $rhs:expr, $span:expr, $emitter:expr, $($arg:tt)+) => ({
        if !$crate::ty::identical($lhs, $rhs) {
            let msg = format!($($arg)*);
            $emitter.emit(
                moore_common::errors::DiagBuilder2::bug(&msg)
                .span($span)
                .add_note("Type mismatch:")
                .add_note(format!("    Left-hand side:  `{}`", $lhs))
                .add_note(format!("    Right-hand side: `{}`", $rhs))
                .add_note(format!("Encountered at {}:{}", file!(), line!()))
            );
            panic!("{}", msg);
        }
    });
}

mod ast_map;
mod codegen;
mod context;
pub mod hir;
mod inst_details;
pub mod mir;
mod param_env;
mod port_mapping;
mod resolver;
pub mod ty;
pub mod typeck;
pub mod value;

pub use crate::{
    codegen::CodeGenerator,
    context::*,
    inst_details::{InstDetails, InstTargetDetails, InstVerbosityVisitor},
    param_env::{
        IntoNodeEnvId, NodeEnvId, ParamEnv, ParamEnvBinding, ParamEnvData, ParamEnvSource,
    },
    port_mapping::{PortMapping, PortMappingSource},
    resolver::{Rib, RibKind},
    syntax::*,
};

/// Items commonly used within the crate.
mod crate_prelude {
    #[allow(unused_imports)]
    pub(crate) use crate::{
        ast,
        common::{
            errors::*,
            name::Name,
            score::Result,
            source::{Span, Spanned},
            util::{HasDesc, HasSpan},
            NodeId, SessionContext, Verbosity,
        },
        context::{BaseContext, Context, GlobalContext},
        hir, mir, param_env, port_mapping,
        resolver::{self, Rib, RibKind},
        ty, typeck, value, IntoNodeEnvId, NodeEnvId, Ref,
    };
}

/// A node reference.
///
/// This reference is useful when querying the compiler database for information
/// about a node. It compares the reference *by pointer address*, thus allowing
/// for pessimistic compiler queries.
#[derive(Copy, Clone)]
pub struct Ref<'a, T>(&'a T);

impl<'a, T> From<&'a T> for Ref<'a, T> {
    fn from(r: &'a T) -> Ref<'a, T> {
        Ref(r)
    }
}

impl<'a, T> std::ops::Deref for Ref<'a, T> {
    type Target = &'a T;

    fn deref(&self) -> &&'a T {
        &self.0
    }
}

impl<T> Eq for Ref<'_, T> {}

impl<T> PartialEq for Ref<'_, T> {
    fn eq(&self, other: &Self) -> bool {
        std::ptr::eq(self.0, other.0)
    }
}

impl<T> std::hash::Hash for Ref<'_, T> {
    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
        std::ptr::hash(self.0, h)
    }
}

impl<T> std::fmt::Debug for Ref<'_, T>
where
    T: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(self.0, f)
    }
}

impl<T> std::fmt::Display for Ref<'_, T>
where
    T: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Display::fmt(self.0, f)
    }
}

impl<T> std::fmt::Binary for Ref<'_, T>
where
    T: std::fmt::Binary,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Binary::fmt(self.0, f)
    }
}
<commit_msg>svlog: Improve Ref<commit_after>// Copyright (c) 2016-2020 Fabian Schuiki

//! This crate implements SystemVerilog for the moore compiler.

#[macro_use]
extern crate moore_common;
#[macro_use]
extern crate log;

pub extern crate moore_svlog_syntax as syntax;
pub(crate) use moore_common as common;

// Inline the salsa crate as a module, since we use a very esoteric branch for
// now.
// TODO(fschuiki): Remove this once salsa is regular dep again
#[macro_use]
mod salsa;

/// Assert that a condition holds, or emit a bug diagnostic and panic.
#[macro_export]
macro_rules! assert_span {
    ($cond:expr, $span:expr, $emitter:expr) => ({
        $crate::assert_span!(@IMPL $cond, $span, $emitter, "assertion failed: {}", stringify!($cond))
    });
    ($cond:expr, $span:expr, $emitter:expr,) => ({
        $crate::assert_span!(@IMPL $cond, $span, $emitter, "assertion failed: {}", stringify!($cond))
    });
    ($cond:expr, $span:expr, $emitter:expr, $($arg:tt)+) => ({
        $crate::assert_span!(@IMPL $cond, $span, $emitter, $($arg)+)
    });
    (@IMPL $cond:expr, $span:expr, $emitter:expr, $($arg:tt)*) => ({
        if !$cond {
            let msg = format!($($arg)*);
            $emitter.emit(
                moore_common::errors::DiagBuilder2::bug(&msg)
                .span($span)
                .add_note(format!("Assertion failed: {}", stringify!($cond)))
                .add_note(format!("Encountered at {}:{}", file!(), line!()))
            );
            panic!("{}", msg);
        }
    });
}

/// Emit a bug diagnostic and panic.
#[macro_export]
macro_rules! bug_span {
    ($span:expr, $emitter:expr, $($arg:tt)+) => ({
        let msg = format!($($arg)*);
        $emitter.emit(
            moore_common::errors::DiagBuilder2::bug(&msg)
            .span($span)
            .add_note(format!("Encountered at {}:{}", file!(), line!()))
        );
        panic!("{}", msg);
    });
}

/// Assert that two types are identical, or emit a bug diagnostic and panic.
#[macro_export]
macro_rules! assert_type {
    ($lhs:expr, $rhs:expr, $span:expr, $emitter:expr) => ({
        $crate::assert_type!($lhs, $rhs, $span, $emitter,)
    });
    ($lhs:expr, $rhs:expr, $span:expr, $emitter:expr,) => ({
        $crate::assert_type!($lhs, $rhs, $span, $emitter, "type assertion failed: `{}` != `{}`", $lhs, $rhs)
    });
    ($lhs:expr, $rhs:expr, $span:expr, $emitter:expr, $($arg:tt)+) => ({
        if !$crate::ty::identical($lhs, $rhs) {
            let msg = format!($($arg)*);
            $emitter.emit(
                moore_common::errors::DiagBuilder2::bug(&msg)
                .span($span)
                .add_note("Type mismatch:")
                .add_note(format!("    Left-hand side:  `{}`", $lhs))
                .add_note(format!("    Right-hand side: `{}`", $rhs))
                .add_note(format!("Encountered at {}:{}", file!(), line!()))
            );
            panic!("{}", msg);
        }
    });
}

mod ast_map;
mod codegen;
mod context;
pub mod hir;
mod inst_details;
pub mod mir;
mod param_env;
mod port_mapping;
mod resolver;
pub mod ty;
pub mod typeck;
pub mod value;

pub use crate::{
    codegen::CodeGenerator,
    context::*,
    inst_details::{InstDetails, InstTargetDetails, InstVerbosityVisitor},
    param_env::{
        IntoNodeEnvId, NodeEnvId, ParamEnv, ParamEnvBinding, ParamEnvData, ParamEnvSource,
    },
    port_mapping::{PortMapping, PortMappingSource},
    resolver::{Rib, RibKind},
    syntax::*,
};

/// Items commonly used within the crate.
mod crate_prelude {
    #[allow(unused_imports)]
    pub(crate) use crate::{
        ast,
        common::{
            errors::*,
            name::Name,
            score::Result,
            source::{Span, Spanned},
            util::{HasDesc, HasSpan},
            NodeId, SessionContext, Verbosity,
        },
        context::{BaseContext, Context, GlobalContext},
        hir, mir, param_env, port_mapping,
        resolver::{self, Rib, RibKind},
        ty, typeck, value, IntoNodeEnvId, NodeEnvId, Ref,
    };
}

/// A node reference.
///
/// This reference is useful when querying the compiler database for information
/// about a node. It compares the reference *by pointer address*, thus allowing
/// for pessimistic compiler queries.
#[derive(Copy, Clone)]
pub struct Ref<'a, T: 'a + ?Sized>(&'a T);

impl<'a, T: ?Sized> From<&'a T> for Ref<'a, T> {
    fn from(r: &'a T) -> Ref<'a, T> {
        Ref(r)
    }
}

impl<'a, T: ?Sized> std::ops::Deref for Ref<'a, T> {
    type Target = &'a T;

    fn deref(&self) -> &&'a T {
        &self.0
    }
}

impl<T: ?Sized> Eq for Ref<'_, T> {}

impl<T: ?Sized> PartialEq for Ref<'_, T> {
    fn eq(&self, other: &Self) -> bool {
        std::ptr::eq(self.0, other.0)
    }
}

impl<T: ?Sized> std::hash::Hash for Ref<'_, T> {
    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
        std::ptr::hash(self.0, h)
    }
}

impl<T: ?Sized> std::fmt::Debug for Ref<'_, T>
where
    T: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Debug::fmt(self.0, f)
    }
}

impl<T: ?Sized> std::fmt::Display for Ref<'_, T>
where
    T: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Display::fmt(self.0, f)
    }
}

impl<T: ?Sized> std::fmt::Binary for Ref<'_, T>
where
    T: std::fmt::Binary,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Binary::fmt(self.0, f)
    }
}

/// A few checks to ensure that `Ref` can be passed around properly.
#[allow(dead_code, unused_variables)]
mod checks {
    use super::*;

    trait Dummy {}
    struct Foo;
    impl Dummy for Foo {}

    fn checks1<'a>(x: Ref<'a, impl Dummy>) {}
    fn checks2<'a>(x: Ref<'a, dyn Dummy>) {}

    fn checks3() {
        let foo = Foo;
        checks1(Ref(&foo));
        checks2(Ref(&foo));
    }

    fn checks4<'a>(x: Ref<'a, impl Dummy>) {
        checks2(Ref(*x));
    }

    fn checks5<'a>(x: Ref<'a, dyn Dummy>) {
        checks2(Ref(*x));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, Ben Boeckel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//     * Neither the name of this project nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::iter;

use crate::keytypes::User;
use crate::Keyring;

use super::utils;
use super::utils::kernel::*;
use super::utils::keys::*;

#[test]
fn empty_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<EmptyKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn unsupported_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<UnsupportedKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<InvalidKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EPERM));

    keyring.invalidate().unwrap()
}

#[test]
fn maxlen_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<MaxLenKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<OverlongKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn keyring_with_payload() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring
        .add_key::<KeyringShadow, _, _>("", "payload")
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn max_user_description() {
    let mut keyring = utils::new_test_keyring();
    // Subtract one because the NUL is added in the kernel API.
    let maxdesc: String = iter::repeat('a').take(*PAGE_SIZE - 1).collect();
    let res = keyring.add_key::<User, _, _>(maxdesc.as_ref(), "payload".as_bytes());
    // If the user's quota is smaller than this, it's an error.
    if KEY_INFO.maxbytes < *PAGE_SIZE {
        assert_eq!(res.unwrap_err(), errno::Errno(libc::EDQUOT));
    } else {
        let key = res.unwrap();
        assert_eq!(key.description().unwrap().description, maxdesc);
        key.invalidate().unwrap();
    }

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_user_description() {
    let mut keyring = utils::new_test_keyring();
    // On MIPS with < 3.19, there is a bug where this is allowed. 3.19 was released in Feb 2015,
    // so this is being ignored here.
    let toolarge: String = iter::repeat('a').take(*PAGE_SIZE).collect();
    let err = keyring
        .add_key::<User, _, _>(toolarge.as_ref(), "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_keyring() {
    let mut keyring = utils::invalid_keyring();
    let err = keyring
        .add_key::<User, _, _>("invalid_keyring", "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));
}

#[test]
fn add_key_to_non_keyring() {
    let mut keyring = utils::new_test_keyring();
    let expected = "stuff".as_bytes();
    let key = keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap();

    let mut not_a_keyring = unsafe { Keyring::new(key.serial()) };
    let err = not_a_keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENOTDIR));

    keyring.invalidate().unwrap()
}

#[test]
fn add_key() {
    let mut keyring = utils::new_test_keyring();

    let payload = "stuff".as_bytes();
    let key = keyring.add_key::<User, _, _>("add_key", payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}

#[test]
fn update_key_via_add() {
    let mut keyring = utils::new_test_keyring();

    let description = "update_key_via_add";

    let payload = "stuff".as_bytes();
    let key = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    let payload = "lizard".as_bytes();
    let key_updated = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key, key_updated);
    assert_eq!(key.read().unwrap(), payload);
    assert_eq!(key_updated.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}
<commit_msg>tests/add: simplify the payload values a bit<commit_after>// Copyright (c) 2019, Ben Boeckel
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//       this list of conditions and the following disclaimer in the documentation
//       and/or other materials provided with the distribution.
//     * Neither the name of this project nor the names of its contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::iter;

use crate::keytypes::User;
use crate::Keyring;

use super::utils;
use super::utils::kernel::*;
use super::utils::keys::*;

#[test]
fn empty_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<EmptyKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn unsupported_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<UnsupportedKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<InvalidKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EPERM));

    keyring.invalidate().unwrap()
}

#[test]
fn maxlen_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<MaxLenKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENODEV));

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_key_type() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring.add_key::<OverlongKey, _, _>("", ()).unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn keyring_with_payload() {
    let mut keyring = utils::new_test_keyring();
    let err = keyring
        .add_key::<KeyringShadow, _, _>("", "payload")
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn max_user_description() {
    let mut keyring = utils::new_test_keyring();
    // Subtract one because the NUL is added in the kernel API.
    let maxdesc: String = iter::repeat('a').take(*PAGE_SIZE - 1).collect();
    let res = keyring.add_key::<User, _, _>(maxdesc.as_ref(), "payload".as_bytes());
    // If the user's quota is smaller than this, it's an error.
    if KEY_INFO.maxbytes < *PAGE_SIZE {
        assert_eq!(res.unwrap_err(), errno::Errno(libc::EDQUOT));
    } else {
        let key = res.unwrap();
        assert_eq!(key.description().unwrap().description, maxdesc);
        key.invalidate().unwrap();
    }

    keyring.invalidate().unwrap()
}

#[test]
fn overlong_user_description() {
    let mut keyring = utils::new_test_keyring();
    // On MIPS with < 3.19, there is a bug where this is allowed. 3.19 was released in Feb 2015,
    // so this is being ignored here.
    let toolarge: String = iter::repeat('a').take(*PAGE_SIZE).collect();
    let err = keyring
        .add_key::<User, _, _>(toolarge.as_ref(), "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));

    keyring.invalidate().unwrap()
}

#[test]
fn invalid_keyring() {
    let mut keyring = utils::invalid_keyring();
    let err = keyring
        .add_key::<User, _, _>("invalid_keyring", "payload".as_bytes())
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::EINVAL));
}

#[test]
fn add_key_to_non_keyring() {
    let mut keyring = utils::new_test_keyring();
    let expected = "stuff".as_bytes();
    let key = keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap();

    let mut not_a_keyring = unsafe { Keyring::new(key.serial()) };
    let err = not_a_keyring
        .add_key::<User, _, _>("add_key_to_non_keyring", expected)
        .unwrap_err();
    assert_eq!(err, errno::Errno(libc::ENOTDIR));

    keyring.invalidate().unwrap()
}

#[test]
fn add_key() {
    let mut keyring = utils::new_test_keyring();

    let payload = "payload".as_bytes();
    let key = keyring.add_key::<User, _, _>("add_key", payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}

#[test]
fn update_key_via_add() {
    let mut keyring = utils::new_test_keyring();

    let description = "update_key_via_add";

    let payload = "payload".as_bytes();
    let key = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key.read().unwrap(), payload);

    let payload = "updated_payload".as_bytes();
    let key_updated = keyring.add_key::<User, _, _>(description, payload).unwrap();
    assert_eq!(key, key_updated);
    assert_eq!(key.read().unwrap(), payload);
    assert_eq!(key_updated.read().unwrap(), payload);

    keyring.invalidate().unwrap()
}
<|endoftext|>


<commit_before>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to [`Request::call`] in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC
/// [`Request`] via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
///
/// [`Request::call`]: struct.Request.html#method.call
/// [`Request`]: struct.Request.html
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// # Errors
    ///
    /// If a transport error occurs, it should be returned as a boxed error - the library will then
    /// return an appropriate [`Error`].
    ///
    /// [`Error`]: struct.Error.html
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [`Transport`]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and contains all
    /// required headers.
    ///
    /// In particular, the following headers must be present:
    ///
    /// ```notrust
    /// Content-Type: text/xml
    /// Content-Length: <body length>
    /// ```
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        response.headers().get::<ContentLength>()
            .ok_or_else(|| format!("expected Content-Length header, but none was found"))?;

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<commit_msg>Tiny doc addition<commit_after>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to [`Request::call`] in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC
/// [`Request`] via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
///
/// [`Request::call`]: struct.Request.html#method.call
/// [`Request`]: struct.Request.html
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// # Errors
    ///
    /// If a transport error occurs, it should be returned as a boxed error - the library will then
    /// return an appropriate [`Error`] to the caller.
    ///
    /// [`Error`]: struct.Error.html
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [`Transport`]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and contains all
    /// required headers.
    ///
    /// In particular, the following headers must be present:
    ///
    /// ```notrust
    /// Content-Type: text/xml
    /// Content-Length: <body length>
    /// ```
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        response.headers().get::<ContentLength>()
            .ok_or_else(|| format!("expected Content-Length header, but none was found"))?;

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<|endoftext|>