<commit_before>use std::{
    fs,
    path::{Path, PathBuf},
    sync::{mpsc, Arc},
    thread,
    time::Duration,
};
use crossbeam_channel::{Receiver, Sender, SendError};
use relative_path::RelativePathBuf;
use thread_worker::WorkerHandle;
use walkdir::WalkDir;
use parking_lot::Mutex;
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as _Watcher};

use crate::{RootConfig, Roots, VfsRoot};

pub(crate) enum Task {
    AddRoot {
        root: VfsRoot,
        config: Arc<RootConfig>,
    },
}

#[derive(Debug)]
pub enum TaskResult {
    BulkLoadRoot {
        root: VfsRoot,
        files: Vec<(RelativePathBuf, String)>,
    },
    AddSingleFile {
        root: VfsRoot,
        path: RelativePathBuf,
        text: String,
    },
    ChangeSingleFile {
        root: VfsRoot,
        path: RelativePathBuf,
        text: String,
    },
    RemoveSingleFile {
        root: VfsRoot,
        path: RelativePathBuf,
    },
}

#[derive(Debug)]
enum ChangeKind {
    Create,
    Write,
    Remove,
}

const WATCHER_DELAY: Duration = Duration::from_millis(250);

pub(crate) struct Worker {
    worker: thread_worker::Worker<Task, TaskResult>,
    worker_handle: WorkerHandle,
}

impl Worker {
    pub(crate) fn start(roots: Arc<Roots>) -> Worker {
        let (worker, worker_handle) =
            thread_worker::spawn("vfs", 128, move |input_receiver, output_sender| {
                let (notify_sender, notify_receiver) = mpsc::channel();
                let watcher = notify::watcher(notify_sender, WATCHER_DELAY)
                    .map_err(|e| log::error!("failed to spawn notify {}", e))
                    .ok();
                let ctx = WatcherCtx {
                    roots,
                    watcher: Arc::new(Mutex::new(watcher)),
                    sender: output_sender,
                };
                let thread = thread::spawn({
                    let ctx = ctx.clone();
                    move || {
                        let _ = notify_receiver
                            .into_iter()
                            // forward relevant events only
                            .try_for_each(|change| ctx.handle_debounced_event(change));
                    }
                });
                let res1 = input_receiver.into_iter().try_for_each(|t| match t {
                    Task::AddRoot { root, config } => watch_root(&ctx, root, Arc::clone(&config)),
                });
                drop(ctx.watcher.lock().take());
                drop(ctx);
                let res2 = thread.join();
                match &res2 {
                    Ok(()) => log::info!("... Watcher terminated with ok"),
                    Err(_) => log::error!("... Watcher terminated with err"),
                }
                res1.unwrap();
                res2.unwrap();
            });
        Worker {
            worker,
            worker_handle,
        }
    }

    pub(crate) fn sender(&self) -> &Sender<Task> {
        &self.worker.inp
    }

    pub(crate) fn receiver(&self) -> &Receiver<TaskResult> {
        &self.worker.out
    }

    pub(crate) fn shutdown(self) -> thread::Result<()> {
        let _ = self.worker.shutdown();
        self.worker_handle.shutdown()
    }
}

fn watch_root(
    woker: &WatcherCtx,
    root: VfsRoot,
    config: Arc<RootConfig>,
) -> Result<(), SendError<TaskResult>> {
    let mut guard = woker.watcher.lock();
    log::debug!("loading {} ...", config.root.as_path().display());
    let files = watch_recursive(guard.as_mut(), config.root.as_path(), &*config)
        .into_iter()
        .filter_map(|path| {
            let abs_path = path.to_path(&config.root);
            let text = read_to_string(&abs_path)?;
            Some((path, text))
        })
        .collect();
    woker
        .sender
        .send(TaskResult::BulkLoadRoot { root, files })?;
    log::debug!("... loaded {}", config.root.as_path().display());
    Ok(())
}

#[derive(Clone)]
struct WatcherCtx {
    roots: Arc<Roots>,
    watcher: Arc<Mutex<Option<RecommendedWatcher>>>,
    sender: Sender<TaskResult>,
}

impl WatcherCtx {
    fn handle_debounced_event(&self, ev: DebouncedEvent) -> Result<(), SendError<TaskResult>> {
        match ev {
            DebouncedEvent::NoticeWrite(_)
            | DebouncedEvent::NoticeRemove(_)
            | DebouncedEvent::Chmod(_) => {
                // ignore
            }
            DebouncedEvent::Rescan => {
                // TODO rescan all roots
            }
            DebouncedEvent::Create(path) => {
                self.handle_change(path, ChangeKind::Create)?;
            }
            DebouncedEvent::Write(path) => {
                self.handle_change(path, ChangeKind::Write)?;
            }
            DebouncedEvent::Remove(path) => {
                self.handle_change(path, ChangeKind::Remove)?;
            }
            DebouncedEvent::Rename(src, dst) => {
                self.handle_change(src, ChangeKind::Remove)?;
                self.handle_change(dst, ChangeKind::Create)?;
            }
            DebouncedEvent::Error(err, path) => {
                // TODO should we reload the file contents?
                log::warn!("watcher error \"{}\", {:?}", err, path);
            }
        }
        Ok(())
    }

    fn handle_change(&self, path: PathBuf, kind: ChangeKind) -> Result<(), SendError<TaskResult>> {
        let (root, rel_path) = match self.roots.find(&path) {
            None => return Ok(()),
            Some(it) => it,
        };
        let config = &self.roots[root];
        match kind {
            ChangeKind::Create => {
                let mut paths = Vec::new();
                if path.is_dir() {
                    let mut guard = self.watcher.lock();
                    paths.extend(watch_recursive(guard.as_mut(), &path, &config));
                } else {
                    paths.push(rel_path);
                }
                paths
                    .into_iter()
                    .filter_map(|rel_path| {
                        let abs_path = rel_path.to_path(&config.root);
                        let text = read_to_string(&abs_path)?;
                        Some((rel_path, text))
                    })
                    .try_for_each(|(path, text)| {
                        self.sender
                            .send(TaskResult::AddSingleFile { root, path, text })
                    })?
            }
            ChangeKind::Write => {
                if let Some(text) = read_to_string(&path) {
                    self.sender.send(TaskResult::ChangeSingleFile {
                        root,
                        path: rel_path,
                        text,
                    })?;
                }
            }
            ChangeKind::Remove => self.sender.send(TaskResult::RemoveSingleFile {
                root,
                path: rel_path,
            })?,
        }
        Ok(())
    }
}

fn watch_recursive(
    mut watcher: Option<&mut RecommendedWatcher>,
    dir: &Path,
    config: &RootConfig,
) -> Vec<RelativePathBuf> {
    let mut files = Vec::new();
    for entry in WalkDir::new(dir)
        .into_iter()
        .filter_entry(|it| config.contains(it.path()).is_some())
        .filter_map(|it| it.map_err(|e| log::warn!("watcher error: {}", e)).ok())
    {
        if entry.file_type().is_dir() {
            if let Some(watcher) = &mut watcher {
                watch_one(watcher, entry.path());
            }
        } else {
            let path = config.contains(entry.path()).unwrap();
            files.push(path.to_owned());
        }
    }
    files
}

fn watch_one(watcher: &mut RecommendedWatcher, dir: &Path) {
    match watcher.watch(dir, RecursiveMode::NonRecursive) {
        Ok(()) => log::debug!("watching \"{}\"", dir.display()),
        Err(e) => log::warn!("could not watch \"{}\": {}", dir.display(), e),
    }
}

fn read_to_string(path: &Path) -> Option<String> {
    fs::read_to_string(&path)
        .map_err(|e| log::warn!("failed to read file {}", e))
        .ok()
}
<commit_msg>cleanup: add result alias<commit_after>use std::{
    fs,
    thread,
    path::{Path, PathBuf},
    sync::{mpsc, Arc},
    time::Duration,
};
use crossbeam_channel::{Receiver, Sender};
use relative_path::RelativePathBuf;
use thread_worker::WorkerHandle;
use walkdir::WalkDir;
use parking_lot::Mutex;
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as _Watcher};

use crate::{RootConfig, Roots, VfsRoot};

type Result<T> = std::result::Result<T, crossbeam_channel::SendError<TaskResult>>;

pub(crate) enum Task {
    AddRoot {
        root: VfsRoot,
        config: Arc<RootConfig>,
    },
}

#[derive(Debug)]
pub enum TaskResult {
    BulkLoadRoot {
        root: VfsRoot,
        files: Vec<(RelativePathBuf, String)>,
    },
    AddSingleFile {
        root: VfsRoot,
        path: RelativePathBuf,
        text: String,
    },
    ChangeSingleFile {
        root: VfsRoot,
        path: RelativePathBuf,
        text: String,
    },
    RemoveSingleFile {
        root: VfsRoot,
        path: RelativePathBuf,
    },
}

#[derive(Debug)]
enum ChangeKind {
    Create,
    Write,
    Remove,
}

const WATCHER_DELAY: Duration = Duration::from_millis(250);

pub(crate) struct Worker {
    worker: thread_worker::Worker<Task, TaskResult>,
    worker_handle: WorkerHandle,
}

impl Worker {
    pub(crate) fn start(roots: Arc<Roots>) -> Worker {
        let (worker, worker_handle) =
            thread_worker::spawn("vfs", 128, move |input_receiver, output_sender| {
                let (notify_sender, notify_receiver) = mpsc::channel();
                let watcher = notify::watcher(notify_sender, WATCHER_DELAY)
                    .map_err(|e| log::error!("failed to spawn notify {}", e))
                    .ok();
                let ctx = WatcherCtx {
                    roots,
                    watcher: Arc::new(Mutex::new(watcher)),
                    sender: output_sender,
                };
                let thread = thread::spawn({
                    let ctx = ctx.clone();
                    move || {
                        let _ = notify_receiver
                            .into_iter()
                            // forward relevant events only
                            .try_for_each(|change| ctx.handle_debounced_event(change));
                    }
                });
                let res1 = input_receiver.into_iter().try_for_each(|t| match t {
                    Task::AddRoot { root, config } => watch_root(&ctx, root, Arc::clone(&config)),
                });
                drop(ctx.watcher.lock().take());
                drop(ctx);
                let res2 = thread.join();
                match &res2 {
                    Ok(()) => log::info!("... Watcher terminated with ok"),
                    Err(_) => log::error!("... Watcher terminated with err"),
                }
                res1.unwrap();
                res2.unwrap();
            });
        Worker {
            worker,
            worker_handle,
        }
    }

    pub(crate) fn sender(&self) -> &Sender<Task> {
        &self.worker.inp
    }

    pub(crate) fn receiver(&self) -> &Receiver<TaskResult> {
        &self.worker.out
    }

    pub(crate) fn shutdown(self) -> thread::Result<()> {
        let _ = self.worker.shutdown();
        self.worker_handle.shutdown()
    }
}

fn watch_root(woker: &WatcherCtx, root: VfsRoot, config: Arc<RootConfig>) -> Result<()> {
    let mut guard = woker.watcher.lock();
    log::debug!("loading {} ...", config.root.as_path().display());
    let files = watch_recursive(guard.as_mut(), config.root.as_path(), &*config)
        .into_iter()
        .filter_map(|path| {
            let abs_path = path.to_path(&config.root);
            let text = read_to_string(&abs_path)?;
            Some((path, text))
        })
        .collect();
    woker
        .sender
        .send(TaskResult::BulkLoadRoot { root, files })?;
    log::debug!("... loaded {}", config.root.as_path().display());
    Ok(())
}

#[derive(Clone)]
struct WatcherCtx {
    roots: Arc<Roots>,
    watcher: Arc<Mutex<Option<RecommendedWatcher>>>,
    sender: Sender<TaskResult>,
}

impl WatcherCtx {
    fn handle_debounced_event(&self, ev: DebouncedEvent) -> Result<()> {
        match ev {
            DebouncedEvent::NoticeWrite(_)
            | DebouncedEvent::NoticeRemove(_)
            | DebouncedEvent::Chmod(_) => {
                // ignore
            }
            DebouncedEvent::Rescan => {
                // TODO rescan all roots
            }
            DebouncedEvent::Create(path) => {
                self.handle_change(path, ChangeKind::Create)?;
            }
            DebouncedEvent::Write(path) => {
                self.handle_change(path, ChangeKind::Write)?;
            }
            DebouncedEvent::Remove(path) => {
                self.handle_change(path, ChangeKind::Remove)?;
            }
            DebouncedEvent::Rename(src, dst) => {
                self.handle_change(src, ChangeKind::Remove)?;
                self.handle_change(dst, ChangeKind::Create)?;
            }
            DebouncedEvent::Error(err, path) => {
                // TODO should we reload the file contents?
                log::warn!("watcher error \"{}\", {:?}", err, path);
            }
        }
        Ok(())
    }

    fn handle_change(&self, path: PathBuf, kind: ChangeKind) -> Result<()> {
        let (root, rel_path) = match self.roots.find(&path) {
            None => return Ok(()),
            Some(it) => it,
        };
        let config = &self.roots[root];
        match kind {
            ChangeKind::Create => {
                let mut paths = Vec::new();
                if path.is_dir() {
                    let mut guard = self.watcher.lock();
                    paths.extend(watch_recursive(guard.as_mut(), &path, &config));
                } else {
                    paths.push(rel_path);
                }
                paths
                    .into_iter()
                    .filter_map(|rel_path| {
                        let abs_path = rel_path.to_path(&config.root);
                        let text = read_to_string(&abs_path)?;
                        Some((rel_path, text))
                    })
                    .try_for_each(|(path, text)| {
                        self.sender
                            .send(TaskResult::AddSingleFile { root, path, text })
                    })?
            }
            ChangeKind::Write => {
                if let Some(text) = read_to_string(&path) {
                    self.sender.send(TaskResult::ChangeSingleFile {
                        root,
                        path: rel_path,
                        text,
                    })?;
                }
            }
            ChangeKind::Remove => self.sender.send(TaskResult::RemoveSingleFile {
                root,
                path: rel_path,
            })?,
        }
        Ok(())
    }
}

fn watch_recursive(
    mut watcher: Option<&mut RecommendedWatcher>,
    dir: &Path,
    config: &RootConfig,
) -> Vec<RelativePathBuf> {
    let mut files = Vec::new();
    for entry in WalkDir::new(dir)
        .into_iter()
        .filter_entry(|it| config.contains(it.path()).is_some())
        .filter_map(|it| it.map_err(|e| log::warn!("watcher error: {}", e)).ok())
    {
        if entry.file_type().is_dir() {
            if let Some(watcher) = &mut watcher {
                watch_one(watcher, entry.path());
            }
        } else {
            let path = config.contains(entry.path()).unwrap();
            files.push(path.to_owned());
        }
    }
    files
}

fn watch_one(watcher: &mut RecommendedWatcher, dir: &Path) {
    match watcher.watch(dir, RecursiveMode::NonRecursive) {
        Ok(()) => log::debug!("watching \"{}\"", dir.display()),
        Err(e) => log::warn!("could not watch \"{}\": {}", dir.display(), e),
    }
}

fn read_to_string(path: &Path) -> Option<String> {
    fs::read_to_string(&path)
        .map_err(|e| log::warn!("failed to read file {}", e))
        .ok()
}
<|endoftext|>


<commit_before>//! Tests for the registry

use std::sync::mpsc;
use std::thread;

use super::*;
use super::super::convert::{ToTable, FromTable};

use hlua;

lua_convertible! {
    #[derive(Debug, Clone, Eq, PartialEq)]
    struct Point {
        x: i32,
        y: i32
    }
}

const ERR: &'static str = "Key which was added no longer exists!";

#[test]
fn add_keys() {
    let num = 1i32;
    let double = -392f64;
    let string = "Hello world".to_string();
    let numbers = vec![1, 2, 3, 4, 5];
    let point = Point { x: -11, y: 12 };

    set(String::from("test_num"), LUA_READ, num);
    set(String::from("test_double"), LUA_READ, double);
    set(String::from("test_string"), LUA_READ, string.clone());
    set(String::from("test_numbers"), LUA_READ, numbers.clone());
    set(String::from("test_point"), LUA_READ, point.clone());

    assert!(contains_key(&String::from("test_num")));
    assert!(contains_key(&String::from("test_double")));
    assert!(contains_key(&String::from("test_string")));
    assert!(contains_key(&String::from("test_numbers")));
    assert!(contains_key(&String::from("test_point")));

    assert_eq!(get::<_, i32>(&String::from("test_num")).expect(ERR).1, num);
    assert_eq!(get::<_, f64>(&String::from("test_double")).expect(ERR).1, double);
    assert_eq!(get::<_,String>(&String::from("test_string")).expect(ERR).1, string);
    assert_eq!(get::<_, Vec<i32>>(&String::from("test_numbers")).expect(ERR).1,
               numbers);
    assert_eq!(get::<_, Point>(&String::from("test_point")).expect(ERR).1, point);

}

#[test]
fn perms() {
    set("perm_none".to_string(), LUA_PRIVATE, 0);
    set("perm_read".to_string(), LUA_READ, 1);
    set("perm_write".to_string(), LUA_WRITE, 2);

    assert_eq!(get::<_, i32>(&"perm_none".to_string()).expect(ERR).0, LUA_PRIVATE);
    assert_eq!(get::<_, i32>(&"perm_read".to_string()).expect(ERR).0, LUA_READ);
    assert_eq!(get::<_, i32>(&"perm_write".to_string()).expect(ERR).0, LUA_WRITE);
}

#[test]
fn multithreaded() {
    let (tx, rx) = mpsc::channel();

    let num = 1i32;
    let double = -392f64;
    let string = "Hello world".to_string();
    let numbers = vec![1, 2, 3, 4, 5];
    let point = Point { x: -11, y: 12 };

    let tx1 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_num"), num, tx1);
    });
    let tx2 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_double"), double, tx2);
    });
    let tx3 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_string"), string, tx3);
    });
    let tx4 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_numbers"), numbers, tx4);
    });
    let tx5 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_point"), point, tx5);
    });

    let mut result = true;

    for _ in 0..5 {
        result = result && rx.recv().expect("Unable to connect to read thread");
    }
    assert!(result);
}

fn read_thread<T>(name: String, in_val: T, sender: mpsc::Sender<bool>)
where T: ::std::fmt::Debug + FromTable + PartialEq {
    for _ in 1 .. 50 {
        if let Ok(acc_val) = get::<_, T>(&name) {
            let (acc, val) = acc_val;
            assert!(acc.contains(LUA_READ));
            assert_eq!(val, in_val);
        }
        else {
            sender.send(false).expect("Unable to reply to test thread");
        }
    }
    sender.send(true).expect("Unable to reply to test thread");
}
<commit_msg>Help ensure registry multithread test runs properly<commit_after>//! Tests for the registry

use std::sync::mpsc;
use std::thread;

use super::*;
use super::super::convert::{ToTable, FromTable};

use hlua;

lua_convertible! {
    #[derive(Debug, Clone, Eq, PartialEq)]
    struct Point {
        x: i32,
        y: i32
    }
}

const ERR: &'static str = "Key which was added no longer exists!";

#[test]
fn add_keys() {
    let num = 1i32;
    let double = -392f64;
    let string = "Hello world".to_string();
    let numbers = vec![1, 2, 3, 4, 5];
    let point = Point { x: -11, y: 12 };

    set(String::from("test_num"), LUA_READ, num);
    set(String::from("test_double"), LUA_READ, double);
    set(String::from("test_string"), LUA_READ, string.clone());
    set(String::from("test_numbers"), LUA_READ, numbers.clone());
    set(String::from("test_point"), LUA_READ, point.clone());

    assert!(contains_key(&String::from("test_num")));
    assert!(contains_key(&String::from("test_double")));
    assert!(contains_key(&String::from("test_string")));
    assert!(contains_key(&String::from("test_numbers")));
    assert!(contains_key(&String::from("test_point")));

    assert_eq!(get::<_, i32>(&String::from("test_num")).expect(ERR).1, num);
    assert_eq!(get::<_, f64>(&String::from("test_double")).expect(ERR).1, double);
    assert_eq!(get::<_,String>(&String::from("test_string")).expect(ERR).1, string);
    assert_eq!(get::<_, Vec<i32>>(&String::from("test_numbers")).expect(ERR).1,
               numbers);
    assert_eq!(get::<_, Point>(&String::from("test_point")).expect(ERR).1, point);

}

#[test]
fn lua_perms() {
    set("perm_none".to_string(), LUA_PRIVATE, 0);
    set("perm_read".to_string(), LUA_READ, 1);
    set("perm_write".to_string(), LUA_WRITE, 2);

    assert_eq!(get::<_, i32>(&"perm_none".to_string()).expect(ERR).0, LUA_PRIVATE);
    assert_eq!(get::<_, i32>(&"perm_read".to_string()).expect(ERR).0, LUA_READ);
    assert_eq!(get::<_, i32>(&"perm_write".to_string()).expect(ERR).0, LUA_WRITE);
}

#[test]
fn multithreaded() {
    use std::time::Duration;
    let (tx, rx) = mpsc::channel();
    thread::sleep(Duration::from_millis(240));
    let num = 1i32;
    let double = -392f64;
    let string = "Hello world".to_string();
    let numbers = vec![1, 2, 3, 4, 5];
    let point = Point { x: -11, y: 12 };

    let tx1 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_num"), num, tx1);
    });
    let tx2 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_double"), double, tx2);
    });
    let tx3 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_string"), string, tx3);
    });
    let tx4 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_numbers"), numbers, tx4);
    });
    let tx5 = tx.clone();
    thread::spawn(move || {
        read_thread(String::from("test_point"), point, tx5);
    });

    let mut result = true;

    for _ in 0..5 {
        result = result && rx.recv().expect("Unable to connect to read thread");
    }
    assert!(result);
}

fn read_thread<T>(name: String, in_val: T, sender: mpsc::Sender<bool>)
where T: ::std::fmt::Debug + FromTable + PartialEq {
    for _ in 1 .. 50 {
        if let Ok(acc_val) = get::<_, T>(&name) {
            let (acc, val) = acc_val;
            assert!(acc.contains(LUA_READ));
            assert_eq!(val, in_val);
        }
        else {
            sender.send(false).expect("Unable to reply to test thread");
        }
    }
    sender.send(true).expect("Unable to reply to test thread");
}
<|endoftext|>


<commit_before>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Use https://github.com/nox/serde_urlencoded
// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Move all enums here (ListingOrderBy, ListingSort, etc.)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.
// FIXME: Write nicer wrappers, getting rid of Listing.

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingSort {
    #[serde(rename = "asc")]
    Asc,
    #[serde(rename = "desc")]
    Desc,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingVisibility {
    #[serde(rename = "public")]
    Public,
    #[serde(rename = "internal")]
    Internal,
    #[serde(rename = "private")]
    Private,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct Milestone {
    pub id: i64,
    pub iid: i64,
    pub project_id: i64,
    pub title: String,
    pub description: String,
    pub state: MilestoneState,
    pub created_at: String,  // FIXME: Use date type?
    pub updated_at: String,  // FIXME: Use date type?
    pub due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
pub struct User {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: UserState,
    pub avatar_url: Option<String>,
    pub web_url: Option<String>
}
<commit_msg>Cleanup old fixmes<commit_after>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Use https://github.com/nox/serde_urlencoded
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingSort {
    #[serde(rename = "asc")]
    Asc,
    #[serde(rename = "desc")]
    Desc,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ListingVisibility {
    #[serde(rename = "public")]
    Public,
    #[serde(rename = "internal")]
    Internal,
    #[serde(rename = "private")]
    Private,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct Milestone {
    pub id: i64,
    pub iid: i64,
    pub project_id: i64,
    pub title: String,
    pub description: String,
    pub state: MilestoneState,
    pub created_at: String,  // FIXME: Use date type?
    pub updated_at: String,  // FIXME: Use date type?
    pub due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
pub struct User {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: UserState,
    pub avatar_url: Option<String>,
    pub web_url: Option<String>
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Handling log-probabilities.

use std::mem;
use std::f64;

pub use stats::{Prob, LogProb};

/// A factor to convert log-probabilities to PHRED-scale (phred = p * LOG_TO_PHRED_FACTOR).
const LOG_TO_PHRED_FACTOR: f64 = -4.3429448190325175; // -10 * 1 / ln(10)

/// A factor to convert PHRED-scale to log-probabilities (p = phred * PHRED_TO_LOG_FACTOR).
const PHRED_TO_LOG_FACTOR: f64 = -0.23025850929940456; // 1 / (-10 * log10(e))

/// Calculate log(1 - p) with p given in log space without loss of precision as described in
/// http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf.
pub fn ln_1m_exp(p: LogProb) -> LogProb {
    if p < -0.693 {
        (-p.exp()).ln_1p()
    }
    else {
        (-p.exp_m1()).ln()
    }
}

/// Convert log scale probability to PHRED scale.
pub fn log_to_phred(p: LogProb) -> f64 {
    p * LOG_TO_PHRED_FACTOR
}

/// Convert PHRED scale probability to log scale.
pub fn phred_to_log(p: f64) -> LogProb {
    p * PHRED_TO_LOG_FACTOR
}

/// Calculate the sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn log_prob_sum(probs: &[LogProb]) -> LogProb {
    if probs.is_empty() {
        f64::NEG_INFINITY
    }
    else {
        let mut pmax = probs[0];
        let mut imax = 0;
        for (i, &p) in probs.iter().enumerate().skip(1) {
            if p > pmax {
                pmax = p;
                imax = i;
            }
        }
        if pmax == f64::NEG_INFINITY {
            f64::NEG_INFINITY
        }
        else if pmax == f64::INFINITY {
            f64::INFINITY
        }
        else {
            // TODO use sum() once it has been stabilized: .sum::<usize>()
            pmax + (probs.iter().enumerate().filter_map(|(i, p)| if i != imax { Some((p - pmax).exp()) } else { None }).fold(0.0, |s, e| s + e)).ln_1p()
        }
    }
}

/// Calculate the sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn log_prob_add(mut p0: LogProb, mut p1: LogProb) -> LogProb {
    if p1 > p0 {
        mem::swap(&mut p0, &mut p1);
    }
    if p0 == f64::NEG_INFINITY {
        f64::NEG_INFINITY
    }
    else if p0 == f64::INFINITY {
        f64::INFINITY
    }
    else {
        p0 + (p1 - p0).exp().ln_1p()
    }
}

/// Calculate the cumulative sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn log_prob_cumsum<'a, I: Iterator<Item=&'a LogProb>>(probs: I) -> Vec<LogProb> {
    probs.scan(f64::NEG_INFINITY, |s, p| {
        *s = log_prob_add(*s, *p);
        Some(*s)
    }).collect()
}

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

    #[test]
    fn test_log_prob_sum() {
        let probs = [f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY];
        assert_eq!(log_prob_sum(&probs), 0.0);
    }

    #[test]
    fn test_empty_log_prob_sum() {
        assert_eq!(log_prob_sum(&[]), f64::NEG_INFINITY);
    }
}
<commit_msg>API refactoring of logprobs module.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Handling log-probabilities.

use std::mem;
use std::f64;

pub use stats::{Prob, LogProb};

/// A factor to convert log-probabilities to PHRED-scale (phred = p * LOG_TO_PHRED_FACTOR).
const LOG_TO_PHRED_FACTOR: f64 = -4.3429448190325175; // -10 * 1 / ln(10)

/// A factor to convert PHRED-scale to log-probabilities (p = phred * PHRED_TO_LOG_FACTOR).
const PHRED_TO_LOG_FACTOR: f64 = -0.23025850929940456; // 1 / (-10 * log10(e))

/// Calculate log(1 - p) with p given in log space without loss of precision as described in
/// http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf.
pub fn ln_1m_exp(p: LogProb) -> LogProb {
    if p < -0.693 {
        (-p.exp()).ln_1p()
    }
    else {
        (-p.exp_m1()).ln()
    }
}

/// Convert log scale probability to PHRED scale.
pub fn log_to_phred(p: LogProb) -> f64 {
    p * LOG_TO_PHRED_FACTOR
}

/// Convert PHRED scale probability to log scale.
pub fn phred_to_log(p: f64) -> LogProb {
    p * PHRED_TO_LOG_FACTOR
}

/// Calculate the sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn sum(probs: &[LogProb]) -> LogProb {
    if probs.is_empty() {
        f64::NEG_INFINITY
    }
    else {
        let mut pmax = probs[0];
        let mut imax = 0;
        for (i, &p) in probs.iter().enumerate().skip(1) {
            if p > pmax {
                pmax = p;
                imax = i;
            }
        }
        if pmax == f64::NEG_INFINITY {
            f64::NEG_INFINITY
        }
        else if pmax == f64::INFINITY {
            f64::INFINITY
        }
        else {
            // TODO use sum() once it has been stabilized: .sum::<usize>()
            pmax + (probs.iter().enumerate().filter_map(|(i, p)| if i != imax { Some((p - pmax).exp()) } else { None }).fold(0.0, |s, e| s + e)).ln_1p()
        }
    }
}

/// Calculate the sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn add(mut p0: LogProb, mut p1: LogProb) -> LogProb {
    if p1 > p0 {
        mem::swap(&mut p0, &mut p1);
    }
    if p0 == f64::NEG_INFINITY {
        f64::NEG_INFINITY
    }
    else if p0 == f64::INFINITY {
        f64::INFINITY
    }
    else {
        p0 + (p1 - p0).exp().ln_1p()
    }
}

/// Calculate the cumulative sum of the given probabilities in a numerically stable way (Durbin 1998).
pub fn cumsum<'a, I: Iterator<Item=&'a LogProb>>(probs: I) -> Vec<LogProb> {
    probs.scan(f64::NEG_INFINITY, |s, p| {
        *s = add(*s, *p);
        Some(*s)
    }).collect()
}

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

    #[test]
    fn test_sum() {
        let probs = [f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY];
        assert_eq!(sum(&probs), 0.0);
    }

    #[test]
    fn test_empty_sum() {
        assert_eq!(sum(&[]), f64::NEG_INFINITY);
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData, FileData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn new(spec: &FileHeaderSpec) -> Self;
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

pub trait FileDataParser<FD: FileData + Sized> : Sized {
    fn new() -> Self;
    fn read(&self, string: Option<String>) -> Result<FD, ParserError>;
    fn write(&self, data: &FD) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP, DP>
{
    headerp : HP,
    datap : DP,
}

impl<HP, DP> Parser<HP, DP> where
    HP: FileHeaderParser,
{

    fn new(headerp: HP, datap: DP) -> Parser<HP, DP> {
        Parser {
            headerp: headerp,
            datap: datap,
        }
    }

    pub fn read<FD>(&self, s: String) -> Result<(FileHeaderData, FD), ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let divided = self.divide_text(&s);

        if divided.is_err() {
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();

        let h_parseres = self.headerp.read(header);
        let d_parseres = self.datap.read(data);

        if h_parseres.is_err() {
            return Err(h_parseres.err().unwrap());
        }

        if d_parseres.is_err() {
            return Err(d_parseres.err().unwrap());
        }

        Ok((h_parseres.ok().unwrap(), d_parseres.ok().unwrap()))
    }

    fn write<FD>(&self, tpl : (FileHeaderData, FD)) -> Result<String, ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let (header, data) = tpl;
        let h_text = self.headerp.write(&header);
        let d_text = self.datap.write(&data);

        if h_text.is_err() {
            return Err(h_text.err().unwrap());
        }

        if d_text.is_err() {
            return Err(d_text.err().unwrap());
        }

        Ok(h_text.ok().unwrap() + &d_text.ok().unwrap()[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}

<commit_msg>Minify Parser.read()<commit_after>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData, FileData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser : Sized {
    fn new(spec: &FileHeaderSpec) -> Self;
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

pub trait FileDataParser<FD: FileData + Sized> : Sized {
    fn new() -> Self;
    fn read(&self, string: Option<String>) -> Result<FD, ParserError>;
    fn write(&self, data: &FD) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP, DP>
{
    headerp : HP,
    datap : DP,
}

impl<HP, DP> Parser<HP, DP> where
    HP: FileHeaderParser,
{

    fn new(headerp: HP, datap: DP) -> Parser<HP, DP> {
        Parser {
            headerp: headerp,
            datap: datap,
        }
    }

    pub fn read<FD>(&self, s: String) -> Result<(FileHeaderData, FD), ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let divided = self.divide_text(&s);

        if divided.is_err() {
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();

        let h_parseres = try!(self.headerp.read(header));
        let d_parseres = try!(self.datap.read(data));

        Ok((h_parseres, d_parseres))
    }

    fn write<FD>(&self, tpl : (FileHeaderData, FD)) -> Result<String, ParserError>
        where FD: FileData + Sized,
              DP: FileDataParser<FD>
    {
        let (header, data) = tpl;
        let h_text = self.headerp.write(&header);
        let d_text = self.datap.write(&data);

        if h_text.is_err() {
            return Err(h_text.err().unwrap());
        }

        if d_text.is_err() {
            return Err(d_text.err().unwrap());
        }

        Ok(h_text.ok().unwrap() + &d_text.ok().unwrap()[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}

<|endoftext|>


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

use std::error::Error;
use std::fmt;
use std::io;

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

use engine::EngineError;

pub type StratisResult<T> = Result<T, StratisError>;

#[derive(Debug)]
pub enum StratisError {
    Engine(EngineError),
    StderrNotFound,
    Io(io::Error),

    #[cfg(feature="dbus_enabled")]
    Dbus(dbus::Error),
}

impl fmt::Display for StratisError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StratisError::Engine(ref err) => {
                write!(f, "Engine error: {}", err.description().to_owned())
            }
            StratisError::StderrNotFound => write!(f, "stderr not found"),
            StratisError::Io(ref err) => write!(f, "IO error: {}", err),

            #[cfg(feature="dbus_enabled")]
            StratisError::Dbus(ref err) => {
                write!(f, "Dbus error: {}", err.message().unwrap_or("Unknown"))
            }
        }
    }
}

impl Error for StratisError {
    fn description(&self) -> &str {
        match *self {
            StratisError::Engine(ref err) => Error::description(err),
            StratisError::StderrNotFound => "stderr not found",
            StratisError::Io(ref err) => err.description(),

            #[cfg(feature="dbus_enabled")]
            StratisError::Dbus(ref err) => err.message().unwrap_or("D-Bus Error"),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            StratisError::Engine(ref err) => Some(err),
            StratisError::StderrNotFound => None,
            StratisError::Io(ref err) => Some(err),

            #[cfg(feature="dbus_enabled")]
            StratisError::Dbus(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for StratisError {
    fn from(err: io::Error) -> StratisError {
        StratisError::Io(err)
    }
}

#[cfg(feature="dbus_enabled")]
impl From<dbus::Error> for StratisError {
    fn from(err: dbus::Error) -> StratisError {
        StratisError::Dbus(err)
    }
}

impl From<EngineError> for StratisError {
    fn from(err: EngineError) -> StratisError {
        StratisError::Engine(err)
    }
}
<commit_msg>errors.rs: Add ability to convert from udev to StratisError<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate libudev;

use std::error::Error;
use std::fmt;
use std::io;

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

use engine::EngineError;

pub type StratisResult<T> = Result<T, StratisError>;

#[derive(Debug)]
pub enum StratisError {
    Engine(EngineError),
    StderrNotFound,
    Io(io::Error),

    #[cfg(feature="dbus_enabled")]
    Dbus(dbus::Error),
    Udev(libudev::Error),
}

impl fmt::Display for StratisError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StratisError::Engine(ref err) => {
                write!(f, "Engine error: {}", err.description().to_owned())
            }
            StratisError::StderrNotFound => write!(f, "stderr not found"),
            StratisError::Io(ref err) => write!(f, "IO error: {}", err),

            #[cfg(feature="dbus_enabled")]
            StratisError::Dbus(ref err) => {
                write!(f, "Dbus error: {}", err.message().unwrap_or("Unknown"))
            }
            StratisError::Udev(ref err) => write!(f, "Udev error: {}", err),
        }
    }
}

impl Error for StratisError {
    fn description(&self) -> &str {
        match *self {
            StratisError::Engine(ref err) => Error::description(err),
            StratisError::StderrNotFound => "stderr not found",
            StratisError::Io(ref err) => err.description(),

            #[cfg(feature="dbus_enabled")]
            StratisError::Dbus(ref err) => err.message().unwrap_or("D-Bus Error"),
            StratisError::Udev(ref err) => Error::description(err),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            StratisError::Engine(ref err) => Some(err),
            StratisError::StderrNotFound => None,
            StratisError::Io(ref err) => Some(err),
            #[cfg(feature="dbus_enabled")]
            StratisError::Dbus(ref err) => Some(err),
            StratisError::Udev(ref err) => Some(err),
        }
    }
}

impl From<io::Error> for StratisError {
    fn from(err: io::Error) -> StratisError {
        StratisError::Io(err)
    }
}

#[cfg(feature="dbus_enabled")]
impl From<dbus::Error> for StratisError {
    fn from(err: dbus::Error) -> StratisError {
        StratisError::Dbus(err)
    }
}

impl From<EngineError> for StratisError {
    fn from(err: EngineError) -> StratisError {
        StratisError::Engine(err)
    }
}

/// Allow ability to convert from libudev error to stratis error
impl From<libudev::Error> for StratisError {
    fn from(err: libudev::Error) -> StratisError {
        StratisError::Udev(err)
    }
}
<|endoftext|>


<commit_before>// A subset of termion's event parsing.
// Termion (c) 2016 Ticki
// Licensed under the MIT license

use std::io::{Result, Error, ErrorKind};
use std::str;

#[derive(Debug)]
pub enum Event {
    Key(Key),
    Unknown(Vec<u8>)
}

#[derive(Debug)]
pub enum Key {
    Escape,
    Backspace,
    Tab,

    Left, Right, Up, Down,

    Home, End,

    PageUp, PageDown,

    Delete, Insert,

    Char(char),
    Alt(char),
    Ctrl(char),

    F(u8),

    Null
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event>
    where I: Iterator<Item = Result<u8>>
{
    let error = Error::new(ErrorKind::Other, "Could not parse an event");
    match item {
        b'\x1B' => {
            // This is an escape character, leading a control sequence.
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        // F1-F4
                        Some(Ok(val @ b'P'..=b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return Err(error),
                    }
                }
                Some(Ok(b'[')) => {
                    // This is a CSI sequence.
                    parse_csi(iter).ok_or(error)?
                }
                Some(Ok(c)) => {
                    let ch = try!(parse_utf8_char(c, iter));
                    Event::Key(Key::Alt(ch))
                }
                Some(Err(_)) | None => return Err(error),
            })
        }
        b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
        b'\t' => Ok(Event::Key(Key::Char('\t'))),
        b'\x7F' => Ok(Event::Key(Key::Backspace)),
        c @ b'\x01'..=b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        c @ b'\x1C'..=b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))),
        b'\0' => Ok(Event::Key(Key::Null)),
        c => {
            Ok({
                let ch = try!(parse_utf8_char(c, iter));
                Event::Key(Key::Char(ch))
            })
        }
    }
}

/// Parses a CSI sequence, just after reading ^[
///
/// Returns None if an unrecognized sequence is found.
fn parse_csi<I>(iter: &mut I) -> Option<Event>
    where I: Iterator<Item = Result<u8>>
{
    Some(match iter.next() {
        Some(Ok(b'D')) => Event::Key(Key::Left),
        Some(Ok(b'C')) => Event::Key(Key::Right),
        Some(Ok(b'A')) => Event::Key(Key::Up),
        Some(Ok(b'B')) => Event::Key(Key::Down),
        Some(Ok(b'H')) => Event::Key(Key::Home),
        Some(Ok(b'F')) => Event::Key(Key::End),
        Some(Ok(c @ b'0'..=b'9')) => {
            // Numbered escape code.
            let mut buf = Vec::new();
            buf.push(c);
            let mut c = iter.next().unwrap().unwrap();
            // The final byte of a CSI sequence can be in the range 64-126, so
            // let's keep reading anything else.
            while c < 64 || c > 126 {
                buf.push(c);
                c = iter.next().unwrap().unwrap();
            }

            match c {
                // Special key code.
                b'~' => {
                    let str_buf = String::from_utf8(buf).unwrap();

                    // This CSI sequence can be a list of semicolon-separated
                    // numbers.
                    let nums: Vec<u8> = str_buf
                        .split(';')
                        .map(|n| n.parse().unwrap())
                        .collect();

                    if nums.is_empty() {
                        return None;
                    }

                    // TODO: handle multiple values for key modififiers (ex: values
                    // [3, 2] means Shift+Delete)
                    if nums.len() > 1 {
                        return None;
                    }

                    match nums[0] {
                        1 | 7 => Event::Key(Key::Home),
                        2 => Event::Key(Key::Insert),
                        3 => Event::Key(Key::Delete),
                        4 | 8 => Event::Key(Key::End),
                        5 => Event::Key(Key::PageUp),
                        6 => Event::Key(Key::PageDown),
                        v @ 11..=15 => Event::Key(Key::F(v - 10)),
                        v @ 17..=21 => Event::Key(Key::F(v - 11)),
                        v @ 23..=24 => Event::Key(Key::F(v - 12)),
                        _ => return None,
                    }
                }
                _ => return None,
            }
        }
        _ => return None,
    })

}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char>
    where I: Iterator<Item = Result<u8>>
{
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap());
            }
            if bytes.len() >= 4 {
                return error;
            }
        }
    }
}
<commit_msg>Remove try! macro usage in favour of ? operator<commit_after>// A subset of termion's event parsing.
// Termion (c) 2016 Ticki
// Licensed under the MIT license

use std::io::{Result, Error, ErrorKind};
use std::str;

#[derive(Debug)]
pub enum Event {
    Key(Key),
    Unknown(Vec<u8>)
}

#[derive(Debug)]
pub enum Key {
    Escape,
    Backspace,
    Tab,

    Left, Right, Up, Down,

    Home, End,

    PageUp, PageDown,

    Delete, Insert,

    Char(char),
    Alt(char),
    Ctrl(char),

    F(u8),

    Null
}

/// Parse an Event from `item` and possibly subsequent bytes through `iter`.
pub fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event>
    where I: Iterator<Item = Result<u8>>
{
    let error = Error::new(ErrorKind::Other, "Could not parse an event");
    match item {
        b'\x1B' => {
            // This is an escape character, leading a control sequence.
            Ok(match iter.next() {
                Some(Ok(b'O')) => {
                    match iter.next() {
                        // F1-F4
                        Some(Ok(val @ b'P'..=b'S')) => Event::Key(Key::F(1 + val - b'P')),
                        _ => return Err(error),
                    }
                }
                Some(Ok(b'[')) => {
                    // This is a CSI sequence.
                    parse_csi(iter).ok_or(error)?
                }
                Some(Ok(c)) => {
                    let ch = parse_utf8_char(c, iter)?;
                    Event::Key(Key::Alt(ch))
                }
                Some(Err(_)) | None => return Err(error),
            })
        }
        b'\n' | b'\r' => Ok(Event::Key(Key::Char('\n'))),
        b'\t' => Ok(Event::Key(Key::Char('\t'))),
        b'\x7F' => Ok(Event::Key(Key::Backspace)),
        c @ b'\x01'..=b'\x1A' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1 + b'a') as char))),
        c @ b'\x1C'..=b'\x1F' => Ok(Event::Key(Key::Ctrl((c as u8 - 0x1C + b'4') as char))),
        b'\0' => Ok(Event::Key(Key::Null)),
        c => {
            Ok({
                let ch = parse_utf8_char(c, iter)?;
                Event::Key(Key::Char(ch))
            })
        }
    }
}

/// Parses a CSI sequence, just after reading ^[
///
/// Returns None if an unrecognized sequence is found.
fn parse_csi<I>(iter: &mut I) -> Option<Event>
    where I: Iterator<Item = Result<u8>>
{
    Some(match iter.next() {
        Some(Ok(b'D')) => Event::Key(Key::Left),
        Some(Ok(b'C')) => Event::Key(Key::Right),
        Some(Ok(b'A')) => Event::Key(Key::Up),
        Some(Ok(b'B')) => Event::Key(Key::Down),
        Some(Ok(b'H')) => Event::Key(Key::Home),
        Some(Ok(b'F')) => Event::Key(Key::End),
        Some(Ok(c @ b'0'..=b'9')) => {
            // Numbered escape code.
            let mut buf = Vec::new();
            buf.push(c);
            let mut c = iter.next().unwrap().unwrap();
            // The final byte of a CSI sequence can be in the range 64-126, so
            // let's keep reading anything else.
            while c < 64 || c > 126 {
                buf.push(c);
                c = iter.next().unwrap().unwrap();
            }

            match c {
                // Special key code.
                b'~' => {
                    let str_buf = String::from_utf8(buf).unwrap();

                    // This CSI sequence can be a list of semicolon-separated
                    // numbers.
                    let nums: Vec<u8> = str_buf
                        .split(';')
                        .map(|n| n.parse().unwrap())
                        .collect();

                    if nums.is_empty() {
                        return None;
                    }

                    // TODO: handle multiple values for key modififiers (ex: values
                    // [3, 2] means Shift+Delete)
                    if nums.len() > 1 {
                        return None;
                    }

                    match nums[0] {
                        1 | 7 => Event::Key(Key::Home),
                        2 => Event::Key(Key::Insert),
                        3 => Event::Key(Key::Delete),
                        4 | 8 => Event::Key(Key::End),
                        5 => Event::Key(Key::PageUp),
                        6 => Event::Key(Key::PageDown),
                        v @ 11..=15 => Event::Key(Key::F(v - 10)),
                        v @ 17..=21 => Event::Key(Key::F(v - 11)),
                        v @ 23..=24 => Event::Key(Key::F(v - 12)),
                        _ => return None,
                    }
                }
                _ => return None,
            }
        }
        _ => return None,
    })

}

/// Parse `c` as either a single byte ASCII char or a variable size UTF-8 char.
fn parse_utf8_char<I>(c: u8, iter: &mut I) -> Result<char>
    where I: Iterator<Item = Result<u8>>
{
    let error = Err(Error::new(ErrorKind::Other, "Input character is not valid UTF-8"));
    if c.is_ascii() {
        Ok(c as char)
    } else {
        let bytes = &mut Vec::new();
        bytes.push(c);

        loop {
            bytes.push(iter.next().unwrap().unwrap());
            if let Ok(st) = str::from_utf8(bytes) {
                return Ok(st.chars().next().unwrap());
            }
            if bytes.len() >= 4 {
                return error;
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::iter::FusedIterator;

use crate::size_hint;

pub struct CoalesceBy<I, F, T>
where
    I: Iterator,
{
    iter: I,
    last: Option<T>,
    f: F,
}

impl<I: Clone, F: Clone, T: Clone> Clone for CoalesceBy<I, F, T>
where
    I: Iterator,
{
    clone_fields!(last, iter, f);
}

impl<I, F, T> fmt::Debug for CoalesceBy<I, F, T>
where
    I: Iterator + fmt::Debug,
    T: fmt::Debug,
{
    debug_fmt_fields!(CoalesceBy, iter);
}

pub trait CoalescePredicate<Item, T> {
    fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>;
}

impl<I, F, T> Iterator for CoalesceBy<I, F, T>
where
    I: Iterator,
    F: CoalescePredicate<I::Item, T>,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        // this fuses the iterator
        let mut last = match self.last.take() {
            None => return None,
            Some(x) => x,
        };
        for next in &mut self.iter {
            match self.f.coalesce_pair(last, next) {
                Ok(joined) => last = joined,
                Err((last_, next_)) => {
                    self.last = Some(next_);
                    return Some(last_);
                }
            }
        }
        Some(last)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize);
        ((low > 0) as usize, hi)
    }

    fn fold<Acc, FnAcc>(self, acc: Acc, mut fn_acc: FnAcc) -> Acc
    where
        FnAcc: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(last) = self.last {
            let mut f = self.f;
            let (last, acc) = self.iter.fold((last, acc), |(last, acc), elt| {
                match f.coalesce_pair(last, elt) {
                    Ok(joined) => (joined, acc),
                    Err((last_, next_)) => (next_, fn_acc(acc, last_)),
                }
            });
            fn_acc(acc, last)
        } else {
            acc
        }
    }
}

impl<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for CoalesceBy<I, F, T> {}

/// An iterator adaptor that may join together adjacent elements.
///
/// See [`.coalesce()`](crate::Itertools::coalesce) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type Coalesce<I, F> = CoalesceBy<I, F, <I as Iterator>::Item>;

impl<F, Item, T> CoalescePredicate<Item, T> for F
where
    F: FnMut(T, Item) -> Result<T, (T, T)>,
{
    fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)> {
        self(t, item)
    }
}

/// Create a new `Coalesce`.
pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F>
where
    I: Iterator,
{
    Coalesce {
        last: iter.next(),
        iter,
        f,
    }
}

/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
///
/// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DedupBy<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, <I as Iterator>::Item>;

#[derive(Clone)]
pub struct DedupPred2CoalescePred<DP>(DP);

pub trait DedupPredicate<T> {
    // TODO replace by Fn(&T, &T)->bool once Rust supports it
    fn dedup_pair(&mut self, a: &T, b: &T) -> bool;
}

impl<DP, T> CoalescePredicate<T, T> for DedupPred2CoalescePred<DP>
where
    DP: DedupPredicate<T>,
{
    fn coalesce_pair(&mut self, t: T, item: T) -> Result<T, (T, T)> {
        if self.0.dedup_pair(&t, &item) {
            Ok(t)
        } else {
            Err((t, item))
        }
    }
}

#[derive(Clone)]
pub struct DedupEq;

impl<T: PartialEq> DedupPredicate<T> for DedupEq {
    fn dedup_pair(&mut self, a: &T, b: &T) -> bool {
        a == b
    }
}

impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F {
    fn dedup_pair(&mut self, a: &T, b: &T) -> bool {
        self(a, b)
    }
}

/// Create a new `DedupBy`.
pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
where
    I: Iterator,
{
    DedupBy {
        last: iter.next(),
        iter,
        f: DedupPred2CoalescePred(dedup_pred),
    }
}

/// An iterator adaptor that removes repeated duplicates.
///
/// See [`.dedup()`](crate::Itertools::dedup) for more information.
pub type Dedup<I> = DedupBy<I, DedupEq>;

/// Create a new `Dedup`.
pub fn dedup<I>(iter: I) -> Dedup<I>
where
    I: Iterator,
{
    dedup_by(iter, DedupEq)
}

/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
/// repeated elements were present. This will determine equality using a comparison function.
///
/// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or
/// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DedupByWithCount<I, Pred> =
    CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, (usize, <I as Iterator>::Item)>;

#[derive(Clone)]
pub struct DedupPredWithCount2CoalescePred<DP>(DP);

impl<DP, T> CoalescePredicate<T, (usize, T)> for DedupPredWithCount2CoalescePred<DP>
where
    DP: DedupPredicate<T>,
{
    fn coalesce_pair(
        &mut self,
        (c, t): (usize, T),
        item: T,
    ) -> Result<(usize, T), ((usize, T), (usize, T))> {
        if self.0.dedup_pair(&t, &item) {
            Ok((c + 1, t))
        } else {
            Err(((c, t), (1, item)))
        }
    }
}

/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
/// repeated elements were present.
///
/// See [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>;

/// Create a new `DedupByWithCount`.
pub fn dedup_by_with_count<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
where
    I: Iterator,
{
    DedupByWithCount {
        last: iter.next().map(|v| (1, v)),
        iter,
        f: DedupPredWithCount2CoalescePred(dedup_pred),
    }
}

/// Create a new `DedupWithCount`.
pub fn dedup_with_count<I>(iter: I) -> DedupWithCount<I>
where
    I: Iterator,
{
    dedup_by_with_count(iter, DedupEq)
}
<commit_msg>Use internal iteration in coalesce<commit_after>use std::fmt;
use std::iter::FusedIterator;

use crate::size_hint;

pub struct CoalesceBy<I, F, T>
where
    I: Iterator,
{
    iter: I,
    last: Option<T>,
    f: F,
}

impl<I: Clone, F: Clone, T: Clone> Clone for CoalesceBy<I, F, T>
where
    I: Iterator,
{
    clone_fields!(last, iter, f);
}

impl<I, F, T> fmt::Debug for CoalesceBy<I, F, T>
where
    I: Iterator + fmt::Debug,
    T: fmt::Debug,
{
    debug_fmt_fields!(CoalesceBy, iter);
}

pub trait CoalescePredicate<Item, T> {
    fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)>;
}

impl<I, F, T> Iterator for CoalesceBy<I, F, T>
where
    I: Iterator,
    F: CoalescePredicate<I::Item, T>,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        // this fuses the iterator
        let last = self.last.take()?;

        let self_last = &mut self.last;
        let self_f = &mut self.f;
        Some(
            self.iter
                .try_fold(last, |last, next| match self_f.coalesce_pair(last, next) {
                    Ok(joined) => Ok(joined),
                    Err((last_, next_)) => {
                        *self_last = Some(next_);
                        Err(last_)
                    }
                })
                .unwrap_or_else(|x| x),
        )
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), self.last.is_some() as usize);
        ((low > 0) as usize, hi)
    }

    fn fold<Acc, FnAcc>(self, acc: Acc, mut fn_acc: FnAcc) -> Acc
    where
        FnAcc: FnMut(Acc, Self::Item) -> Acc,
    {
        if let Some(last) = self.last {
            let mut f = self.f;
            let (last, acc) = self.iter.fold((last, acc), |(last, acc), elt| {
                match f.coalesce_pair(last, elt) {
                    Ok(joined) => (joined, acc),
                    Err((last_, next_)) => (next_, fn_acc(acc, last_)),
                }
            });
            fn_acc(acc, last)
        } else {
            acc
        }
    }
}

impl<I: Iterator, F: CoalescePredicate<I::Item, T>, T> FusedIterator for CoalesceBy<I, F, T> {}

/// An iterator adaptor that may join together adjacent elements.
///
/// See [`.coalesce()`](crate::Itertools::coalesce) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type Coalesce<I, F> = CoalesceBy<I, F, <I as Iterator>::Item>;

impl<F, Item, T> CoalescePredicate<Item, T> for F
where
    F: FnMut(T, Item) -> Result<T, (T, T)>,
{
    fn coalesce_pair(&mut self, t: T, item: Item) -> Result<T, (T, T)> {
        self(t, item)
    }
}

/// Create a new `Coalesce`.
pub fn coalesce<I, F>(mut iter: I, f: F) -> Coalesce<I, F>
where
    I: Iterator,
{
    Coalesce {
        last: iter.next(),
        iter,
        f,
    }
}

/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function.
///
/// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DedupBy<I, Pred> = CoalesceBy<I, DedupPred2CoalescePred<Pred>, <I as Iterator>::Item>;

#[derive(Clone)]
pub struct DedupPred2CoalescePred<DP>(DP);

pub trait DedupPredicate<T> {
    // TODO replace by Fn(&T, &T)->bool once Rust supports it
    fn dedup_pair(&mut self, a: &T, b: &T) -> bool;
}

impl<DP, T> CoalescePredicate<T, T> for DedupPred2CoalescePred<DP>
where
    DP: DedupPredicate<T>,
{
    fn coalesce_pair(&mut self, t: T, item: T) -> Result<T, (T, T)> {
        if self.0.dedup_pair(&t, &item) {
            Ok(t)
        } else {
            Err((t, item))
        }
    }
}

#[derive(Clone)]
pub struct DedupEq;

impl<T: PartialEq> DedupPredicate<T> for DedupEq {
    fn dedup_pair(&mut self, a: &T, b: &T) -> bool {
        a == b
    }
}

impl<T, F: FnMut(&T, &T) -> bool> DedupPredicate<T> for F {
    fn dedup_pair(&mut self, a: &T, b: &T) -> bool {
        self(a, b)
    }
}

/// Create a new `DedupBy`.
pub fn dedup_by<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupBy<I, Pred>
where
    I: Iterator,
{
    DedupBy {
        last: iter.next(),
        iter,
        f: DedupPred2CoalescePred(dedup_pred),
    }
}

/// An iterator adaptor that removes repeated duplicates.
///
/// See [`.dedup()`](crate::Itertools::dedup) for more information.
pub type Dedup<I> = DedupBy<I, DedupEq>;

/// Create a new `Dedup`.
pub fn dedup<I>(iter: I) -> Dedup<I>
where
    I: Iterator,
{
    dedup_by(iter, DedupEq)
}

/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
/// repeated elements were present. This will determine equality using a comparison function.
///
/// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or
/// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub type DedupByWithCount<I, Pred> =
    CoalesceBy<I, DedupPredWithCount2CoalescePred<Pred>, (usize, <I as Iterator>::Item)>;

#[derive(Clone)]
pub struct DedupPredWithCount2CoalescePred<DP>(DP);

impl<DP, T> CoalescePredicate<T, (usize, T)> for DedupPredWithCount2CoalescePred<DP>
where
    DP: DedupPredicate<T>,
{
    fn coalesce_pair(
        &mut self,
        (c, t): (usize, T),
        item: T,
    ) -> Result<(usize, T), ((usize, T), (usize, T))> {
        if self.0.dedup_pair(&t, &item) {
            Ok((c + 1, t))
        } else {
            Err(((c, t), (1, item)))
        }
    }
}

/// An iterator adaptor that removes repeated duplicates, while keeping a count of how many
/// repeated elements were present.
///
/// See [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information.
pub type DedupWithCount<I> = DedupByWithCount<I, DedupEq>;

/// Create a new `DedupByWithCount`.
pub fn dedup_by_with_count<I, Pred>(mut iter: I, dedup_pred: Pred) -> DedupByWithCount<I, Pred>
where
    I: Iterator,
{
    DedupByWithCount {
        last: iter.next().map(|v| (1, v)),
        iter,
        f: DedupPredWithCount2CoalescePred(dedup_pred),
    }
}

/// Create a new `DedupWithCount`.
pub fn dedup_with_count<I>(iter: I) -> DedupWithCount<I>
where
    I: Iterator,
{
    dedup_by_with_count(iter, DedupEq)
}
<|endoftext|>


<commit_before>#![crate_id(name="tr", vers="1.0.0", author="Michael Gehring")]

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

extern crate collections;
extern crate getopts;

use collections::hashmap::HashSet;
use collections::smallintmap::SmallIntMap;
use getopts::OptGroup;
use std::char::from_u32;
use std::io::print;
use std::io::stdio::{stdin,stdout};
use std::iter::FromIterator;
use std::os;
use std::vec::Vec;

static NAME : &'static str = "tr";
static VERSION : &'static str = "1.0.0";

fn unescape_char(c: char) -> char {
    match c {
        'a' => 0x07u8 as char,
        'b' => 0x08u8 as char,
        'f' => 0x0cu8 as char,
        'v' => 0x0bu8 as char,
        'n' => '\n',
        'r' => '\r',
        't' => '\t',
        _ => c,
    }
}

fn unescape(v: Vec<char>) -> Vec<char> {
    let mut out = Vec::new();
    let mut input = v.as_slice();
    loop {
        input = match input {
            ['\\', e, ..rest] => {
                out.push(unescape_char(e));
                rest
            }
            [c, ..rest] => {
                out.push(c);
                rest
            }
            [] => break
        }
    }
    out
}

fn expand_range(from: char, to: char) -> Vec<char> {
    range(from as u32, to as u32 + 1).map(|c| from_u32(c).unwrap()).collect()
}

fn expand_set(s: &str) -> Vec<char> {
    let mut set = Vec::<char>::new();
    let unesc = unescape(FromIterator::from_iter(s.chars()));
    let mut input = unesc.as_slice();

    loop {
        input = match input {
            [f, '-', t, ..rest] => {
                set.push_all(expand_range(f, t).as_slice());
                rest
            }
            [c, ..rest] => {
                set.push(c);
                rest
            }
            [] => break
        };
    }
    set
}

fn delete(set: Vec<char>) {
    let mut hset = HashSet::new();
    let mut out = stdout();

    for &c in set.iter() {
        hset.insert(c);
    }

    for c in stdin().chars() {
        match c {
            Ok(c) if !hset.contains(&c) => out.write_char(c).unwrap(),
            Ok(_) => (),
            Err(err) => fail!("{}", err),
        };
    }
}

fn tr(set1: &[char], set2: &[char]) {
    let mut map = SmallIntMap::<char>::new();
    let mut out = stdout();

    for i in range(0, set1.len()) {
        if i >= set2.len() {
            map.insert(set1[i] as uint, set2[set2.len()-1]);
        } else {
            map.insert(set1[i] as uint, set2[i]);
        }
    }

    for c in stdin().chars() {
        match c {
            Ok(inc) => {
                let trc = match map.find(&(inc as uint)) {
                    Some(t) => *t,
                    None => inc,
                };
                out.write_char(trc).unwrap();
            }
            Err(err) => {
                fail!("{}", err);
            }
        }
    }
}

fn usage(opts: &[OptGroup]) {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] SET1 [SET2]", NAME);
        println!("");
        print(getopts::usage("Translate or delete characters.", opts).as_slice());
}

pub fn main() {
    let args: Vec<StrBuf> = os::args().iter().map(|x| x.to_strbuf()).collect();
    let opts = [
        getopts::optflag("d", "delete", "delete characters in SET1"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(err) => fail!("{}", err.to_err_msg()),
    };

    if matches.opt_present("help") {
        usage(opts);
        return
    }

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

    if matches.free.len() == 0 {
        usage(opts);
        os::set_exit_status(1);
        return
    }

    let dflag = matches.opt_present("d");
    let sets = matches.free;

    if dflag {
        let set1 = expand_set(sets.get(0).as_slice());
        delete(set1);
    } else {
        let set1 = expand_set(sets.get(0).as_slice());
        let set2 = expand_set(sets.get(1).as_slice());
        tr(set1.as_slice(), set2.as_slice());
    }
}
<commit_msg>tr: use BitvSet instead of HashSet<commit_after>#![crate_id(name="tr", vers="1.0.0", author="Michael Gehring")]

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

extern crate collections;
extern crate getopts;

use collections::bitv::BitvSet;
use collections::smallintmap::SmallIntMap;
use getopts::OptGroup;
use std::char::from_u32;
use std::io::print;
use std::io::stdio::{stdin,stdout};
use std::iter::FromIterator;
use std::os;
use std::vec::Vec;

static NAME : &'static str = "tr";
static VERSION : &'static str = "1.0.0";

fn unescape_char(c: char) -> char {
    match c {
        'a' => 0x07u8 as char,
        'b' => 0x08u8 as char,
        'f' => 0x0cu8 as char,
        'v' => 0x0bu8 as char,
        'n' => '\n',
        'r' => '\r',
        't' => '\t',
        _ => c,
    }
}

fn unescape(v: Vec<char>) -> Vec<char> {
    let mut out = Vec::new();
    let mut input = v.as_slice();
    loop {
        input = match input {
            ['\\', e, ..rest] => {
                out.push(unescape_char(e));
                rest
            }
            [c, ..rest] => {
                out.push(c);
                rest
            }
            [] => break
        }
    }
    out
}

fn expand_range(from: char, to: char) -> Vec<char> {
    range(from as u32, to as u32 + 1).map(|c| from_u32(c).unwrap()).collect()
}

fn expand_set(s: &str) -> Vec<char> {
    let mut set = Vec::<char>::new();
    let unesc = unescape(FromIterator::from_iter(s.chars()));
    let mut input = unesc.as_slice();

    loop {
        input = match input {
            [f, '-', t, ..rest] => {
                set.push_all(expand_range(f, t).as_slice());
                rest
            }
            [c, ..rest] => {
                set.push(c);
                rest
            }
            [] => break
        };
    }
    set
}

fn delete(set: Vec<char>) {
    let mut bset = BitvSet::new();
    let mut out = stdout();

    for &c in set.iter() {
        bset.insert(c as uint);
    }

    for c in stdin().chars() {
        match c {
            Ok(c) if !bset.contains(&(c as uint)) => out.write_char(c).unwrap(),
            Ok(_) => (),
            Err(err) => fail!("{}", err),
        };
    }
}

fn tr(set1: &[char], set2: &[char]) {
    let mut map = SmallIntMap::<char>::new();
    let mut out = stdout();

    for i in range(0, set1.len()) {
        if i >= set2.len() {
            map.insert(set1[i] as uint, set2[set2.len()-1]);
        } else {
            map.insert(set1[i] as uint, set2[i]);
        }
    }

    for c in stdin().chars() {
        match c {
            Ok(inc) => {
                let trc = match map.find(&(inc as uint)) {
                    Some(t) => *t,
                    None => inc,
                };
                out.write_char(trc).unwrap();
            }
            Err(err) => {
                fail!("{}", err);
            }
        }
    }
}

fn usage(opts: &[OptGroup]) {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] SET1 [SET2]", NAME);
        println!("");
        print(getopts::usage("Translate or delete characters.", opts).as_slice());
}

pub fn main() {
    let args: Vec<StrBuf> = os::args().iter().map(|x| x.to_strbuf()).collect();
    let opts = [
        getopts::optflag("d", "delete", "delete characters in SET1"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(err) => fail!("{}", err.to_err_msg()),
    };

    if matches.opt_present("help") {
        usage(opts);
        return
    }

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

    if matches.free.len() == 0 {
        usage(opts);
        os::set_exit_status(1);
        return
    }

    let dflag = matches.opt_present("d");
    let sets = matches.free;

    if dflag {
        let set1 = expand_set(sets.get(0).as_slice());
        delete(set1);
    } else {
        let set1 = expand_set(sets.get(0).as_slice());
        let set2 = expand_set(sets.get(1).as_slice());
        tr(set1.as_slice(), set2.as_slice());
    }
}
<|endoftext|>


<commit_before>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms},
    gpu::arc::ArcBuffer,
    Image, WgpuContext,
};
use crevice::std140::AsStd140;
use std::{
    collections::BTreeMap,
    sync::{
        atomic::{AtomicBool, AtomicU32, Ordering::SeqCst},
        Arc,
    },
};

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug, Clone)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    pub(crate) indices: ArcBuffer,
    pub(crate) image: Image,
    dirty: Arc<AtomicBool>,
    instances: Vec<DrawParam>,
    capacity: u32,
    len: Arc<AtomicU32>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    pub fn new(gfx: &GraphicsContext, image: impl Into<Option<Image>>, capacity: u32) -> Self {
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            capacity,
        )
    }

    fn new_wgpu(wgpu: &WgpuContext, image: Image, capacity: u32) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let indices = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: std::mem::size_of::<u32>() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_SRC
                | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        let instances = Vec::with_capacity(capacity as usize);

        InstanceArray {
            buffer,
            indices,
            image,
            dirty: Arc::new(AtomicBool::new(false)),
            instances,
            capacity,
            len: Arc::new(AtomicU32::new(0)),
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    pub fn set(&mut self, instances: impl IntoIterator<Item = DrawParam>) {
        self.dirty.store(true, SeqCst);
        self.instances = instances.into_iter().collect();
    }

    /// Pushes a new instance onto the end.
    pub fn push(&mut self, instance: DrawParam) {
        self.dirty.store(true, SeqCst);
        self.instances.push(instance);
    }

    /// Updates an existing instance at a given index, and returns the previous value at the index.
    pub fn update(&mut self, index: u32, instance: DrawParam) -> Option<DrawParam> {
        self.dirty.store(true, SeqCst);
        Some(std::mem::replace(
            self.instances.get_mut(index as usize)?,
            instance,
        ))
    }

    /// Returns an immutable reference to all the instance data.
    #[inline]
    pub fn instances(&self) -> &[DrawParam] {
        &self.instances
    }

    /// Returns a mutable reference to all the instance data.
    #[inline]
    pub fn instances_mut(&mut self) -> &mut [DrawParam] {
        self.dirty.store(true, SeqCst);
        &mut self.instances
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        self.len.store(0, SeqCst);
        self.instances.clear();
    }

    /// Returns whether the instance data has been changed without [`InstanceArray::flush()`] being called.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        self.dirty.load(SeqCst)
    }

    /// Uploads the instance data to the GPU.
    ///
    /// You do not usually need to call this yourself as it is done automatically during drawing.
    pub fn flush(&mut self, gfx: &GraphicsContext) {
        self.flush_wgpu(&gfx.wgpu)
    }

    #[allow(unsafe_code)]
    pub(crate) fn flush_wgpu(&mut self, wgpu: &WgpuContext) {
        if !self.is_dirty() {
            return;
        } else {
            self.dirty.store(false, SeqCst);
        }

        let mut layers = BTreeMap::<_, Vec<_>>::new();
        let instances = self
            .instances
            .iter()
            .enumerate()
            .map(|(i, param)| {
                layers.entry(param.z).or_default().push(i as u32);
                DrawUniforms::from_param(
                    *param,
                    [self.image.width() as f32, self.image.height() as f32].into(),
                )
                .as_std140()
            })
            .collect::<Vec<_>>();

        let len = instances.len() as u32;
        if len > self.capacity {
            self.resize_impl(wgpu, len, false);
        }

        self.len.store(instances.len() as u32, SeqCst);
        wgpu.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                instances.as_ptr() as *const u8,
                instances.len() * DrawUniforms::std140_size_static(),
            )
        });

        let indices = layers
            .into_iter()
            .map(|(_, x)| x)
            .flatten()
            .collect::<Vec<_>>();
        wgpu.queue.write_buffer(&self.indices, 0, unsafe {
            std::slice::from_raw_parts(
                indices.as_ptr() as *const u8,
                indices.len() * std::mem::size_of::<u32>(),
            )
        });
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &GraphicsContext, new_capacity: u32) {
        self.resize_impl(&gfx.wgpu, new_capacity, true)
    }

    fn resize_impl(&mut self, wgpu: &WgpuContext, new_capacity: u32, copy: bool) {
        let len = self.len.load(SeqCst);
        let resized = InstanceArray::new_wgpu(wgpu, self.image.clone(), new_capacity);
        resized.len.store(new_capacity.min(len), SeqCst);

        if copy {
            let cmd = {
                let mut cmd = wgpu.device.create_command_encoder(&Default::default());
                cmd.copy_buffer_to_buffer(
                    &self.buffer,
                    0,
                    &resized.buffer,
                    0,
                    new_capacity.min(len) as u64 * DrawUniforms::std140_size_static() as u64,
                );
                cmd.finish()
            };
            wgpu.queue.submit([cmd]);
        }

        *self = resized;
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray].
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }

    #[inline]
    pub(crate) fn len(&self) -> usize {
        self.len.load(SeqCst) as usize
    }

    #[inline]
    pub(crate) fn is_empty(&self) -> bool {
        self.len.load(SeqCst) == 0
    }
}
<commit_msg>fix clippy warning<commit_after>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms},
    gpu::arc::ArcBuffer,
    Image, WgpuContext,
};
use crevice::std140::AsStd140;
use std::{
    collections::BTreeMap,
    sync::{
        atomic::{AtomicBool, AtomicU32, Ordering::SeqCst},
        Arc,
    },
};

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug, Clone)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    pub(crate) indices: ArcBuffer,
    pub(crate) image: Image,
    dirty: Arc<AtomicBool>,
    instances: Vec<DrawParam>,
    capacity: u32,
    len: Arc<AtomicU32>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    pub fn new(gfx: &GraphicsContext, image: impl Into<Option<Image>>, capacity: u32) -> Self {
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            capacity,
        )
    }

    fn new_wgpu(wgpu: &WgpuContext, image: Image, capacity: u32) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let indices = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: std::mem::size_of::<u32>() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_SRC
                | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        let instances = Vec::with_capacity(capacity as usize);

        InstanceArray {
            buffer,
            indices,
            image,
            dirty: Arc::new(AtomicBool::new(false)),
            instances,
            capacity,
            len: Arc::new(AtomicU32::new(0)),
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    pub fn set(&mut self, instances: impl IntoIterator<Item = DrawParam>) {
        self.dirty.store(true, SeqCst);
        self.instances = instances.into_iter().collect();
    }

    /// Pushes a new instance onto the end.
    pub fn push(&mut self, instance: DrawParam) {
        self.dirty.store(true, SeqCst);
        self.instances.push(instance);
    }

    /// Updates an existing instance at a given index, and returns the previous value at the index.
    pub fn update(&mut self, index: u32, instance: DrawParam) -> Option<DrawParam> {
        self.dirty.store(true, SeqCst);
        Some(std::mem::replace(
            self.instances.get_mut(index as usize)?,
            instance,
        ))
    }

    /// Returns an immutable reference to all the instance data.
    #[inline]
    pub fn instances(&self) -> &[DrawParam] {
        &self.instances
    }

    /// Returns a mutable reference to all the instance data.
    #[inline]
    pub fn instances_mut(&mut self) -> &mut [DrawParam] {
        self.dirty.store(true, SeqCst);
        &mut self.instances
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        self.len.store(0, SeqCst);
        self.instances.clear();
    }

    /// Returns whether the instance data has been changed without [`InstanceArray::flush()`] being called.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        self.dirty.load(SeqCst)
    }

    /// Uploads the instance data to the GPU.
    ///
    /// You do not usually need to call this yourself as it is done automatically during drawing.
    pub fn flush(&mut self, gfx: &GraphicsContext) {
        self.flush_wgpu(&gfx.wgpu)
    }

    #[allow(unsafe_code)]
    pub(crate) fn flush_wgpu(&mut self, wgpu: &WgpuContext) {
        if !self.is_dirty() {
            return;
        } else {
            self.dirty.store(false, SeqCst);
        }

        let mut layers = BTreeMap::<_, Vec<_>>::new();
        let instances = self
            .instances
            .iter()
            .enumerate()
            .map(|(i, param)| {
                layers.entry(param.z).or_default().push(i as u32);
                DrawUniforms::from_param(
                    *param,
                    [self.image.width() as f32, self.image.height() as f32].into(),
                )
                .as_std140()
            })
            .collect::<Vec<_>>();

        let len = instances.len() as u32;
        if len > self.capacity {
            self.resize_impl(wgpu, len, false);
        }

        self.len.store(instances.len() as u32, SeqCst);
        wgpu.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                instances.as_ptr() as *const u8,
                instances.len() * DrawUniforms::std140_size_static(),
            )
        });

        let indices = layers.into_iter().flat_map(|(_, x)| x).collect::<Vec<_>>();
        wgpu.queue.write_buffer(&self.indices, 0, unsafe {
            std::slice::from_raw_parts(
                indices.as_ptr() as *const u8,
                indices.len() * std::mem::size_of::<u32>(),
            )
        });
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &GraphicsContext, new_capacity: u32) {
        self.resize_impl(&gfx.wgpu, new_capacity, true)
    }

    fn resize_impl(&mut self, wgpu: &WgpuContext, new_capacity: u32, copy: bool) {
        let len = self.len.load(SeqCst);
        let resized = InstanceArray::new_wgpu(wgpu, self.image.clone(), new_capacity);
        resized.len.store(new_capacity.min(len), SeqCst);

        if copy {
            let cmd = {
                let mut cmd = wgpu.device.create_command_encoder(&Default::default());
                cmd.copy_buffer_to_buffer(
                    &self.buffer,
                    0,
                    &resized.buffer,
                    0,
                    new_capacity.min(len) as u64 * DrawUniforms::std140_size_static() as u64,
                );
                cmd.finish()
            };
            wgpu.queue.submit([cmd]);
        }

        *self = resized;
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray].
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }

    #[inline]
    pub(crate) fn len(&self) -> usize {
        self.len.load(SeqCst) as usize
    }

    #[inline]
    pub(crate) fn is_empty(&self) -> bool {
        self.len.load(SeqCst) == 0
    }
}
<|endoftext|>