<commit_before>extern crate html5ever_dom_sink;
extern crate html5ever;
extern crate tendril;
extern crate regex;
extern crate hyper;
extern crate string_cache;
extern crate core;

use self::core::str::FromStr;

use self::tendril::Tendril;

use self::html5ever_dom_sink::common::{Document, Doctype, Text, Comment, Element};
use self::html5ever_dom_sink::rcdom::{RcDom, Handle};
use self::html5ever::{parse, one_input, Attribute};
use self::core::default::Default;
use std::io::Read;

use self::regex::Regex;
use self::hyper::Client;
use self::hyper::header::Connection;
use self::hyper::header::ConnectionOption;

use Provider;
use Track;

pub fn extract_tracks(url: &str) -> Vec<Track> {
    let client = Client::new();
    let mut res = client.get(url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let input: Tendril<_> = FromStr::from_str(&body).unwrap();
    let dom: RcDom = parse(one_input(input), Default::default());
    let mut tracks  = Vec::new();
    walk(0, dom.document, &mut tracks);
    return tracks
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize, handle: Handle, tracks: &mut Vec<Track>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, ref attrs) => {
            let tag_name = name.local.as_slice();
            match extract_track(tag_name, attrs) {
                Some(track) => {
                    if !(*tracks).contains(&track) {
                        (*tracks).push(track)
                    }
                },
                None => {}
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks);
    }
}

fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs.iter() {
        if attr.name.local.as_slice() == attr_name {
            return Some(attr.value.to_string())
        }
    }
    None
}

fn extract_identifier(value: &str, regex_str: &str) -> Option<String> {
    match Regex::new(regex_str) {
        Ok(re) => match re.captures(value) {
            Some(cap) => match cap.at(1) {
                Some(str) => {
                    let strs: Vec<&str> = str.split('?').collect();
                    return Some(strs[0].to_string())
                },
                None => None
            },
            None => None
        },
        Err(_) => None
    }
}

pub fn extract_track(tag_name: &str, attrs: &Vec<Attribute>) -> Option<Track> {
    if tag_name == "iframe" {
        match attr("src", attrs) {
            Some(ref src) => {
                match extract_identifier(&src, r"www.youtube.com/embed/([^\?&].+)") {
                    Some(identifier) => {
                        return Some(Track {
                                    id: 0,
                              provider: Provider::YouTube,
                                 title: "".to_string(),
                                   url: src.to_string(),
                            identifier: identifier
                        });
                    },
                    None => ()
                }
                match extract_identifier(&src, r"api.soundcloud.com/tracks/([^\?&]+)") {
                    Some(identifier) => {
                        return Some(Track {
                                    id: 0,
                              provider: Provider::SoundCloud,
                                 title: "".to_string(),
                                   url: src.to_string(),
                            identifier: identifier
                        });
                    },
                    None => ()
                }
            },
            None => ()
        }
    } else if tag_name == "a" {
        match attr("href", attrs) {
            Some(ref href) => {
                match extract_identifier(&href, r"www.youtube.com/watch\?v=([^\?&]+)") {
                    Some(identifier) => {
                        return Some(Track {
                                    id: 0,
                              provider: Provider::YouTube,
                                 title: "".to_string(),
                                   url: href.to_string(),
                            identifier: identifier
                        });
                    },
                    None => ()
                }
            },
            None => ()
        }
    }
    return None
}

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

    #[test]
    fn test_extract_identifier() {
        let soundcloud_src = "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/195425494&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true";
        match extract_identifier(soundcloud_src,
                                 r"api.soundcloud.com/tracks/([^\?&]+)") {
            Some(identifier) => assert_eq!(identifier,
                                           "195425494".to_string()),
            None             => assert!(false)
        }

        let youtube_src = "https://www.youtube.com/embed/X8tOngmlES0?rel=0";
        match extract_identifier(youtube_src,
                                 r"www.youtube.com/embed/([^\?&].+)") {
            Some(identifier) => assert_eq!(identifier,
                                           "X8tOngmlES0".to_string()),
            None             => assert!(false)
        }

        let youtube_href_src = "https://www.youtube.com/watch?v=oDuif301F-8";
        match extract_identifier(youtube_href_src,
                                 r"www.youtube.com/watch\?v=([^\?&]+)") {
            Some(identifier) => assert_eq!(identifier,
                                           "oDuif301F-8".to_string()),
            None             => assert!(false)
        }
    }
}
<commit_msg>Extract track from link tag<commit_after>extern crate html5ever_dom_sink;
extern crate html5ever;
extern crate tendril;
extern crate regex;
extern crate hyper;
extern crate string_cache;
extern crate core;

use self::core::str::FromStr;

use self::tendril::Tendril;

use self::html5ever_dom_sink::common::{Document, Doctype, Text, Comment, Element};
use self::html5ever_dom_sink::rcdom::{RcDom, Handle};
use self::html5ever::{parse, one_input, Attribute};
use self::core::default::Default;
use std::io::Read;

use self::regex::Regex;
use self::hyper::Client;
use self::hyper::header::Connection;
use self::hyper::header::ConnectionOption;

use Provider;
use Track;

pub fn extract_tracks(url: &str) -> Vec<Track> {
    let client = Client::new();
    let mut res = client.get(url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let input: Tendril<_> = FromStr::from_str(&body).unwrap();
    let dom: RcDom = parse(one_input(input), Default::default());
    let mut tracks  = Vec::new();
    walk(0, dom.document, &mut tracks);
    return tracks
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize, handle: Handle, tracks: &mut Vec<Track>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, ref attrs) => {
            let tag_name = name.local.as_slice();
            match extract_track(tag_name, attrs) {
                Some(track) => {
                    if !(*tracks).contains(&track) {
                        (*tracks).push(track)
                    }
                },
                None => {}
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks);
    }
}

fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs.iter() {
        if attr.name.local.as_slice() == attr_name {
            return Some(attr.value.to_string())
        }
    }
    None
}

fn extract_identifier(value: &str, regex_str: &str) -> Option<String> {
    match Regex::new(regex_str) {
        Ok(re) => match re.captures(value) {
            Some(cap) => match cap.at(1) {
                Some(str) => {
                    let strs: Vec<&str> = str.split('?').collect();
                    return Some(strs[0].to_string())
                },
                None => None
            },
            None => None
        },
        Err(_) => None
    }
}

pub fn extract_track(tag_name: &str, attrs: &Vec<Attribute>) -> Option<Track> {
    if tag_name == "iframe" {
        match attr("src", attrs) {
            Some(ref src) => {
                match extract_identifier(&src, r"www.youtube.com/embed/([^\?&].+)") {
                    Some(identifier) => {
                        return Some(Track {
                                    id: 0,
                              provider: Provider::YouTube,
                                 title: "".to_string(),
                                   url: src.to_string(),
                            identifier: identifier
                        });
                    },
                    None => ()
                }
                match extract_identifier(&src, r"api.soundcloud.com/tracks/([^\?&]+)") {
                    Some(identifier) => {
                        return Some(Track {
                                    id: 0,
                              provider: Provider::SoundCloud,
                                 title: "".to_string(),
                                   url: src.to_string(),
                            identifier: identifier
                        });
                    },
                    None => ()
                }
            },
            None => ()
        }
    } else if tag_name == "a" || tag_name == "link" {
        match attr("href", attrs) {
            Some(ref href) => {
                match extract_identifier(&href, r"www.youtube.com/watch\?v=([^\?&]+)") {
                    Some(identifier) => {
                        return Some(Track {
                                    id: 0,
                              provider: Provider::YouTube,
                                 title: "".to_string(),
                                   url: href.to_string(),
                            identifier: identifier
                        });
                    },
                    None => ()
                }
            },
            None => ()
        }
    }
    return None
}

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

    #[test]
    fn test_extract_identifier() {
        let soundcloud_src = "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/195425494&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true";
        match extract_identifier(soundcloud_src,
                                 r"api.soundcloud.com/tracks/([^\?&]+)") {
            Some(identifier) => assert_eq!(identifier,
                                           "195425494".to_string()),
            None             => assert!(false)
        }

        let youtube_src = "https://www.youtube.com/embed/X8tOngmlES0?rel=0";
        match extract_identifier(youtube_src,
                                 r"www.youtube.com/embed/([^\?&].+)") {
            Some(identifier) => assert_eq!(identifier,
                                           "X8tOngmlES0".to_string()),
            None             => assert!(false)
        }

        let youtube_href_src = "https://www.youtube.com/watch?v=oDuif301F-8";
        match extract_identifier(youtube_href_src,
                                 r"www.youtube.com/watch\?v=([^\?&]+)") {
            Some(identifier) => assert_eq!(identifier,
                                           "oDuif301F-8".to_string()),
            None             => assert!(false)
        }
    }
}
<|endoftext|>


<commit_before>pub mod torrent {
    pub use self::ver_249b1b as current;
    pub use self::current::Session;
    use bincode;

    pub fn load(data: &[u8]) -> Option<Session> {
        if let Ok(m) = bincode::deserialize::<ver_249b1b::Session>(data) {
            Some(m)
        } else if let Ok(m) = bincode::deserialize::<ver_5f166d::Session>(data) {
            info!("Migrating torrent session from v5f166d");
            Some(m.migrate())
        } else {
            None
        }
    }

    impl Session {
        pub fn migrate(self) -> Self {
            self
        }
    }

    pub mod ver_249b1b {
        use torrent::{Bitfield, Info};

        use chrono::{DateTime, Utc};

        #[derive(Serialize, Deserialize)]
        pub struct Session {
            pub info: Info,
            pub pieces: Bitfield,
            pub uploaded: u64,
            pub downloaded: u64,
            pub status: Status,
            pub path: Option<String>,
            pub priority: u8,
            pub priorities: Vec<u8>,
            pub created: DateTime<Utc>,
            pub throttle_ul: Option<i64>,
            pub throttle_dl: Option<i64>,
        }

        #[derive(Clone, Debug, Serialize, Deserialize)]
        pub struct Status {
            pub paused: bool,
            pub validating: bool,
            pub error: Option<String>,
            pub state: StatusState,
        }

        #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
        pub enum StatusState {
            Magnet,
            // Torrent has not acquired all pieces
            Incomplete,
            // Torrent has acquired all pieces, regardless of validity
            Complete,
        }
    }

    pub mod ver_5f166d {
        use super::ver_249b1b as next;

        use torrent::{Bitfield, Info};

        use chrono::{DateTime, Utc};

        #[derive(Serialize, Deserialize)]
        pub struct Session {
            pub info: Info,
            pub pieces: Bitfield,
            pub uploaded: u64,
            pub downloaded: u64,
            pub status: Status,
            pub path: Option<String>,
            pub wanted: Bitfield,
            pub priority: u8,
            pub priorities: Vec<u8>,
            pub created: DateTime<Utc>,
            pub throttle_ul: Option<i64>,
            pub throttle_dl: Option<i64>,
        }

        #[derive(Serialize, Deserialize)]
        pub enum Status {
            Pending,
            Paused,
            Leeching,
            Idle,
            Seeding,
            Validating,
            Magnet,
            DiskError,
        }

        impl Session {
            pub fn migrate(self) -> next::Session {
                let state = if self.pieces.complete() {
                    next::StatusState::Complete
                } else {
                    next::StatusState::Incomplete
                };
                let paused = match self.status {
                    Status::Paused => true,
                    _ => false,
                };
                next::Session {
                    info: self.info,
                    pieces: self.pieces,
                    uploaded: self.uploaded,
                    downloaded: self.downloaded,
                    status: next::Status {
                        paused,
                        state,
                        validating: false,
                        error: None,
                    },
                    path: self.path,
                    priority: self.priority,
                    priorities: self.priorities,
                    created: self.created,
                    throttle_ul: self.throttle_ul,
                    throttle_dl: self.throttle_dl,
                }.migrate()
            }
        }
    }
}
<commit_msg>Ensure old Info format is correct<commit_after>pub mod torrent {
    pub use self::ver_249b1b as current;
    pub use self::current::Session;
    use bincode;

    pub fn load(data: &[u8]) -> Option<Session> {
        if let Ok(m) = bincode::deserialize::<ver_249b1b::Session>(data) {
            Some(m)
        } else if let Ok(m) = bincode::deserialize::<ver_5f166d::Session>(data) {
            info!("Migrating torrent session from v5f166d");
            Some(m.migrate())
        } else {
            None
        }
    }

    impl Session {
        pub fn migrate(self) -> Self {
            self
        }
    }

    pub mod ver_249b1b {
        use torrent::{Bitfield, Info};

        use chrono::{DateTime, Utc};

        #[derive(Serialize, Deserialize)]
        pub struct Session {
            pub info: Info,
            pub pieces: Bitfield,
            pub uploaded: u64,
            pub downloaded: u64,
            pub status: Status,
            pub path: Option<String>,
            pub priority: u8,
            pub priorities: Vec<u8>,
            pub created: DateTime<Utc>,
            pub throttle_ul: Option<i64>,
            pub throttle_dl: Option<i64>,
        }

        #[derive(Clone, Debug, Serialize, Deserialize)]
        pub struct Status {
            pub paused: bool,
            pub validating: bool,
            pub error: Option<String>,
            pub state: StatusState,
        }

        #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
        pub enum StatusState {
            Magnet,
            // Torrent has not acquired all pieces
            Incomplete,
            // Torrent has acquired all pieces, regardless of validity
            Complete,
        }
    }

    pub mod ver_5f166d {
        use super::ver_249b1b as next;

        use torrent::{info, Info as TInfo, Bitfield};

        use chrono::{DateTime, Utc};
        use url::Url;

        #[derive(Serialize, Deserialize)]
        pub struct Session {
            pub info: Info,
            pub pieces: Bitfield,
            pub uploaded: u64,
            pub downloaded: u64,
            pub status: Status,
            pub path: Option<String>,
            pub wanted: Bitfield,
            pub priority: u8,
            pub priorities: Vec<u8>,
            pub created: DateTime<Utc>,
            pub throttle_ul: Option<i64>,
            pub throttle_dl: Option<i64>,
        }

        #[derive(Serialize, Deserialize)]
        pub enum Status {
            Pending,
            Paused,
            Leeching,
            Idle,
            Seeding,
            Validating,
            Magnet,
            DiskError,
        }

        #[derive(Serialize, Deserialize)]
        pub struct Info {
            pub name: String,
            pub announce: Option<String>,
            pub piece_len: u32,
            pub total_len: u64,
            pub hashes: Vec<Vec<u8>>,
            pub hash: [u8; 20],
            pub files: Vec<info::File>,
            pub private: bool,
            pub be_name: Option<Vec<u8>>,
        }

        impl Session {
            pub fn migrate(self) -> next::Session {
                let state = if self.pieces.complete() {
                    next::StatusState::Complete
                } else {
                    next::StatusState::Incomplete
                };
                let paused = match self.status {
                    Status::Paused => true,
                    _ => false,
                };
                let piece_idx = TInfo::generate_piece_idx(
                    self.info.hashes.len(),
                    self.info.piece_len as u64,
                    &self.info.files,
                );
                next::Session {
                    info: TInfo {
                        name: self.info.name,
                        announce: self.info.announce.and_then(|url| Url::parse(&url).ok()),
                        piece_len: self.info.piece_len,
                        total_len: self.info.total_len,
                        hashes: self.info.hashes,
                        hash: self.info.hash,
                        files: self.info.files,
                        private: self.info.private,
                        be_name: self.info.be_name,
                        piece_idx,
                    },
                    pieces: self.pieces,
                    uploaded: self.uploaded,
                    downloaded: self.downloaded,
                    status: next::Status {
                        paused,
                        state,
                        validating: false,
                        error: None,
                    },
                    path: self.path,
                    priority: self.priority,
                    priorities: self.priorities,
                    created: self.created,
                    throttle_ul: self.throttle_ul,
                    throttle_dl: self.throttle_dl,
                }.migrate()
            }
        }
    }
}
<|endoftext|>


<commit_before>//! A library for handling signals in UNIX-like environments.
//!
//! Using this library it is possible to subscribe and unsubscribe from signals and to
//! handle them asynchronously.
//!
//! # Example
//!
//! ```rust
//! let signals = Signals::new().unwrap();
//! signals.subscribe(Interrupt);
//! for s in signals.receiver().iter() {
//!     println!("{:?}", s);
//! }
//! ```
//!
//! At any given time there can only be one signal handler in the program.
//! `Signals::new()` returns `None` if there is already another signal handler.

#![crate_id = "signals#0.1.0"]
#![crate_type = "lib"]
#![license = "MIT"]

extern crate libc;

use self::libc::{c_int};
use std::sync::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};
use std::mem::{forget, transmute};

static mut ALIVE: AtomicBool = INIT_ATOMIC_BOOL;
static mut INITIALIZED: AtomicBool = INIT_ATOMIC_BOOL;
static mut SND: *Sender<Signal> = 0 as *Sender<Signal>;
static mut RCV: *Receiver<Signal> = 0 as *Receiver<Signal>;

extern {
    fn signal(signum: c_int, hdlr: Option<unsafe extern fn(c_int)>);
}

unsafe extern fn handler(num: c_int) {
    if !ALIVE.load(Relaxed) || !INITIALIZED.load(Relaxed) {
        return;
    }
    let snd: &Sender<Signal> = transmute(SND);
    match num {
        _ if num == Abort     as c_int => snd.send(Abort),
        _ if num == Alarm     as c_int => snd.send(Alarm),
        _ if num == Bus       as c_int => snd.send(Bus),
        _ if num == Child     as c_int => snd.send(Child),
        _ if num == Continue  as c_int => snd.send(Continue),
        _ if num == FPE       as c_int => snd.send(FPE),
        _ if num == Hangup    as c_int => snd.send(Hangup),
        _ if num == Illegal   as c_int => snd.send(Illegal),
        _ if num == Interrupt as c_int => snd.send(Interrupt),
        _ if num == Kill      as c_int => snd.send(Kill),
        _ if num == Pipe      as c_int => snd.send(Pipe),
        _ if num == Quit      as c_int => snd.send(Quit),
        _ if num == Poll      as c_int => snd.send(Poll),
        _ if num == Prof      as c_int => snd.send(Prof),
        _ if num == Segfault  as c_int => snd.send(Segfault),
        _ if num == Stop      as c_int => snd.send(Stop),
        _ if num == TermStop  as c_int => snd.send(TermStop),
        _ if num == Sys       as c_int => snd.send(Sys),
        _ if num == Terminate as c_int => snd.send(Terminate),
        _ if num == Trap      as c_int => snd.send(Trap),
        _ if num == TTIN      as c_int => snd.send(TTIN),
        _ if num == TTOU      as c_int => snd.send(TTOU),
        _ if num == Urgent    as c_int => snd.send(Urgent),
        _ if num == User1     as c_int => snd.send(User1),
        _ if num == User2     as c_int => snd.send(User2),
        _ if num == WinSize   as c_int => snd.send(WinSize),
        _ if num == XCPU      as c_int => snd.send(XCPU),
        _ if num == XFSZ      as c_int => snd.send(XFSZ),
        _ => { },
    }
}

/// Available signals.
pub enum Signal {
    /// Process abort signal
    Abort     = 6,
    /// Alarm clock
    Alarm     = 14,
    /// Access to an undefined portion of a memory object
    Bus       = 10,
    /// Child process terminated, stopped,
    Child     = 18,
    /// Continue executing, if stopped.
    Continue  = 25,
    /// Erroneous arithmetic operation.
    FPE       = 8,
    /// Hangup.
    Hangup    = 1,
    /// Illegal instruction.
    Illegal   = 4,
    /// Terminal interrupt signal.
    Interrupt = 2,
    /// Kill (cannot be caught or ignored).
    Kill      = 9,
    /// Abnormal termination of the process	Write on a pipe with no one to read it.
    Pipe      = 13,
    /// Abnormal termination of the process	Terminal quit signal.
    Quit      = 3,
    /// Pollable event.
    Poll      = 22,
    /// Profiling timer expired.
    Prof      = 29,
    /// Invalid memory reference.
    Segfault  = 11,
    /// Stop executing (cannot be caught or ignored).
    Stop      = 23,
    /// Terminal stop signal.
    TermStop  = 20,
    /// Bad system call.
    Sys       = 12,
    /// Termination signal.
    Terminate = 15,
    /// Trace/breakpoint trap.
    Trap      = 5,
    /// Background process attempting read.
    TTIN      = 26,
    /// Background process attempting write.
    TTOU      = 27,
    /// High bandwidth data is available at a socket.
    Urgent    = 21,
    /// User-defined signal 1.
    User1     = 16,
    /// User-defined signal 2.
    User2     = 17,
    /// Window resized.
    WinSize   = 28,
    /// CPU time limit exceeded.
    XCPU      = 30,
    /// File size limit exceeded.
    XFSZ      = 31,
}

/// Signal handler
pub struct Signals {
    _unit: (),
}

impl Signals {
    /// Create a new signal handler
    ///
    /// Returns `None` if there is already another signal handler in the program.
    pub fn new() -> Option<Signals> {
        unsafe {
            if ALIVE.compare_and_swap(false, true, Relaxed) {
                return None;
            }
            if !INITIALIZED.compare_and_swap(false, true, Relaxed) {
                let (s, r) = channel();
                let s = box s;
                let r = box r;
                SND = &*s as *_;
                RCV = &*r as *_;
                forget(s);
                forget(r);
            }
            Some(Signals { _unit: () })
        }
    }

    /// Subscribe to a signal.
    ///
    /// Note: Dropping the signal handler doesn't automatically unsubscribe.
    /// To return to the default behavior, one has to explicitly call `unsubscribe`.
    pub fn subscribe(&self, sig: Signal) {
        unsafe { signal(sig as c_int, Some(handler)); }
    }

    /// Unsubscribe from a signal.
    pub fn unsubscribe(&self, sig: Signal) {
        unsafe { signal(sig as c_int, None); }
    }

    /// Create a non-blocking iterator over all received signals.
    pub fn iter<'a>(&'a self) -> SignalIter<'a> {
        SignalIter { _unit: () }
    }

    /// Return a reference to the internal `Receiver`.
    pub fn receiver<'a>(&'a self) -> &'a Receiver<Signal> {
        unsafe { transmute(RCV) }
    }
}

impl Drop for Signals {
    fn drop(&mut self) {
        unsafe { ALIVE.store(false, Relaxed); }
    }
}

/// Non-blocking iterator over the available signals.
pub struct SignalIter<'a> {
    _unit: (),
}

impl<'a> Iterator<Signal> for SignalIter<'a> {
    fn next(&mut self) -> Option<Signal> {
        let rcv: &Receiver<Signal> = unsafe { transmute(RCV) };
        match rcv.try_recv() {
            Ok(v) => Some(v),
            _ => None,
        }
    }
}
<commit_msg>switch to Once<commit_after>//! A library for handling signals in UNIX-like environments.
//!
//! Using this library it is possible to subscribe and unsubscribe from signals and to
//! handle them asynchronously.
//!
//! # Example
//!
//! ```rust
//! let signals = Signals::new().unwrap();
//! signals.subscribe(Interrupt);
//! for s in signals.receiver().iter() {
//!     println!("{:?}", s);
//! }
//! ```
//!
//! At any given time there can only be one signal handler in the program.
//! `Signals::new()` returns `None` if there is already another signal handler.

#![crate_id = "signals#0.1.0"]
#![crate_type = "lib"]
#![license = "MIT"]

extern crate libc;

use self::libc::{c_int};
use std::sync::{Once, ONCE_INIT};
use std::sync::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};
use std::mem::{forget, transmute};

static mut ALIVE: AtomicBool = INIT_ATOMIC_BOOL;
static mut INITIALIZED: Once = ONCE_INIT;
static mut SND: *Sender<Signal> = 0 as *Sender<Signal>;
static mut RCV: *Receiver<Signal> = 0 as *Receiver<Signal>;

extern {
    fn signal(signum: c_int, hdlr: Option<unsafe extern fn(c_int)>);
}

unsafe extern fn handler(num: c_int) {
    if !ALIVE.load(Relaxed) {
        return;
    }
    let snd: &Sender<Signal> = transmute(SND);
    match num {
        _ if num == Abort     as c_int => snd.send(Abort),
        _ if num == Alarm     as c_int => snd.send(Alarm),
        _ if num == Bus       as c_int => snd.send(Bus),
        _ if num == Child     as c_int => snd.send(Child),
        _ if num == Continue  as c_int => snd.send(Continue),
        _ if num == FPE       as c_int => snd.send(FPE),
        _ if num == Hangup    as c_int => snd.send(Hangup),
        _ if num == Illegal   as c_int => snd.send(Illegal),
        _ if num == Interrupt as c_int => snd.send(Interrupt),
        _ if num == Kill      as c_int => snd.send(Kill),
        _ if num == Pipe      as c_int => snd.send(Pipe),
        _ if num == Quit      as c_int => snd.send(Quit),
        _ if num == Poll      as c_int => snd.send(Poll),
        _ if num == Prof      as c_int => snd.send(Prof),
        _ if num == Segfault  as c_int => snd.send(Segfault),
        _ if num == Stop      as c_int => snd.send(Stop),
        _ if num == TermStop  as c_int => snd.send(TermStop),
        _ if num == Sys       as c_int => snd.send(Sys),
        _ if num == Terminate as c_int => snd.send(Terminate),
        _ if num == Trap      as c_int => snd.send(Trap),
        _ if num == TTIN      as c_int => snd.send(TTIN),
        _ if num == TTOU      as c_int => snd.send(TTOU),
        _ if num == Urgent    as c_int => snd.send(Urgent),
        _ if num == User1     as c_int => snd.send(User1),
        _ if num == User2     as c_int => snd.send(User2),
        _ if num == WinSize   as c_int => snd.send(WinSize),
        _ if num == XCPU      as c_int => snd.send(XCPU),
        _ if num == XFSZ      as c_int => snd.send(XFSZ),
        _ => { },
    }
}

/// Available signals.
pub enum Signal {
    /// Process abort signal
    Abort     = 6,
    /// Alarm clock
    Alarm     = 14,
    /// Access to an undefined portion of a memory object
    Bus       = 10,
    /// Child process terminated, stopped,
    Child     = 18,
    /// Continue executing, if stopped.
    Continue  = 25,
    /// Erroneous arithmetic operation.
    FPE       = 8,
    /// Hangup.
    Hangup    = 1,
    /// Illegal instruction.
    Illegal   = 4,
    /// Terminal interrupt signal.
    Interrupt = 2,
    /// Kill (cannot be caught or ignored).
    Kill      = 9,
    /// Abnormal termination of the process	Write on a pipe with no one to read it.
    Pipe      = 13,
    /// Abnormal termination of the process	Terminal quit signal.
    Quit      = 3,
    /// Pollable event.
    Poll      = 22,
    /// Profiling timer expired.
    Prof      = 29,
    /// Invalid memory reference.
    Segfault  = 11,
    /// Stop executing (cannot be caught or ignored).
    Stop      = 23,
    /// Terminal stop signal.
    TermStop  = 20,
    /// Bad system call.
    Sys       = 12,
    /// Termination signal.
    Terminate = 15,
    /// Trace/breakpoint trap.
    Trap      = 5,
    /// Background process attempting read.
    TTIN      = 26,
    /// Background process attempting write.
    TTOU      = 27,
    /// High bandwidth data is available at a socket.
    Urgent    = 21,
    /// User-defined signal 1.
    User1     = 16,
    /// User-defined signal 2.
    User2     = 17,
    /// Window resized.
    WinSize   = 28,
    /// CPU time limit exceeded.
    XCPU      = 30,
    /// File size limit exceeded.
    XFSZ      = 31,
}

/// Signal handler
pub struct Signals {
    _unit: (),
}

impl Signals {
    /// Create a new signal handler
    ///
    /// Returns `None` if there is already another signal handler in the program.
    pub fn new() -> Option<Signals> {
        unsafe {
            INITIALIZED.doit(|| {
                let (s, r) = channel();
                let s = box s;
                let r = box r;
                SND = &*s as *_;
                RCV = &*r as *_;
                forget(s);
                forget(r);
            });
            if ALIVE.compare_and_swap(false, true, Relaxed) {
                return None;
            }
            Some(Signals { _unit: () })
        }
    }

    /// Subscribe to a signal.
    ///
    /// Note: Dropping the signal handler doesn't automatically unsubscribe.
    /// To return to the default behavior, one has to explicitly call `unsubscribe`.
    pub fn subscribe(&self, sig: Signal) {
        unsafe { signal(sig as c_int, Some(handler)); }
    }

    /// Unsubscribe from a signal.
    pub fn unsubscribe(&self, sig: Signal) {
        unsafe { signal(sig as c_int, None); }
    }

    /// Create a non-blocking iterator over all received signals.
    pub fn iter<'a>(&'a self) -> SignalIter<'a> {
        SignalIter { _unit: () }
    }

    /// Return a reference to the internal `Receiver`.
    pub fn receiver<'a>(&'a self) -> &'a Receiver<Signal> {
        unsafe { transmute(RCV) }
    }
}

impl Drop for Signals {
    fn drop(&mut self) {
        unsafe { ALIVE.store(false, Relaxed); }
    }
}

/// Non-blocking iterator over the available signals.
pub struct SignalIter<'a> {
    _unit: (),
}

impl<'a> Iterator<Signal> for SignalIter<'a> {
    fn next(&mut self) -> Option<Signal> {
        let rcv: &Receiver<Signal> = unsafe { transmute(RCV) };
        match rcv.try_recv() {
            Ok(v) => Some(v),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Summarizer {
    data: Vec<f64>,
}

impl Summarizer {
    /// Construct a `Summarizer` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Option<Self> {
        if data.len() == 0 {
            return None;
        }

        if data.iter().any(|x| !x.is_finite()) {
            return None;
        }

        let mut data = Vec::from(data);

        // Won't panic: we have checked that each float is finite.
        data.sort_by(|a, b| a.partial_cmp(b).unwrap());

        let s = Summarizer { data };

        Some(s)
    }

    pub fn as_slice(&self) -> &[f64] {
        self.data.as_slice()
    }

    pub fn size(&self) -> f64 {
        self.data.len() as f64
    }

    pub fn min(&self) -> f64 {
        self.data[0]
    }

    pub fn max(&self) -> f64 {
        self.data[self.data.len() - 1]
    }

    pub fn mean(&self) -> f64 {
        let t: f64 = self.data.iter().sum();

        t / self.size()
    }

    pub fn median(&self) -> f64 {
        let d = &self.data;
        let n = d.len();

        if n % 2 == 0 {
            (d[(n / 2) - 1] + d[n / 2]) / 2.0
        } else {
            d[(n - 1) / 2]
        }
    }

    /// Closest-ranks percentile computed via linear interpolation.
    /// See: http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm
    pub fn percentile(&self, p: f64) -> Option<f64> {
        if !p.is_finite() { return None; }
        if p < 0.0 { return None; }
        if p >= 1.0 { return None; }

        let rank = (self.size() - 1.0) * p;
        let frac = rank.fract();

        let i = rank.floor() as usize;
        let j = i + 1;

        let xi = self.data[i];
        let xj = self.data[j];
        let x = xi + frac * (xj - xi);

        Some(x)
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        let m = self.mean();
        let sum_sq_diff: f64 = self.data
            .iter()
            .map(|x| (x - m).powi(2))
            .sum();

        (1.0 / (self.size() - 1.0)) * sum_sq_diff
    }

    pub fn standard_deviation(&self) -> f64 {
        self.unbiased_variance().sqrt()
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_deviation() / self.size().sqrt()
    }
}

#[derive(Debug)]
pub struct Summary {
    len: usize,
    lower_quartile: f64,
    min: f64,
    max: f64,
    mean: f64,
    median: f64,
    standard_deviation: f64,
    standard_error: f64,
    unbiased_variance: f64,
    upper_quartile: f64,
}

impl Summary {
    /// Construct a `Summary` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Option<Self> {
        Summarizer::new(data).map(|s| Summary {
            len: s.data.len(),
            lower_quartile: s.percentile(0.25).unwrap(),
            min: s.min(),
            max: s.max(),
            mean: s.mean(),
            median: s.median(),
            upper_quartile: s.percentile(0.75).unwrap(),
            unbiased_variance: s.unbiased_variance(),
            standard_deviation: s.standard_deviation(),
            standard_error: s.standard_error(),
        })
    }

    pub fn size(&self) -> f64 {
        self.len as f64
    }

    pub fn lower_quartile(&self) -> f64 {
        self.lower_quartile
    }

    pub fn min(&self) -> f64 {
        self.min
    }

    pub fn max(&self) -> f64 {
        self.max
    }

    pub fn mean(&self) -> f64 {
        self.mean
    }

    pub fn median(&self) -> f64 {
        self.median
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        self.unbiased_variance
    }

    pub fn upper_quartile(&self) -> f64 {
        self.upper_quartile
    }

    pub fn standard_deviation(&self) -> f64 {
        self.standard_deviation
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_error
    }
}
<commit_msg>Use custom error in `summary` module<commit_after>use error::Error;

#[derive(Debug)]
pub struct Summarizer {
    data: Vec<f64>,
}

impl Summarizer {
    /// Construct a `Summarizer` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        if data.len() == 0 {
            return Err(Error::EmptySample);
        }

        if data.iter().any(|x| !x.is_finite()) {
            return Err(Error::BadSample);
        }

        let mut data = Vec::from(data);

        // Won't panic: we have checked that each float is finite.
        data.sort_by(|a, b| a.partial_cmp(b).unwrap());

        let s = Summarizer { data };

        Ok(s)
    }

    pub fn as_slice(&self) -> &[f64] {
        self.data.as_slice()
    }

    pub fn size(&self) -> f64 {
        self.data.len() as f64
    }

    pub fn min(&self) -> f64 {
        self.data[0]
    }

    pub fn max(&self) -> f64 {
        self.data[self.data.len() - 1]
    }

    pub fn mean(&self) -> f64 {
        let t: f64 = self.data.iter().sum();

        t / self.size()
    }

    pub fn median(&self) -> f64 {
        let d = &self.data;
        let n = d.len();

        if n % 2 == 0 {
            (d[(n / 2) - 1] + d[n / 2]) / 2.0
        } else {
            d[(n - 1) / 2]
        }
    }

    /// Closest-ranks percentile computed via linear interpolation.
    /// See: http://www.itl.nist.gov/div898/handbook/prc/section2/prc262.htm
    pub fn percentile(&self, p: f64) -> Option<f64> {
        if !p.is_finite() { return None; }
        if p < 0.0 { return None; }
        if p >= 1.0 { return None; }

        let rank = (self.size() - 1.0) * p;
        let frac = rank.fract();

        let i = rank.floor() as usize;
        let j = i + 1;

        let xi = self.data[i];
        let xj = self.data[j];
        let x = xi + frac * (xj - xi);

        Some(x)
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        let m = self.mean();
        let sum_sq_diff: f64 = self.data
            .iter()
            .map(|x| (x - m).powi(2))
            .sum();

        (1.0 / (self.size() - 1.0)) * sum_sq_diff
    }

    pub fn standard_deviation(&self) -> f64 {
        self.unbiased_variance().sqrt()
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_deviation() / self.size().sqrt()
    }
}

#[derive(Debug)]
pub struct Summary {
    len: usize,
    lower_quartile: f64,
    min: f64,
    max: f64,
    mean: f64,
    median: f64,
    standard_deviation: f64,
    standard_error: f64,
    unbiased_variance: f64,
    upper_quartile: f64,
}

impl Summary {
    /// Construct a `Summary` from a slice of 64-bit floating point numbers.
    ///
    /// This constructor is partial, and we obtain the following guarantees
    /// about the resulting sample data:
    ///
    ///   - The sample size is positive
    ///   - All values are finite
    ///   - The data are sorted
    ///
    pub fn new(data: &[f64]) -> Result<Self, Error> {
        Summarizer::new(data).map(|s| Summary {
            len: s.data.len(),
            lower_quartile: s.percentile(0.25).unwrap(),
            min: s.min(),
            max: s.max(),
            mean: s.mean(),
            median: s.median(),
            upper_quartile: s.percentile(0.75).unwrap(),
            unbiased_variance: s.unbiased_variance(),
            standard_deviation: s.standard_deviation(),
            standard_error: s.standard_error(),
        })
    }

    pub fn size(&self) -> f64 {
        self.len as f64
    }

    pub fn lower_quartile(&self) -> f64 {
        self.lower_quartile
    }

    pub fn min(&self) -> f64 {
        self.min
    }

    pub fn max(&self) -> f64 {
        self.max
    }

    pub fn mean(&self) -> f64 {
        self.mean
    }

    pub fn median(&self) -> f64 {
        self.median
    }

    /// Uses Bessel's correction to estimate population variance.
    pub fn unbiased_variance(&self) -> f64 {
        self.unbiased_variance
    }

    pub fn upper_quartile(&self) -> f64 {
        self.upper_quartile
    }

    pub fn standard_deviation(&self) -> f64 {
        self.standard_deviation
    }

    pub fn standard_error(&self) -> f64 {
        self.standard_error
    }
}
<|endoftext|>


<commit_before>use crate::compiler::Code;
use crate::driver::cmd::AsmSyntax;
use crate::ty::TypeList;
use crate::vm::{Fct, VM};

pub fn supported() -> bool {
    false
}

pub fn disassemble(
    _vm: &VM,
    _fct: &Fct,
    _type_params: &TypeList,
    _code: &Code,
    _asm_syntax: AsmSyntax,
) {
    unreachable!();
}
<commit_msg>fix build without disassembler<commit_after>use crate::compiler::Code;
use crate::driver::cmd::AsmSyntax;
use crate::ty::SourceTypeArray;
use crate::vm::{Fct, VM};

pub fn supported() -> bool {
    false
}

pub fn disassemble(
    _vm: &VM,
    _fct: &Fct,
    _type_params: &SourceTypeArray,
    _code: &Code,
    _asm_syntax: AsmSyntax,
) {
    unreachable!();
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::frame::*;
use crate::tiling::*;
use crate::util::*;
use itertools::izip;
use rust_hawktracer::*;

#[derive(Debug, Default, Clone)]
pub struct ActivityMask {
  variances: Vec<u32>,
  // Width and height of the original frame that is masked
  width: usize,
  height: usize,
  // Side of unit (square) activity block in log2
  granularity: usize,
}

impl ActivityMask {
  #[hawktracer(activity_mask_from_plane)]
  pub fn from_plane<T: Pixel>(luma_plane: &Plane<T>) -> ActivityMask {
    let PlaneConfig { width, height, .. } = luma_plane.cfg;

    let granularity = 3;

    let aligned_luma = Rect {
      x: 0_isize,
      y: 0_isize,
      width: (width >> granularity) << granularity,
      height: (height >> granularity) << granularity,
    };
    let luma = PlaneRegion::new(luma_plane, aligned_luma);

    let mut variances =
      Vec::with_capacity((height >> granularity) * (width >> granularity));

    for y in 0..height >> granularity {
      for x in 0..width >> granularity {
        let block_rect = Area::Rect {
          x: (x << granularity) as isize,
          y: (y << granularity) as isize,
          width: 8,
          height: 8,
        };

        let block = luma.subregion(block_rect);
        let variance = variance_8x8(&block);
        variances.push(variance);
      }
    }
    ActivityMask { variances, width, height, granularity }
  }
}

// Adapted from the source variance calculation in cdef_dist_wxh_8x8.
#[inline(never)]
fn variance_8x8<T: Pixel>(src: &PlaneRegion<'_, T>) -> u32 {
  debug_assert!(src.plane_cfg.xdec == 0);
  debug_assert!(src.plane_cfg.ydec == 0);

  // Sum into columns to improve auto-vectorization
  let mut sum_s_cols: [u16; 8] = [0; 8];
  let mut sum_s2_cols: [u32; 8] = [0; 8];

  // Check upfront that 8 rows are available.
  let _row = &src[7];

  for j in 0..8 {
    let row = &src[j][0..8];
    for (sum_s, sum_s2, s) in izip!(&mut sum_s_cols, &mut sum_s2_cols, row) {
      // Don't convert directly to u32 to allow better vectorization
      let s: u16 = u16::cast_from(*s);
      *sum_s += s;

      // Convert to u32 to avoid overflows when multiplying
      let s: u32 = s as u32;
      *sum_s2 += s * s;
    }
  }

  // Sum together the sum of columns
  let sum_s = sum_s_cols.iter().map(|&a| u32::cast_from(a)).sum::<u32>();
  let sum_s2 = sum_s2_cols.iter().sum::<u32>();

  // Use sums to calculate variance
  sum_s2 - ((sum_s * sum_s + 32) >> 6)
}
<commit_msg>Store ActivityMask with (w_in_imp_b, h_in_imp_b) dimensions<commit_after>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use crate::frame::*;
use crate::tiling::*;
use crate::util::*;
use itertools::izip;
use rust_hawktracer::*;

#[derive(Debug, Default, Clone)]
pub struct ActivityMask {
  variances: Box<[u32]>,
  // Width and height of the original frame that is masked
  width: usize,
  height: usize,
}

impl ActivityMask {
  #[hawktracer(activity_mask_from_plane)]
  pub fn from_plane<T: Pixel>(luma_plane: &Plane<T>) -> ActivityMask {
    let PlaneConfig { width, height, .. } = luma_plane.cfg;

    // Width and height are padded to 8×8 block size.
    let w_in_imp_b = width.align_power_of_two_and_shift(3);
    let h_in_imp_b = height.align_power_of_two_and_shift(3);

    let aligned_luma = Rect {
      x: 0_isize,
      y: 0_isize,
      width: w_in_imp_b << 3,
      height: h_in_imp_b << 3,
    };
    let luma = PlaneRegion::new(luma_plane, aligned_luma);

    let mut variances = Vec::with_capacity(w_in_imp_b * h_in_imp_b);

    for y in 0..h_in_imp_b {
      for x in 0..w_in_imp_b {
        let block_rect = Area::Rect {
          x: (x << 3) as isize,
          y: (y << 3) as isize,
          width: 8,
          height: 8,
        };

        let block = luma.subregion(block_rect);
        let variance = variance_8x8(&block);
        variances.push(variance);
      }
    }
    ActivityMask { variances: variances.into_boxed_slice(), width, height }
  }
}

// Adapted from the source variance calculation in cdef_dist_wxh_8x8.
#[inline(never)]
fn variance_8x8<T: Pixel>(src: &PlaneRegion<'_, T>) -> u32 {
  debug_assert!(src.plane_cfg.xdec == 0);
  debug_assert!(src.plane_cfg.ydec == 0);

  // Sum into columns to improve auto-vectorization
  let mut sum_s_cols: [u16; 8] = [0; 8];
  let mut sum_s2_cols: [u32; 8] = [0; 8];

  // Check upfront that 8 rows are available.
  let _row = &src[7];

  for j in 0..8 {
    let row = &src[j][0..8];
    for (sum_s, sum_s2, s) in izip!(&mut sum_s_cols, &mut sum_s2_cols, row) {
      // Don't convert directly to u32 to allow better vectorization
      let s: u16 = u16::cast_from(*s);
      *sum_s += s;

      // Convert to u32 to avoid overflows when multiplying
      let s: u32 = s as u32;
      *sum_s2 += s * s;
    }
  }

  // Sum together the sum of columns
  let sum_s = sum_s_cols.iter().map(|&a| u32::cast_from(a)).sum::<u32>();
  let sum_s2 = sum_s2_cols.iter().sum::<u32>();

  // Use sums to calculate variance
  sum_s2 - ((sum_s * sum_s + 32) >> 6)
}
<|endoftext|>


<commit_before>use rand::Rng;

pub struct Faker;

pub trait Dummy<T>: Sized {
    fn dummy(config: &T) -> Self {
        let mut r = rand::thread_rng();
        Dummy::<T>::dummy_with_rng(config, &mut r)
    }

    fn dummy_with_rng<R: Rng + ?Sized>(config: &T, rng: &mut R) -> Self;
}

mod private {
    pub trait FakeBase<T>: Sized {
        fn _fake(&self) -> T;
        fn _fake_with_rng<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> T;
    }

    impl<T, U> FakeBase<U> for T
    where
        U: crate::Dummy<T>,
    {
        fn _fake(&self) -> U {
            U::dummy(self)
        }

        fn _fake_with_rng<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> U {
            U::dummy_with_rng(self, rng)
        }
    }
}

pub trait Fake: Sized {
    #[inline]
    fn fake<U>(&self) -> U
    where
        Self: private::FakeBase<U>,
    {
        self._fake()
    }

    #[inline]
    fn fake_with_rng<U, R: Rng + ?Sized>(&self, rng: &mut R) -> U
    where
        Self: private::FakeBase<U>,
    {
        self._fake_with_rng(rng)
    }
}
impl<T> Fake for T {}

#[macro_use]
mod impls;
pub use impls::std::result::ResultFaker;
pub use impls::std::string::StringFaker;

pub mod faker;
pub mod locales;

#[cfg(feature = "derive")]
pub use dummy::Dummy;
<commit_msg>export PathFaker<commit_after>use rand::Rng;

pub struct Faker;

pub trait Dummy<T>: Sized {
    fn dummy(config: &T) -> Self {
        let mut r = rand::thread_rng();
        Dummy::<T>::dummy_with_rng(config, &mut r)
    }

    fn dummy_with_rng<R: Rng + ?Sized>(config: &T, rng: &mut R) -> Self;
}

mod private {
    pub trait FakeBase<T>: Sized {
        fn _fake(&self) -> T;
        fn _fake_with_rng<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> T;
    }

    impl<T, U> FakeBase<U> for T
    where
        U: crate::Dummy<T>,
    {
        fn _fake(&self) -> U {
            U::dummy(self)
        }

        fn _fake_with_rng<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> U {
            U::dummy_with_rng(self, rng)
        }
    }
}

pub trait Fake: Sized {
    #[inline]
    fn fake<U>(&self) -> U
    where
        Self: private::FakeBase<U>,
    {
        self._fake()
    }

    #[inline]
    fn fake_with_rng<U, R: Rng + ?Sized>(&self, rng: &mut R) -> U
    where
        Self: private::FakeBase<U>,
    {
        self._fake_with_rng(rng)
    }
}
impl<T> Fake for T {}

#[macro_use]
mod impls;
pub use impls::std::result::ResultFaker;
pub use impls::std::string::StringFaker;
pub use impls::std::path::PathFaker;

pub mod faker;
pub mod locales;

#[cfg(feature = "derive")]
pub use dummy::Dummy;
<|endoftext|>


<commit_before>// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Data-driven tests

use serde_json::Value;
use std::str::FromStr;
use url::{quirks, Url};

fn check_invariants(url: &Url, name: &str, comment: Option<&str>) -> bool {
    let mut passed = true;
    if let Err(e) = url.check_invariants() {
        passed = false;
        eprint_failure(
            format!("  failed: invariants checked -> {:?}", e),
            name,
            comment,
        );
    }

    #[cfg(feature = "serde")]
    {
        let bytes = serde_json::to_vec(url).unwrap();
        let new_url: Url = serde_json::from_slice(&bytes).unwrap();
        passed &= test_eq(url, &new_url, name, comment);
    }

    passed
}

trait JsonExt {
    fn take_key(&mut self, key: &str) -> Option<Value>;
    fn string(self) -> String;
    fn take_string(&mut self, key: &str) -> String;
}

impl JsonExt for Value {
    fn take_key(&mut self, key: &str) -> Option<Value> {
        self.as_object_mut().unwrap().remove(key)
    }

    fn string(self) -> String {
        if let Value::String(s) = self {
            s
        } else {
            panic!("Not a Value::String")
        }
    }

    fn take_string(&mut self, key: &str) -> String {
        self.take_key(key).unwrap().string()
    }
}

#[test]
fn urltestdata() {
    // Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
    let mut json = Value::from_str(include_str!("urltestdata.json"))
        .expect("JSON parse error in urltestdata.json");
    let mut passed = true;
    for entry in json.as_array_mut().unwrap() {
        if entry.is_string() {
            continue; // ignore comments
        }
        let base = entry.take_string("base");
        let input = entry.take_string("input");
        let failure = entry.take_key("failure").is_some();

        let base = match Url::parse(&base) {
            Ok(base) => base,
            Err(_) if failure => continue,
            Err(message) => {
                eprint_failure(
                    format!("  failed: error parsing base {:?}: {}", base, message),
                    &format!("parse base for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        let url = match (base.join(&input), failure) {
            (Ok(url), false) => url,
            (Err(_), true) => continue,
            (Err(message), false) => {
                eprint_failure(
                    format!("  failed: {}", message),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
            (Ok(_), true) => {
                eprint_failure(
                    format!("  failed: expected parse error for URL {:?}", input),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        passed &= check_invariants(&url, &format!("invariants for {:?}", input), None);

        for &attr in ATTRIBS {
            passed &= test_eq_eprint(
                entry.take_string(attr),
                get(&url, attr),
                &format!("{:?} - {}", input, attr),
                None,
            );
        }

        if let Some(expected_origin) = entry.take_key("origin").map(|s| s.string()) {
            passed &= test_eq_eprint(
                expected_origin,
                &quirks::origin(&url),
                &format!("origin for {:?}", input),
                None,
            );
        }
    }

    assert!(passed)
}

#[test]
fn setters_tests() {
    let mut json = Value::from_str(include_str!("setters_tests.json"))
        .expect("JSON parse error in setters_tests.json");

    let mut passed = true;
    for &attr in ATTRIBS {
        if attr == "href" {
            continue;
        }

        let mut tests = json.take_key(attr).unwrap();
        for mut test in tests.as_array_mut().unwrap().drain(..) {
            let comment = test.take_key("comment").map(|s| s.string());
            let href = test.take_string("href");
            let new_value = test.take_string("new_value");
            let name = format!("{:?}.{} = {:?}", href, attr, new_value);
            let mut expected = test.take_key("expected").unwrap();

            let mut url = Url::parse(&href).unwrap();
            let comment_ref = comment.as_deref();
            passed &= check_invariants(&url, &name, comment_ref);
            let _ = set(&mut url, attr, &new_value);

            for attr in ATTRIBS {
                if let Some(value) = expected.take_key(attr) {
                    passed &= test_eq_eprint(value.string(), get(&url, attr), &name, comment_ref);
                };
            }

            passed &= check_invariants(&url, &name, comment_ref);
        }
    }

    assert!(passed);
}

fn get<'a>(url: &'a Url, attr: &str) -> &'a str {
    match attr {
        "href" => quirks::href(url),
        "protocol" => quirks::protocol(url),
        "username" => quirks::username(url),
        "password" => quirks::password(url),
        "hostname" => quirks::hostname(url),
        "host" => quirks::host(url),
        "port" => quirks::port(url),
        "pathname" => quirks::pathname(url),
        "search" => quirks::search(url),
        "hash" => quirks::hash(url),
        _ => unreachable!(),
    }
}

fn set<'a>(url: &'a mut Url, attr: &str, new: &str) {
    let _ = match attr {
        "protocol" => quirks::set_protocol(url, new),
        "username" => quirks::set_username(url, new),
        "password" => quirks::set_password(url, new),
        "hostname" => quirks::set_hostname(url, new),
        "host" => quirks::set_host(url, new),
        "port" => quirks::set_port(url, new),
        "pathname" => Ok(quirks::set_pathname(url, new)),
        "search" => Ok(quirks::set_search(url, new)),
        "hash" => Ok(quirks::set_hash(url, new)),
        _ => unreachable!(),
    };
}

fn test_eq_eprint(expected: String, actual: &str, name: &str, comment: Option<&str>) -> bool {
    if expected == actual {
        return true;
    }
    eprint_failure(
        format!("expected: {}\n  actual: {}", expected, actual),
        name,
        comment,
    );
    false
}

fn eprint_failure(err: String, name: &str, comment: Option<&str>) {
    eprintln!("    test: {}\n{}", name, err);
    if let Some(comment) = comment {
        eprintln!("{}\n", comment);
    } else {
        eprintln!("");
    }
}

const ATTRIBS: &[&str] = &[
    "href", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search",
    "hash",
];
<commit_msg>url: tweak code order in test module<commit_after>// Copyright 2013-2014 The rust-url developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Data-driven tests

use std::str::FromStr;

use serde_json::Value;
use url::{quirks, Url};

#[test]
fn urltestdata() {
    // Copied form https://github.com/w3c/web-platform-tests/blob/master/url/
    let mut json = Value::from_str(include_str!("urltestdata.json"))
        .expect("JSON parse error in urltestdata.json");

    let mut passed = true;
    for entry in json.as_array_mut().unwrap() {
        if entry.is_string() {
            continue; // ignore comments
        }

        let base = entry.take_string("base");
        let input = entry.take_string("input");
        let failure = entry.take_key("failure").is_some();

        let base = match Url::parse(&base) {
            Ok(base) => base,
            Err(_) if failure => continue,
            Err(message) => {
                eprint_failure(
                    format!("  failed: error parsing base {:?}: {}", base, message),
                    &format!("parse base for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        let url = match (base.join(&input), failure) {
            (Ok(url), false) => url,
            (Err(_), true) => continue,
            (Err(message), false) => {
                eprint_failure(
                    format!("  failed: {}", message),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
            (Ok(_), true) => {
                eprint_failure(
                    format!("  failed: expected parse error for URL {:?}", input),
                    &format!("parse URL for {:?}", input),
                    None,
                );
                passed = false;
                continue;
            }
        };

        passed &= check_invariants(&url, &format!("invariants for {:?}", input), None);

        for &attr in ATTRIBS {
            passed &= test_eq_eprint(
                entry.take_string(attr),
                get(&url, attr),
                &format!("{:?} - {}", input, attr),
                None,
            );
        }

        if let Some(expected_origin) = entry.take_key("origin").map(|s| s.string()) {
            passed &= test_eq_eprint(
                expected_origin,
                &quirks::origin(&url),
                &format!("origin for {:?}", input),
                None,
            );
        }
    }

    assert!(passed)
}

#[test]
fn setters_tests() {
    let mut json = Value::from_str(include_str!("setters_tests.json"))
        .expect("JSON parse error in setters_tests.json");

    let mut passed = true;
    for &attr in ATTRIBS {
        if attr == "href" {
            continue;
        }

        let mut tests = json.take_key(attr).unwrap();
        for mut test in tests.as_array_mut().unwrap().drain(..) {
            let comment = test.take_key("comment").map(|s| s.string());
            let href = test.take_string("href");
            let new_value = test.take_string("new_value");
            let name = format!("{:?}.{} = {:?}", href, attr, new_value);
            let mut expected = test.take_key("expected").unwrap();

            let mut url = Url::parse(&href).unwrap();
            let comment_ref = comment.as_deref();
            passed &= check_invariants(&url, &name, comment_ref);
            let _ = set(&mut url, attr, &new_value);

            for attr in ATTRIBS {
                if let Some(value) = expected.take_key(attr) {
                    passed &= test_eq_eprint(value.string(), get(&url, attr), &name, comment_ref);
                };
            }

            passed &= check_invariants(&url, &name, comment_ref);
        }
    }

    assert!(passed);
}

fn check_invariants(url: &Url, name: &str, comment: Option<&str>) -> bool {
    let mut passed = true;
    if let Err(e) = url.check_invariants() {
        passed = false;
        eprint_failure(
            format!("  failed: invariants checked -> {:?}", e),
            name,
            comment,
        );
    }

    #[cfg(feature = "serde")]
    {
        let bytes = serde_json::to_vec(url).unwrap();
        let new_url: Url = serde_json::from_slice(&bytes).unwrap();
        passed &= test_eq(url, &new_url, name, comment);
    }

    passed
}

trait JsonExt {
    fn take_key(&mut self, key: &str) -> Option<Value>;
    fn string(self) -> String;
    fn take_string(&mut self, key: &str) -> String;
}

impl JsonExt for Value {
    fn take_key(&mut self, key: &str) -> Option<Value> {
        self.as_object_mut().unwrap().remove(key)
    }

    fn string(self) -> String {
        if let Value::String(s) = self {
            s
        } else {
            panic!("Not a Value::String")
        }
    }

    fn take_string(&mut self, key: &str) -> String {
        self.take_key(key).unwrap().string()
    }
}

fn get<'a>(url: &'a Url, attr: &str) -> &'a str {
    match attr {
        "href" => quirks::href(url),
        "protocol" => quirks::protocol(url),
        "username" => quirks::username(url),
        "password" => quirks::password(url),
        "hostname" => quirks::hostname(url),
        "host" => quirks::host(url),
        "port" => quirks::port(url),
        "pathname" => quirks::pathname(url),
        "search" => quirks::search(url),
        "hash" => quirks::hash(url),
        _ => unreachable!(),
    }
}

fn set<'a>(url: &'a mut Url, attr: &str, new: &str) {
    let _ = match attr {
        "protocol" => quirks::set_protocol(url, new),
        "username" => quirks::set_username(url, new),
        "password" => quirks::set_password(url, new),
        "hostname" => quirks::set_hostname(url, new),
        "host" => quirks::set_host(url, new),
        "port" => quirks::set_port(url, new),
        "pathname" => Ok(quirks::set_pathname(url, new)),
        "search" => Ok(quirks::set_search(url, new)),
        "hash" => Ok(quirks::set_hash(url, new)),
        _ => unreachable!(),
    };
}

fn test_eq_eprint(expected: String, actual: &str, name: &str, comment: Option<&str>) -> bool {
    if expected == actual {
        return true;
    }
    eprint_failure(
        format!("expected: {}\n  actual: {}", expected, actual),
        name,
        comment,
    );
    false
}

fn eprint_failure(err: String, name: &str, comment: Option<&str>) {
    eprintln!("    test: {}\n{}", name, err);
    if let Some(comment) = comment {
        eprintln!("{}\n", comment);
    } else {
        eprintln!("");
    }
}

const ATTRIBS: &[&str] = &[
    "href", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search",
    "hash",
];
<|endoftext|>


<commit_before>extern crate extra;

use std::env;
use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::exit;

static MAN_PAGE: &str = /* @MANSTART{grep} */ r#"
NAME
    grep - print lines matching a pattern

SYNOPSIS
    grep [-h | --help] [-n --line-number] PATTERN [FILE...]

DESCRIPTION
    grep searches the named input FILEs for lines containing a match to the given PATTERN. If no
    files are specified, grep searches the standard input. grep prints the matching lines.

OPTIONS
    -h
    --help
        Print this manual page.

    -v
    --invert-match
        Invert matching.

    -c
    --count
        Print count of matching lines, instead of those lines.

    -n
    --line-number
        Prefix each line of output with the line number of the match.
"#; /* @MANEND */

#[derive(Copy, Clone)]
struct Flags {
    line_numbers: bool,
    invert_match: bool,
    count: bool,
}

impl Flags {
    fn new() -> Flags {
        Flags {
            line_numbers: false,
            invert_match: false,
            count: false,
        }
    }
}

fn main() {
    let args = env::args().skip(1);
    let stdin = io::stdin();
    let stdin = stdin.lock();

    let mut flags = Flags::new();
    let mut pattern = String::new();
    let mut files = Vec::with_capacity(args.len());
    for arg in args {
        if arg.starts_with('-') {
            match arg.as_str() {
                "-h" | "--help" => {
                    print!("{}", MAN_PAGE);
                    exit(0);
                }
                "-n" | "--line-number" => flags.line_numbers = true,
                "-v" | "--invert-match" => flags.invert_match = true,
                "-c" | "--count" => flags.count = true,
                _ => {
                    eprintln!("Error, unknown option: {}", arg);
                    exit(2);
                }
            }
        } else if pattern.is_empty() {
            pattern = arg.clone();
        } else {
            files.push(arg)
        }
    }

    if pattern.is_empty() {
        eprintln!("You must provide a pattern");
        exit(2);
    }

    let mut found = false;
    let mut error = false;
    if files.is_empty() {
        found = do_simple_search(BufReader::new(stdin), &pattern, flags);
    } else {
        for path in files {
            match File::open(&Path::new(&path)) {
                Ok(f) => {
                    found |= do_simple_search(BufReader::new(f), &pattern, flags);
                }
                Err(err) => {
                    eprintln!("Error opening {}: {}", path, err);
                    error = true;
                }
            }
        }
    }
    if error {
        exit(2);
    }
    if !found {
        exit(1);
    }
}

fn do_simple_search<T: BufRead>(reader: T, pattern: &str, flags: Flags) -> bool {
    let mut count = 0;
    for (line_num, result) in reader.lines().enumerate() {
        if let Ok(line) = result {
            let mut is_match = line.contains(pattern);
            if flags.invert_match {
                is_match = !is_match
            }
            if is_match {
                count += 1;
                if flags.line_numbers {
                    print!("{}: ", line_num + 1);
                }
                println!("{}", line);
            }
        }
    }

    if flags.count {
        println!("{}", count);
    }

    return count > 0;
}
<commit_msg>Print matches or count, not both, in grep<commit_after>extern crate extra;

use std::env;
use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::exit;

static MAN_PAGE: &str = /* @MANSTART{grep} */ r#"
NAME
    grep - print lines matching a pattern

SYNOPSIS
    grep [-h | --help] [-n --line-number] PATTERN [FILE...]

DESCRIPTION
    grep searches the named input FILEs for lines containing a match to the given PATTERN. If no
    files are specified, grep searches the standard input. grep prints the matching lines.

OPTIONS
    -h
    --help
        Print this manual page.

    -v
    --invert-match
        Invert matching.

    -c
    --count
        Print count of matching lines, instead of those lines.

    -n
    --line-number
        Prefix each line of output with the line number of the match.
"#; /* @MANEND */

#[derive(Copy, Clone)]
struct Flags {
    line_numbers: bool,
    invert_match: bool,
    count: bool,
}

impl Flags {
    fn new() -> Flags {
        Flags {
            line_numbers: false,
            invert_match: false,
            count: false,
        }
    }
}

fn main() {
    let args = env::args().skip(1);
    let stdin = io::stdin();
    let stdin = stdin.lock();

    let mut flags = Flags::new();
    let mut pattern = String::new();
    let mut files = Vec::with_capacity(args.len());
    for arg in args {
        if arg.starts_with('-') {
            match arg.as_str() {
                "-h" | "--help" => {
                    print!("{}", MAN_PAGE);
                    exit(0);
                }
                "-n" | "--line-number" => flags.line_numbers = true,
                "-v" | "--invert-match" => flags.invert_match = true,
                "-c" | "--count" => flags.count = true,
                _ => {
                    eprintln!("Error, unknown option: {}", arg);
                    exit(2);
                }
            }
        } else if pattern.is_empty() {
            pattern = arg.clone();
        } else {
            files.push(arg)
        }
    }

    if pattern.is_empty() {
        eprintln!("You must provide a pattern");
        exit(2);
    }

    let mut found = false;
    let mut error = false;
    if files.is_empty() {
        found = do_simple_search(BufReader::new(stdin), &pattern, flags);
    } else {
        for path in files {
            match File::open(&Path::new(&path)) {
                Ok(f) => {
                    found |= do_simple_search(BufReader::new(f), &pattern, flags);
                }
                Err(err) => {
                    eprintln!("Error opening {}: {}", path, err);
                    error = true;
                }
            }
        }
    }
    if error {
        exit(2);
    }
    if !found {
        exit(1);
    }
}

fn do_simple_search<T: BufRead>(reader: T, pattern: &str, flags: Flags) -> bool {
    let mut count = 0;
    for (line_num, result) in reader.lines().enumerate() {
        if let Ok(line) = result {
            let mut is_match = line.contains(pattern);
            if flags.invert_match {
                is_match = !is_match
            }
            if is_match {
                count += 1;
                if !flags.count {
                    if flags.line_numbers {
                        print!("{}: ", line_num + 1);
                    }
                    println!("{}", line);
                }
            }
        }
    }

    if flags.count {
        println!("{}", count);
    }

    return count > 0;
}
<|endoftext|>


<commit_before>//! # mm_cli
//!
//! The `mm_cli` feature provides the ability to compile a very minimal cli for querying against
//! the PBS Media Manager API. It is built directly on top of the [Client](struct.Client.html)
//! and allows for querying against either the production API or the staging API.
//!
//! ### Configuration
//!
//! Configuration for the cli is contained within a `config.toml` file. It uses a `live` key to
//! designate your credentials for the production API and a `staging` key for the staging API.
//!
//! The confiuration file can be created manually or the cli can generate it with some assistance.
//! If you run the cli without a configuration file then it will attempt to generate one and prompt
//! for the necessary credentials. Settings can be rewritten by running the cli with the `init`
//! flag.

#![deny(missing_docs)]
extern crate app_dirs;
extern crate clap;
extern crate mm_client;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod error;
mod config;

use app_dirs::{AppDataType, AppInfo, get_app_dir};
use clap::{App, Arg};
use mm_client::Client;
use mm_client::Endpoints;
use mm_client::MMCResult;

use std::str::FromStr;

use error::CLIError;
use config::Config;

fn main() {

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            Arg::with_name("init")
                .long("init")
                .takes_value(false)
                .help("Creates/replaces a config.toml file"),
        )
        .arg(
            Arg::with_name("type")
                .takes_value(true)
                .required(false)
                .help("Object type to query for"),
        )
        .arg(
            Arg::with_name("id")
                .takes_value(true)
                .required(false)
                .help("Object id to query for"),
        )
        .arg(
            Arg::with_name("staging")
                .short("s")
                .long("staging")
                .takes_value(false)
                .help("Runs query against the staging environment"),
        )
        .get_matches();

    let info = AppInfo {
        name: env!("CARGO_PKG_NAME"),
        author: "tpt",
    };

    let config_path = get_app_dir(AppDataType::UserConfig, &info, "/")
        .and_then(|mut path| {
            path.push("config.toml");
            Ok(path)
        })
        .expect(
            "Failed to run. Unable to determine default config location.",
        );

    let path = config_path.to_str().expect(
        "Failed to parse config location.",
    );

    if matches.is_present("init") {
        Config::create(path);
    };

    match (matches.value_of("type"), matches.value_of("id")) {
        (Some(endpoint), Some(id)) => {

            Config::parse_config(path).and_then(|config| {
                let result = Endpoints::from_str(endpoint)
                    .or(Err(CLIError::Endpoint))
                    .and_then(|ep| {
                        rq_endpoint(&config, matches.is_present("staging"), ep, id)
                    });

                // Handle the result from the client, outputting it to the user
                match result {
                    Ok(ref value) => println!("{}", value),
                    Err(ref error) => println!("An error occured: {}", error),
                };

                result
            });
        }
        _ => (),
    }
}

fn rq_endpoint(
    config: &Config,
    is_staging: bool,
    endpoint: Endpoints,
    id: &str,
) -> Result<String, CLIError> {
    let conf = if is_staging {
        &config.staging
    } else {
        &config.live
    };

    // Attempt to get a response from the requested endpoint if it is
    // one of the available endpoints
    match *conf {
        Some(ref key_sec) => {

            let client = if is_staging {
                Client::staging(key_sec.key.as_str(), key_sec.secret.as_str())
            } else {
                Client::new(key_sec.key.as_str(), key_sec.secret.as_str())
            };

            client.map_err(CLIError::Network).and_then(|cl| {
                handle_client_response(cl.get(endpoint, id))
            })
        }
        None => Err(CLIError::EndpointConfigMissing),
    }
}

/// Handles responses from the Core Data Client and transforms them into
/// a Result that is ready for output to a user
fn handle_client_response(result: MMCResult<String>) -> Result<String, CLIError> {
    match result {
        Ok(json_string) => to_pretty_print(json_string),
        Err(err) => Err(CLIError::Network(err)),
    }
}

// Accepts a String of json, and returns the Result of attempting to transform
// it into a pretty printable String
fn to_pretty_print(json_string: String) -> Result<String, CLIError> {

    // Attempt to deserialize the json string
    let parsed: Result<serde_json::Value, serde_json::Error> =
        serde_json::from_str(json_string.as_str());

    // Return either successfully decoded json or a Format error
    match parsed {
        Ok(json) => serde_json::ser::to_string_pretty(&json).map_err(CLIError::Format),
        Err(err) => Err(CLIError::Format(err)),
    }
}
<commit_msg>DEVOPS-86 Update cli for client changes<commit_after>//! # mm_cli
//!
//! The `mm_cli` feature provides the ability to compile a very minimal cli for querying against
//! the PBS Media Manager API. It is built directly on top of the [Client](struct.Client.html)
//! and allows for querying against either the production API or the staging API.
//!
//! ### Configuration
//!
//! Configuration for the cli is contained within a `config.toml` file. It uses a `live` key to
//! designate your credentials for the production API and a `staging` key for the staging API.
//!
//! The confiuration file can be created manually or the cli can generate it with some assistance.
//! If you run the cli without a configuration file then it will attempt to generate one and prompt
//! for the necessary credentials. Settings can be rewritten by running the cli with the `init`
//! flag.

#![deny(missing_docs)]
extern crate app_dirs;
extern crate clap;
extern crate mm_client;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod error;
mod config;

use app_dirs::{AppDataType, AppInfo, get_app_dir};
use clap::{App, Arg};
use mm_client::Client;
use mm_client::Endpoints;
use mm_client::MMCResult;

use std::str::FromStr;

use error::CLIError;
use config::Config;

fn main() {

    let matches = App::new(env!("CARGO_PKG_NAME"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            Arg::with_name("init")
                .long("init")
                .takes_value(false)
                .help("Creates/replaces a config.toml file"),
        )
        .arg(
            Arg::with_name("type")
                .takes_value(true)
                .required(false)
                .help("Object type to query for"),
        )
        .arg(
            Arg::with_name("id")
                .takes_value(true)
                .required(false)
                .help("Object id to query for"),
        )
        .arg(
            Arg::with_name("staging")
                .short("s")
                .long("staging")
                .takes_value(false)
                .help("Runs query against the staging environment"),
        )
        .get_matches();

    let info = AppInfo {
        name: env!("CARGO_PKG_NAME"),
        author: "tpt",
    };

    let config_path = get_app_dir(AppDataType::UserConfig, &info, "/")
        .and_then(|mut path| {
            path.push("config.toml");
            Ok(path)
        })
        .expect(
            "Failed to run. Unable to determine default config location.",
        );

    let path = config_path.to_str().expect(
        "Failed to parse config location.",
    );

    if matches.is_present("init") {
        Config::create(path);
    };

    match (matches.value_of("type"), matches.value_of("id")) {
        (Some(endpoint), Some(id)) => {

            Config::parse_config(path).and_then(|config| {
                let result = Endpoints::from_str(endpoint)
                    .or(Err(CLIError::Endpoint))
                    .and_then(|ep| {
                        rq_endpoint(&config, matches.is_present("staging"), ep, id)
                    });

                // Handle the result from the client, outputting it to the user
                match result {
                    Ok(ref value) => println!("{}", value),
                    Err(ref error) => println!("An error occured: {}", error),
                };

                result
            });
        }
        _ => (),
    }
}

fn rq_endpoint(
    config: &Config,
    is_staging: bool,
    endpoint: Endpoints,
    id: &str,
) -> Result<String, CLIError> {
    let conf = if is_staging {
        &config.staging
    } else {
        &config.live
    };

    // Attempt to get a response from the requested endpoint if it is
    // one of the available endpoints
    match *conf {
        Some(ref key_sec) => {

            let client = if is_staging {
                Client::staging(key_sec.key.as_str(), key_sec.secret.as_str())
            } else {
                Client::new(key_sec.key.as_str(), key_sec.secret.as_str())
            };

            client.map_err(CLIError::Network).and_then(|cl| {
                handle_client_response(cl.get(endpoint, id, None))
            })
        }
        None => Err(CLIError::EndpointConfigMissing),
    }
}

/// Handles responses from the Core Data Client and transforms them into
/// a Result that is ready for output to a user
fn handle_client_response(result: MMCResult<String>) -> Result<String, CLIError> {
    match result {
        Ok(json_string) => to_pretty_print(json_string),
        Err(err) => Err(CLIError::Network(err)),
    }
}

// Accepts a String of json, and returns the Result of attempting to transform
// it into a pretty printable String
fn to_pretty_print(json_string: String) -> Result<String, CLIError> {

    // Attempt to deserialize the json string
    let parsed: Result<serde_json::Value, serde_json::Error> =
        serde_json::from_str(json_string.as_str());

    // Return either successfully decoded json or a Format error
    match parsed {
        Ok(json) => serde_json::ser::to_string_pretty(&json).map_err(CLIError::Format),
        Err(err) => Err(CLIError::Format(err)),
    }
}
<|endoftext|>