<commit_before>// http://rosettacode.org/wiki/Arithmetic/Rational

#![feature(zero_one)]

use std::num::{Zero, One};
use std::fmt;
use std::cmp::Ordering;
use std::ops::{Add, Mul, Neg, Sub, Div};

fn main() {
    for p in perfect_numbers(1 << 19) {
        println!("{} is perfect", p);
    }
}

fn perfect_numbers(max: i64) -> Vec<i64> {
    let mut ret = Vec::new();
    for candidate in 2..max {
        let mut sum = Frac::secure_new(1, candidate).unwrap();
        let max2 = ((candidate as f64).sqrt().floor()) as i64;

        for factor in 2..max2 + 1 {
            if candidate % factor == 0 {
                sum = sum + Frac::new(1, factor) + Frac::new(factor, candidate);
            }
        }
        if sum == Frac::new(1, 1) {
            ret.push(candidate);
        }
    }
    ret
}

#[derive(Copy, Clone)]
struct Frac {
    num: i64,
    den: i64,
}

fn gcd(m: i64, n: i64) -> i64 {
    let mut t: i64;
    let (mut m, mut n) = (m.abs(), n.abs());
    while n > 0 {
        t = n;
        n = m % n;
        m = t;
    }
    m
}

fn lcm(m: i64, n: i64) -> i64 {
    m.abs() / gcd(m, n) * n.abs()
}

impl Frac {
    /// fails on den=0
    fn new(num: i64, den: i64) -> Frac {
        let (n, d) = match (num, den) {
            (0, _) => (0, 0),
            (n, d) if d < 0 => (-n, -d),
            a @ _ => a,
        };

        Frac { num: n, den: d }
    }

    /// does not fail (returns Err on den=0)
    fn secure_new(num: i64, den: i64) -> Result<Frac, String> {
        if den == 0 {
            Err("Error: Division by zero".to_string())
        } else {
            Ok(Frac::new(num, den))
        }
    }

    /// fails on den=0, returns frac already in its reduced form
    fn new_reduced(num: i64, den: i64) -> Frac {
        Frac::new(num, den).reduce()
    }

    /// reduces the fraction to lowest terms
    fn reduce(mut self) -> Frac {
        match self {
            z @ Frac{num:0, den:0} => z,
            _ => {
                let gcd = gcd(self.num, self.den);
                self.num /= gcd;
                self.den /= gcd;
                self
            }
        }
    }
}

impl fmt::Debug for Frac {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match (self.num, self.den) {
            (_, 1) | (0, 0) => write!(f, "{}", self.num),
            (_, _) => write!(f, "{}/{}", self.num, self.den),
        }
    }
}

impl PartialEq for Frac {
    fn eq(&self, other: &Frac) -> bool {
        let (red_a, red_b) = (self.reduce(), other.reduce());
        red_a.num == red_b.num && red_a.den == red_b.den
    }
}

impl Eq for Frac {}

impl PartialOrd for Frac {
    fn partial_cmp(&self, other: &Frac) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Frac {
    fn cmp(&self, other: &Frac) -> Ordering {
        (self.num * other.den).cmp(&(self.den * other.num))
    }
}

impl Neg for Frac {
    type Output = Frac;

    fn neg(self) -> Frac {
        Frac {
            num: -self.num,
            den: self.den,
        }
    }
}

impl Add for Frac {
    type Output = Frac;
    fn add(self, other: Frac) -> Frac {
        let (a, b) = (self.reduce(), other.reduce());
        let m = lcm(a.den, b.den);

        let na = a.num * m / a.den;
        let nb = b.num * m / b.den;
        Frac::new_reduced(na + nb, m)
    }
}

impl Sub for Frac {
    type Output = Frac;
    fn sub(self, other: Frac) -> Frac {
        self + (-other)
    }
}

impl Mul for Frac {
    type Output = Frac;
    fn mul(self, other: Frac) -> Frac {
        Frac::new_reduced(self.num * other.num, self.den * other.den)
    }
}

impl Div for Frac {
    type Output = Frac;
    fn div(self, other: Frac) -> Frac {
        Frac::new_reduced(self.num * other.den, self.den * other.num)
    }
}

impl Zero for Frac {
    fn zero() -> Frac {
        Frac::new(0, 1)
    }
}

impl One for Frac {
    fn one() -> Frac {
        Frac::new(1, 1)
    }
}

#[test]
fn operators() {
    let (a, b) = (Frac::new(1, 2), Frac::new(12, 15));
    assert_eq!(a + b, Frac::secure_new(13, 10).unwrap());
    assert_eq!(b - a, Frac::new(3, 10));
    assert_eq!(a - b, Frac::new(-3, 10));
    assert_eq!(a * b, Frac::new(2, 5));
    assert_eq!(a / b, Frac::new(5, 8));

    let (a, b) = (Frac::new(1, 2), Frac::new(1, 2));
    assert_eq!(a + b, One::one());
    assert_eq!(b - a, Zero::zero());
    assert_eq!(a - b, Zero::zero());
    assert_eq!(a * b, Frac::new(1, 4));
    assert_eq!(a / b, Frac::new(1, 1));
}

#[test]
fn first_perfect_numbers() {
    assert_eq!(perfect_numbers(8150), vec![6, 28, 496, 8128]);
}
<commit_msg>fix redundant pattern<commit_after>// http://rosettacode.org/wiki/Arithmetic/Rational

#![feature(zero_one)]

use std::num::{Zero, One};
use std::fmt;
use std::cmp::Ordering;
use std::ops::{Add, Mul, Neg, Sub, Div};

fn main() {
    for p in perfect_numbers(1 << 19) {
        println!("{} is perfect", p);
    }
}

fn perfect_numbers(max: i64) -> Vec<i64> {
    let mut ret = Vec::new();
    for candidate in 2..max {
        let mut sum = Frac::secure_new(1, candidate).unwrap();
        let max2 = ((candidate as f64).sqrt().floor()) as i64;

        for factor in 2..max2 + 1 {
            if candidate % factor == 0 {
                sum = sum + Frac::new(1, factor) + Frac::new(factor, candidate);
            }
        }
        if sum == Frac::new(1, 1) {
            ret.push(candidate);
        }
    }
    ret
}

#[derive(Copy, Clone)]
struct Frac {
    num: i64,
    den: i64,
}

fn gcd(m: i64, n: i64) -> i64 {
    let mut t: i64;
    let (mut m, mut n) = (m.abs(), n.abs());
    while n > 0 {
        t = n;
        n = m % n;
        m = t;
    }
    m
}

fn lcm(m: i64, n: i64) -> i64 {
    m.abs() / gcd(m, n) * n.abs()
}

impl Frac {
    /// fails on den=0
    fn new(num: i64, den: i64) -> Frac {
        let (n, d) = match (num, den) {
            (0, _) => (0, 0),
            (n, d) if d < 0 => (-n, -d),
            a => a,
        };

        Frac { num: n, den: d }
    }

    /// does not fail (returns Err on den=0)
    fn secure_new(num: i64, den: i64) -> Result<Frac, String> {
        if den == 0 {
            Err("Error: Division by zero".to_string())
        } else {
            Ok(Frac::new(num, den))
        }
    }

    /// fails on den=0, returns frac already in its reduced form
    fn new_reduced(num: i64, den: i64) -> Frac {
        Frac::new(num, den).reduce()
    }

    /// reduces the fraction to lowest terms
    fn reduce(mut self) -> Frac {
        match self {
            z @ Frac { num: 0, den: 0 } => z,
            _ => {
                let gcd = gcd(self.num, self.den);
                self.num /= gcd;
                self.den /= gcd;
                self
            }
        }
    }
}

impl fmt::Debug for Frac {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match (self.num, self.den) {
            (_, 1) | (0, 0) => write!(f, "{}", self.num),
            (_, _) => write!(f, "{}/{}", self.num, self.den),
        }
    }
}

impl PartialEq for Frac {
    fn eq(&self, other: &Frac) -> bool {
        let (red_a, red_b) = (self.reduce(), other.reduce());
        red_a.num == red_b.num && red_a.den == red_b.den
    }
}

impl Eq for Frac {}

impl PartialOrd for Frac {
    fn partial_cmp(&self, other: &Frac) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Frac {
    fn cmp(&self, other: &Frac) -> Ordering {
        (self.num * other.den).cmp(&(self.den * other.num))
    }
}

impl Neg for Frac {
    type Output = Frac;

    fn neg(self) -> Frac {
        Frac {
            num: -self.num,
            den: self.den,
        }
    }
}

impl Add for Frac {
    type Output = Frac;
    fn add(self, other: Frac) -> Frac {
        let (a, b) = (self.reduce(), other.reduce());
        let m = lcm(a.den, b.den);

        let na = a.num * m / a.den;
        let nb = b.num * m / b.den;
        Frac::new_reduced(na + nb, m)
    }
}

impl Sub for Frac {
    type Output = Frac;
    fn sub(self, other: Frac) -> Frac {
        self + (-other)
    }
}

impl Mul for Frac {
    type Output = Frac;
    fn mul(self, other: Frac) -> Frac {
        Frac::new_reduced(self.num * other.num, self.den * other.den)
    }
}

impl Div for Frac {
    type Output = Frac;
    fn div(self, other: Frac) -> Frac {
        Frac::new_reduced(self.num * other.den, self.den * other.num)
    }
}

impl Zero for Frac {
    fn zero() -> Frac {
        Frac::new(0, 1)
    }
}

impl One for Frac {
    fn one() -> Frac {
        Frac::new(1, 1)
    }
}

#[test]
fn operators() {
    let (a, b) = (Frac::new(1, 2), Frac::new(12, 15));
    assert_eq!(a + b, Frac::secure_new(13, 10).unwrap());
    assert_eq!(b - a, Frac::new(3, 10));
    assert_eq!(a - b, Frac::new(-3, 10));
    assert_eq!(a * b, Frac::new(2, 5));
    assert_eq!(a / b, Frac::new(5, 8));

    let (a, b) = (Frac::new(1, 2), Frac::new(1, 2));
    assert_eq!(a + b, One::one());
    assert_eq!(b - a, Zero::zero());
    assert_eq!(a - b, Zero::zero());
    assert_eq!(a * b, Frac::new(1, 4));
    assert_eq!(a / b, Frac::new(1, 1));
}

#[test]
fn first_perfect_numbers() {
    assert_eq!(perfect_numbers(8150), vec![6, 28, 496, 8128]);
}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, Entry};
use std::path::Path;

use url::Url;

use ffi;
use ffi::opt;
use ffi::easy::Easy;
use http::Response;
use http::body::{Body,ToBody};
use {ProgressCb,ErrCode};

use self::Method::{Get, Head, Post, Put, Patch, Delete};
use self::BodyType::{Fixed, Chunked};

const DEFAULT_TIMEOUT_MS: usize = 30_000;

pub struct Handle {
    easy: Easy,
}

impl Handle {
    pub fn new() -> Handle {
        return configure(Handle { easy: Easy::new() }
            .timeout(DEFAULT_TIMEOUT_MS)
            .connect_timeout(DEFAULT_TIMEOUT_MS));

        #[cfg(unix)]
        fn configure(handle: Handle) -> Handle {
            let probe = ::openssl::probe::probe();
            let handle = match probe.cert_file {
                Some(ref path) => handle.ssl_ca_info(path),
                None => handle,
            };
            match probe.cert_dir {
                Some(ref path) => handle.ssl_ca_path(path),
                None => handle,
            }
        }

        #[cfg(not(unix))]
        fn configure(handle: Handle) -> Handle { handle }
    }

    pub fn timeout(mut self, ms: usize) -> Handle {
        self.easy.setopt(opt::TIMEOUT_MS, ms).unwrap();
        self
    }

    pub fn connect_timeout(mut self, ms: usize) -> Handle {
        self.easy.setopt(opt::CONNECTTIMEOUT_MS, ms).unwrap();
        self
    }

    /// Set the time in seconds that the transfer speed should be below
    /// the `low_speed_limit` rate of bytes per second for the library to
    /// consider it too slow and abort.
    ///
    /// The default for this option is 0 which means that this option is
    /// disabled.
    pub fn low_speed_timeout(mut self, seconds: usize) -> Handle {
        self.easy.setopt(opt::LOW_SPEED_TIME, seconds).unwrap();
        self
    }

    /// Set the average transfer speed in bytes per second that the
    /// transfer should be below during `low_speed_timeout` seconds for
    /// libcurl to consider it to be too slow and abort.
    ///
    /// The default for this option is 0 which means that this option is
    /// disabled.
    pub fn low_speed_limit(mut self, bytes_per_second: usize) -> Handle {
        self.easy.setopt(opt::LOW_SPEED_LIMIT, bytes_per_second).unwrap();
        self
    }

    pub fn ssl_verifypeer(mut self, value: bool) -> Handle {
        self.easy.setopt(opt::SSL_VERIFYPEER, value).unwrap();
        self
    }

    pub fn follow_location(mut self, value: isize) -> Handle {
        self.easy.setopt(opt::FOLLOWLOCATION, value).unwrap();
        self
    }

    pub fn userpwd(mut self, userpwd: &str) -> Handle {
        self.easy.setopt(opt::USERPWD, userpwd).unwrap();
        self
    }

    pub fn verbose(mut self) -> Handle {
        self.easy.setopt(opt::VERBOSE, 1).unwrap();
        self
    }

    pub fn proxy<U: ToUrl>(mut self, proxy: U) -> Handle {
        proxy.with_url_str(|s| {
            self.easy.setopt(opt::PROXY, s).unwrap();
        });

        self
    }

    pub fn ssl_ca_path(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::CAPATH, path).unwrap();
        self
    }

    pub fn ssl_ca_info(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::CAINFO, path).unwrap();
        self
    }

    pub fn cookie_jar(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::COOKIEJAR, path).unwrap();
        self
    }

    pub fn cookie_file(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::COOKIEFILE, path).unwrap();
        self
    }

    pub fn cookies(self, path: &Path) -> Handle {
        self.cookie_jar(path).cookie_file(path)
    }

    pub fn cookie(mut self, cookie: &str) -> Handle {
        self.easy.setopt(opt::COOKIELIST, cookie).unwrap();
        self
    }

    pub fn get<'a, 'b, U: ToUrl>(&'a mut self, uri: U) -> Request<'a, 'b> {
        Request::new(self, Get).uri(uri)
    }

    pub fn head<'a, 'b, U: ToUrl>(&'a mut self, uri: U) -> Request<'a, 'b> {
        Request::new(self, Head).uri(uri)
    }

    pub fn post<'a, 'b, U: ToUrl, B: ToBody<'b>>(&'a mut self, uri: U, body: B) -> Request<'a, 'b> {
        Request::new(self, Post).uri(uri).body(body)
    }

    pub fn put<'a, 'b, U: ToUrl, B: ToBody<'b>>(&'a mut self, uri: U, body: B) -> Request<'a, 'b> {
        Request::new(self, Put).uri(uri).body(body)
    }

    pub fn patch<'a, 'b, U: ToUrl, B: ToBody<'b>>(&'a mut self, uri: U, body: B) -> Request<'a, 'b> {
        Request::new(self, Patch).uri(uri).body(body)
    }

    pub fn delete<'a, 'b, U: ToUrl>(&'a mut self, uri: U) -> Request<'a, 'b> {
        Request::new(self, Delete).uri(uri)
    }
}

#[derive(Copy, Clone)]
pub enum Method {
    Options,
    Get,
    Head,
    Post,
    Put,
    Patch,
    Delete,
    Trace,
    Connect
}

pub struct Request<'a, 'b> {
    err: Option<ErrCode>,
    handle: &'a mut Handle,
    method: Method,
    headers: HashMap<String, Vec<String>>,
    body: Option<Body<'b>>,
    body_type: Option<BodyType>,
    content_type: bool, // whether or not the content type was set
    expect_continue: bool, // whether to expect a 100 continue from the server
    progress: Option<Box<ProgressCb<'b>>>,
    follow: bool,
}

enum BodyType {
    Fixed(usize),
    Chunked,
}

impl<'a, 'b> Request<'a, 'b> {
    pub fn new(handle: &'a mut Handle, method: Method) -> Request<'a, 'b> {
        Request {
            err: None,
            handle: handle,
            method: method,
            headers: HashMap::new(),
            body: None,
            body_type: None,
            content_type: false,
            expect_continue: false,
            progress: None,
            follow: false,
        }
    }

    pub fn uri<U: ToUrl>(mut self, uri: U) -> Request<'a, 'b> {
        uri.with_url_str(|s| {
            match self.handle.easy.setopt(opt::URL, s) {
                Ok(_) => {}
                Err(e) => self.err = Some(e)
            }
        });

        self
    }

    pub fn body<B: ToBody<'b>>(mut self, body: B) -> Request<'a, 'b> {
        self.body = Some(body.to_body());
        self
    }

    pub fn content_type(mut self, ty: &str) -> Request<'a, 'b> {
        if !self.content_type {
            self.content_type = true;
            append_header(&mut self.headers, "Content-Type", ty);
        }

        self
    }

    pub fn content_length(mut self, len: usize) -> Request<'a, 'b> {
        self.body_type = Some(Fixed(len));
        self
    }

    pub fn chunked(mut self) -> Request<'a, 'b> {
        self.body_type = Some(Chunked);
        self
    }

    pub fn expect_continue(mut self) -> Request<'a, 'b> {
        self.expect_continue = true;
        self
    }

    pub fn header(mut self, name: &str, val: &str) -> Request<'a, 'b> {
        append_header(&mut self.headers, name, val);
        self
    }

    pub fn get_header(&self, name: &str) -> Option<&[String]> {
        self.headers.get(name).map(|a| &a[..])
    }

    pub fn headers<'c, 'd, I: Iterator<Item=(&'c str, &'d str)>>(mut self, hdrs: I) -> Request<'a, 'b> {
        for (name, val) in hdrs {
            append_header(&mut self.headers, name, val);
        }

        self
    }

    pub fn progress<F>(mut self, cb: F) -> Request<'a, 'b>
        where F: FnMut(usize, usize, usize, usize) + 'b
    {
        self.progress = Some(Box::new(cb) as Box<ProgressCb<'b>>);
        self
    }

    pub fn follow_redirects(mut self, follow: bool) -> Request<'a, 'b> {
        self.follow = follow;
        self
    }

    pub fn exec(self) -> Result<Response, ErrCode> {
        // Deconstruct the struct
        let Request {
            err,
            handle,
            method,
            mut headers,
            mut body,
            body_type,
            content_type,
            expect_continue,
            progress,
            follow,
            ..
        } = self;

        if follow {
            try!(handle.easy.setopt(opt::FOLLOWLOCATION, 1));
        }

        match err {
            Some(e) => return Err(e),
            None => {}
        }

        // Clear custom headers set from the previous request
        try!(handle.easy.setopt(opt::HTTPHEADER, 0));

        match method {
            Get => try!(handle.easy.setopt(opt::HTTPGET, 1)),
            Head => try!(handle.easy.setopt(opt::NOBODY, 1)),
            Post => try!(handle.easy.setopt(opt::POST, 1)),
            Put => try!(handle.easy.setopt(opt::UPLOAD, 1)),
            Patch => {
                try!(handle.easy.setopt(opt::CUSTOMREQUEST, "PATCH"));
                try!(handle.easy.setopt(opt::UPLOAD, 1));
            },
            Delete => {
                if body.is_some() {
                    try!(handle.easy.setopt(opt::UPLOAD, 1));
                }

                try!(handle.easy.setopt(opt::CUSTOMREQUEST, "DELETE"));
            }
            _ => unimplemented!()
        }

        match body.as_ref() {
            None => {}
            Some(body) => {
                let body_type = body_type.unwrap_or(match body.get_size() {
                    Some(len) => Fixed(len),
                    None => Chunked,
                });

                match body_type {
                    Fixed(len) => {
                        match method {
                            Post => try!(handle.easy.setopt(opt::POSTFIELDSIZE, len)),
                            Put | Patch | Delete  => try!(handle.easy.setopt(opt::INFILESIZE, len)),
                            _ => {
                                append_header(&mut headers, "Content-Length",
                                              &len.to_string());
                            }
                        }
                    }
                    Chunked => {
                        append_header(&mut headers, "Transfer-Encoding",
                                      "chunked");
                    }

                }

                if !content_type {
                    append_header(&mut headers, "Content-Type", "application/octet-stream");
                }

                if !expect_continue {
                    append_header(&mut headers, "Expect", "");
                }
            }
        }

        let mut ffi_headers = ffi::List::new();

        if !headers.is_empty() {
            let mut buf = Vec::new();

            for (k, v) in headers.iter() {
                buf.extend(k.bytes());
                buf.extend(": ".bytes());

                for v in v.iter() {
                    buf.extend(v.bytes());
                    buf.push(0);
                    ffi_headers.push_bytes(&buf);
                    buf.truncate(k.len() + 2);
                }

                buf.truncate(0);
            }

            try!(handle.easy.setopt(opt::HTTPHEADER, &ffi_headers));
        }

        handle.easy.perform(body.as_mut(), progress)
    }
}

fn append_header(map: &mut HashMap<String, Vec<String>>, key: &str, val: &str) {
    match map.entry(key.to_string()) {
        Entry::Vacant(entry) => {
            let mut values = Vec::new();
            values.push(val.to_string());
            entry.insert(values)
        },
        Entry::Occupied(entry) => entry.into_mut()
    };
}

pub trait ToUrl{
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str);
}

impl<'a> ToUrl for &'a str {
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str) {
        f(self);
    }
}

impl<'a> ToUrl for &'a Url {
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str) {
        self.to_string().with_url_str(f);
    }
}

impl ToUrl for String {
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str) {
        self[..].with_url_str(f);
    }
}

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

    #[test]
    fn get_header() {
        let mut h = Handle::new();
        let r = h.get("/foo").header("foo", "bar");
        assert_eq!(r.get_header("foo"), Some(&["bar".to_string()][..]));
    }
}
<commit_msg>Don't panic setting CAINFO/CAPATH options<commit_after>use std::collections::hash_map::{HashMap, Entry};
use std::path::Path;

use url::Url;

use ffi::easy::Easy;
use ffi::err;
use ffi::opt;
use ffi;
use http::Response;
use http::body::{Body,ToBody};
use {ProgressCb,ErrCode};

use self::Method::{Get, Head, Post, Put, Patch, Delete};
use self::BodyType::{Fixed, Chunked};

const DEFAULT_TIMEOUT_MS: usize = 30_000;

pub struct Handle {
    easy: Easy,
}

impl Handle {
    pub fn new() -> Handle {
        return configure(Handle { easy: Easy::new() }
            .timeout(DEFAULT_TIMEOUT_MS)
            .connect_timeout(DEFAULT_TIMEOUT_MS));

        #[cfg(unix)]
        fn configure(mut handle: Handle) -> Handle {
            let probe = ::openssl::probe::probe();
            if let Some(ref path) = probe.cert_file {
                set_path(&mut handle, opt::CAINFO, path);
            }
            if let Some(ref path) = probe.cert_dir {
                set_path(&mut handle, opt::CAPATH, path);
            }
            return handle;

            fn set_path(handle: &mut Handle, opt: opt::Opt, path: &Path) {
                if let Err(e) = handle.easy.setopt(opt, path) {
                    if let err::NOT_BUILT_IN = e.code() {
                        return
                    }
                    panic!("failed to set {:?}: {}", opt, e)
                }
            }
        }

        #[cfg(not(unix))]
        fn configure(handle: Handle) -> Handle { handle }
    }

    pub fn timeout(mut self, ms: usize) -> Handle {
        self.easy.setopt(opt::TIMEOUT_MS, ms).unwrap();
        self
    }

    pub fn connect_timeout(mut self, ms: usize) -> Handle {
        self.easy.setopt(opt::CONNECTTIMEOUT_MS, ms).unwrap();
        self
    }

    /// Set the time in seconds that the transfer speed should be below
    /// the `low_speed_limit` rate of bytes per second for the library to
    /// consider it too slow and abort.
    ///
    /// The default for this option is 0 which means that this option is
    /// disabled.
    pub fn low_speed_timeout(mut self, seconds: usize) -> Handle {
        self.easy.setopt(opt::LOW_SPEED_TIME, seconds).unwrap();
        self
    }

    /// Set the average transfer speed in bytes per second that the
    /// transfer should be below during `low_speed_timeout` seconds for
    /// libcurl to consider it to be too slow and abort.
    ///
    /// The default for this option is 0 which means that this option is
    /// disabled.
    pub fn low_speed_limit(mut self, bytes_per_second: usize) -> Handle {
        self.easy.setopt(opt::LOW_SPEED_LIMIT, bytes_per_second).unwrap();
        self
    }

    pub fn ssl_verifypeer(mut self, value: bool) -> Handle {
        self.easy.setopt(opt::SSL_VERIFYPEER, value).unwrap();
        self
    }

    pub fn follow_location(mut self, value: isize) -> Handle {
        self.easy.setopt(opt::FOLLOWLOCATION, value).unwrap();
        self
    }

    pub fn userpwd(mut self, userpwd: &str) -> Handle {
        self.easy.setopt(opt::USERPWD, userpwd).unwrap();
        self
    }

    pub fn verbose(mut self) -> Handle {
        self.easy.setopt(opt::VERBOSE, 1).unwrap();
        self
    }

    pub fn proxy<U: ToUrl>(mut self, proxy: U) -> Handle {
        proxy.with_url_str(|s| {
            self.easy.setopt(opt::PROXY, s).unwrap();
        });

        self
    }

    pub fn ssl_ca_path(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::CAPATH, path).unwrap();
        self
    }

    pub fn ssl_ca_info(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::CAINFO, path).unwrap();
        self
    }

    pub fn cookie_jar(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::COOKIEJAR, path).unwrap();
        self
    }

    pub fn cookie_file(mut self, path: &Path) -> Handle {
        self.easy.setopt(opt::COOKIEFILE, path).unwrap();
        self
    }

    pub fn cookies(self, path: &Path) -> Handle {
        self.cookie_jar(path).cookie_file(path)
    }

    pub fn cookie(mut self, cookie: &str) -> Handle {
        self.easy.setopt(opt::COOKIELIST, cookie).unwrap();
        self
    }

    pub fn get<'a, 'b, U: ToUrl>(&'a mut self, uri: U) -> Request<'a, 'b> {
        Request::new(self, Get).uri(uri)
    }

    pub fn head<'a, 'b, U: ToUrl>(&'a mut self, uri: U) -> Request<'a, 'b> {
        Request::new(self, Head).uri(uri)
    }

    pub fn post<'a, 'b, U: ToUrl, B: ToBody<'b>>(&'a mut self, uri: U, body: B) -> Request<'a, 'b> {
        Request::new(self, Post).uri(uri).body(body)
    }

    pub fn put<'a, 'b, U: ToUrl, B: ToBody<'b>>(&'a mut self, uri: U, body: B) -> Request<'a, 'b> {
        Request::new(self, Put).uri(uri).body(body)
    }

    pub fn patch<'a, 'b, U: ToUrl, B: ToBody<'b>>(&'a mut self, uri: U, body: B) -> Request<'a, 'b> {
        Request::new(self, Patch).uri(uri).body(body)
    }

    pub fn delete<'a, 'b, U: ToUrl>(&'a mut self, uri: U) -> Request<'a, 'b> {
        Request::new(self, Delete).uri(uri)
    }
}

#[derive(Copy, Clone)]
pub enum Method {
    Options,
    Get,
    Head,
    Post,
    Put,
    Patch,
    Delete,
    Trace,
    Connect
}

pub struct Request<'a, 'b> {
    err: Option<ErrCode>,
    handle: &'a mut Handle,
    method: Method,
    headers: HashMap<String, Vec<String>>,
    body: Option<Body<'b>>,
    body_type: Option<BodyType>,
    content_type: bool, // whether or not the content type was set
    expect_continue: bool, // whether to expect a 100 continue from the server
    progress: Option<Box<ProgressCb<'b>>>,
    follow: bool,
}

enum BodyType {
    Fixed(usize),
    Chunked,
}

impl<'a, 'b> Request<'a, 'b> {
    pub fn new(handle: &'a mut Handle, method: Method) -> Request<'a, 'b> {
        Request {
            err: None,
            handle: handle,
            method: method,
            headers: HashMap::new(),
            body: None,
            body_type: None,
            content_type: false,
            expect_continue: false,
            progress: None,
            follow: false,
        }
    }

    pub fn uri<U: ToUrl>(mut self, uri: U) -> Request<'a, 'b> {
        uri.with_url_str(|s| {
            match self.handle.easy.setopt(opt::URL, s) {
                Ok(_) => {}
                Err(e) => self.err = Some(e)
            }
        });

        self
    }

    pub fn body<B: ToBody<'b>>(mut self, body: B) -> Request<'a, 'b> {
        self.body = Some(body.to_body());
        self
    }

    pub fn content_type(mut self, ty: &str) -> Request<'a, 'b> {
        if !self.content_type {
            self.content_type = true;
            append_header(&mut self.headers, "Content-Type", ty);
        }

        self
    }

    pub fn content_length(mut self, len: usize) -> Request<'a, 'b> {
        self.body_type = Some(Fixed(len));
        self
    }

    pub fn chunked(mut self) -> Request<'a, 'b> {
        self.body_type = Some(Chunked);
        self
    }

    pub fn expect_continue(mut self) -> Request<'a, 'b> {
        self.expect_continue = true;
        self
    }

    pub fn header(mut self, name: &str, val: &str) -> Request<'a, 'b> {
        append_header(&mut self.headers, name, val);
        self
    }

    pub fn get_header(&self, name: &str) -> Option<&[String]> {
        self.headers.get(name).map(|a| &a[..])
    }

    pub fn headers<'c, 'd, I: Iterator<Item=(&'c str, &'d str)>>(mut self, hdrs: I) -> Request<'a, 'b> {
        for (name, val) in hdrs {
            append_header(&mut self.headers, name, val);
        }

        self
    }

    pub fn progress<F>(mut self, cb: F) -> Request<'a, 'b>
        where F: FnMut(usize, usize, usize, usize) + 'b
    {
        self.progress = Some(Box::new(cb) as Box<ProgressCb<'b>>);
        self
    }

    pub fn follow_redirects(mut self, follow: bool) -> Request<'a, 'b> {
        self.follow = follow;
        self
    }

    pub fn exec(self) -> Result<Response, ErrCode> {
        // Deconstruct the struct
        let Request {
            err,
            handle,
            method,
            mut headers,
            mut body,
            body_type,
            content_type,
            expect_continue,
            progress,
            follow,
            ..
        } = self;

        if follow {
            try!(handle.easy.setopt(opt::FOLLOWLOCATION, 1));
        }

        match err {
            Some(e) => return Err(e),
            None => {}
        }

        // Clear custom headers set from the previous request
        try!(handle.easy.setopt(opt::HTTPHEADER, 0));

        match method {
            Get => try!(handle.easy.setopt(opt::HTTPGET, 1)),
            Head => try!(handle.easy.setopt(opt::NOBODY, 1)),
            Post => try!(handle.easy.setopt(opt::POST, 1)),
            Put => try!(handle.easy.setopt(opt::UPLOAD, 1)),
            Patch => {
                try!(handle.easy.setopt(opt::CUSTOMREQUEST, "PATCH"));
                try!(handle.easy.setopt(opt::UPLOAD, 1));
            },
            Delete => {
                if body.is_some() {
                    try!(handle.easy.setopt(opt::UPLOAD, 1));
                }

                try!(handle.easy.setopt(opt::CUSTOMREQUEST, "DELETE"));
            }
            _ => unimplemented!()
        }

        match body.as_ref() {
            None => {}
            Some(body) => {
                let body_type = body_type.unwrap_or(match body.get_size() {
                    Some(len) => Fixed(len),
                    None => Chunked,
                });

                match body_type {
                    Fixed(len) => {
                        match method {
                            Post => try!(handle.easy.setopt(opt::POSTFIELDSIZE, len)),
                            Put | Patch | Delete  => try!(handle.easy.setopt(opt::INFILESIZE, len)),
                            _ => {
                                append_header(&mut headers, "Content-Length",
                                              &len.to_string());
                            }
                        }
                    }
                    Chunked => {
                        append_header(&mut headers, "Transfer-Encoding",
                                      "chunked");
                    }

                }

                if !content_type {
                    append_header(&mut headers, "Content-Type", "application/octet-stream");
                }

                if !expect_continue {
                    append_header(&mut headers, "Expect", "");
                }
            }
        }

        let mut ffi_headers = ffi::List::new();

        if !headers.is_empty() {
            let mut buf = Vec::new();

            for (k, v) in headers.iter() {
                buf.extend(k.bytes());
                buf.extend(": ".bytes());

                for v in v.iter() {
                    buf.extend(v.bytes());
                    buf.push(0);
                    ffi_headers.push_bytes(&buf);
                    buf.truncate(k.len() + 2);
                }

                buf.truncate(0);
            }

            try!(handle.easy.setopt(opt::HTTPHEADER, &ffi_headers));
        }

        handle.easy.perform(body.as_mut(), progress)
    }
}

fn append_header(map: &mut HashMap<String, Vec<String>>, key: &str, val: &str) {
    match map.entry(key.to_string()) {
        Entry::Vacant(entry) => {
            let mut values = Vec::new();
            values.push(val.to_string());
            entry.insert(values)
        },
        Entry::Occupied(entry) => entry.into_mut()
    };
}

pub trait ToUrl{
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str);
}

impl<'a> ToUrl for &'a str {
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str) {
        f(self);
    }
}

impl<'a> ToUrl for &'a Url {
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str) {
        self.to_string().with_url_str(f);
    }
}

impl ToUrl for String {
    fn with_url_str<F>(self, f: F) where F: FnOnce(&str) {
        self[..].with_url_str(f);
    }
}

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

    #[test]
    fn get_header() {
        let mut h = Handle::new();
        let r = h.get("/foo").header("foo", "bar");
        assert_eq!(r.get_header("foo"), Some(&["bar".to_string()][..]));
    }
}
<|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, RequestExt, StatusCode};

use crate::middleware::normalize_path::OriginalPath;
use crate::middleware::response_timing::ResponseTime;
use std::cell::RefCell;
use std::fmt::{self, Display, Formatter};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

// A thread local is used instead of a request extension to avoid the need to pass the request
// object everywhere in the codebase. When migrating to async this will need to be moved to an
// async-equivalent, as thread locals misbehave in async contexes.
thread_local! {
    static CUSTOM_METADATA: RefCell<Vec<(&'static str, String)>> = RefCell::new(Vec::new());
}

#[derive(Default)]
pub(super) struct LogRequests();

impl Middleware for LogRequests {
    fn before(&self, _: &mut dyn RequestExt) -> BeforeResult {
        // Remove any metadata set by the previous task before processing any new request.
        CUSTOM_METADATA.with(|metadata| metadata.borrow_mut().clear());

        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        println!("{}", RequestLine { req, res: &res });

        res
    }
}

pub fn add_custom_metadata<V: Display>(key: &'static str, value: V) {
    CUSTOM_METADATA.with(|metadata| metadata.borrow_mut().push((key, value.to_string())));
    sentry::configure_scope(|scope| scope.set_extra(key, value.to_string().into()));
}

#[cfg(test)]
pub(crate) fn get_log_message(key: &'static str) -> String {
    CUSTOM_METADATA.with(|metadata| {
        for (k, v) in &*metadata.borrow() {
            if key == *k {
                return v.clone();
            }
        }
        panic!("expected log message for {} not found", key);
    })
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let status = self.res.as_ref().map(|res| res.status());
        let status = status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

        let at = if status.is_server_error() {
            "error"
        } else {
            "info"
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;

        let is_download_endpoint = self.req.path().ends_with("/download");

        // The request_id is not logged for successful download requests
        if !(is_download_endpoint && status.is_redirection()) {
            line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        }

        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;

        let response_time = self.req.extensions().get::<ResponseTime>();
        if let Some(response_time) = response_time {
            line.add_field("service", response_time)?;
        }
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        CUSTOM_METADATA.with(|metadata| {
            for (key, value) in &*metadata.borrow() {
                line.add_quoted_field(key, value)?;
            }
            fmt::Result::Ok(())
        })?;

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if let Some(response_time) = response_time {
            if response_time.as_millis() > SLOW_REQUEST_THRESHOLD_MS {
                line.add_marker("SLOW REQUEST")?;
            }
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let request = self.0;

        let original_path = request.extensions().get::<OriginalPath>();
        let path = original_path
            .map(|p| p.0.as_str())
            .unwrap_or_else(|| request.path());

        write!(f, "{}", path)?;

        if let Some(q_string) = request.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<commit_msg>middleware::log_request: Extract `is_download_redirect` variable<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;

use conduit::{header, RequestExt, StatusCode};

use crate::middleware::normalize_path::OriginalPath;
use crate::middleware::response_timing::ResponseTime;
use std::cell::RefCell;
use std::fmt::{self, Display, Formatter};

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

// A thread local is used instead of a request extension to avoid the need to pass the request
// object everywhere in the codebase. When migrating to async this will need to be moved to an
// async-equivalent, as thread locals misbehave in async contexes.
thread_local! {
    static CUSTOM_METADATA: RefCell<Vec<(&'static str, String)>> = RefCell::new(Vec::new());
}

#[derive(Default)]
pub(super) struct LogRequests();

impl Middleware for LogRequests {
    fn before(&self, _: &mut dyn RequestExt) -> BeforeResult {
        // Remove any metadata set by the previous task before processing any new request.
        CUSTOM_METADATA.with(|metadata| metadata.borrow_mut().clear());

        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        println!("{}", RequestLine { req, res: &res });

        res
    }
}

pub fn add_custom_metadata<V: Display>(key: &'static str, value: V) {
    CUSTOM_METADATA.with(|metadata| metadata.borrow_mut().push((key, value.to_string())));
    sentry::configure_scope(|scope| scope.set_extra(key, value.to_string().into()));
}

#[cfg(test)]
pub(crate) fn get_log_message(key: &'static str) -> String {
    CUSTOM_METADATA.with(|metadata| {
        for (k, v) in &*metadata.borrow() {
            if key == *k {
                return v.clone();
            }
        }
        panic!("expected log message for {} not found", key);
    })
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let status = self.res.as_ref().map(|res| res.status());
        let status = status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

        let at = if status.is_server_error() {
            "error"
        } else {
            "info"
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;

        let is_download_endpoint = self.req.path().ends_with("/download");
        let is_download_redirect = is_download_endpoint && status.is_redirection();

        // The request_id is not logged for successful download requests
        if !is_download_redirect {
            line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        }

        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;

        let response_time = self.req.extensions().get::<ResponseTime>();
        if let Some(response_time) = response_time {
            line.add_field("service", response_time)?;
        }
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        CUSTOM_METADATA.with(|metadata| {
            for (key, value) in &*metadata.borrow() {
                line.add_quoted_field(key, value)?;
            }
            fmt::Result::Ok(())
        })?;

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if let Some(response_time) = response_time {
            if response_time.as_millis() > SLOW_REQUEST_THRESHOLD_MS {
                line.add_marker("SLOW REQUEST")?;
            }
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let request = self.0;

        let original_path = request.extensions().get::<OriginalPath>();
        let path = original_path
            .map(|p| p.0.as_str())
            .unwrap_or_else(|| request.path());

        write!(f, "{}", path)?;

        if let Some(q_string) = request.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use juniper::{
    DefaultScalarValue, EmptyMutation, EmptySubscription, Object, ParseScalarResult,
    ParseScalarValue, RootNode, Value, Variables,
};

struct DefaultName(i32);
struct OtherOrder(i32);
struct Named(i32);
struct ScalarDescription(i32);

struct Root;

/*

Syntax to validate:

* Default name vs. custom name
* Description vs. no description on the scalar

*/

#[juniper::graphql_scalar]
impl<S> GraphQLScalar for DefaultName
where
    S: juniper::ScalarValue,
{
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &juniper::InputValue) -> Option<DefaultName> {
        v.as_scalar_value()
            .and_then(|s| s.as_int())
            .map(|i| DefaultName(i))
    }

    fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        <i32 as ParseScalarValue<S>>::from_str(value)
    }
}

#[juniper::graphql_scalar]
impl GraphQLScalar for OtherOrder {
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &juniper::InputValue) -> Option<OtherOrder> {
        v.as_scalar_value::<i32>().map(|i| OtherOrder(*i))
    }

    fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
        <i32 as ParseScalarValue>::from_str(value)
    }
}

#[juniper::graphql_scalar(name = "ANamedScalar")]
impl GraphQLScalar for Named {
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &juniper::InputValue) -> Option<Named> {
        v.as_scalar_value::<i32>().map(|i| Named(*i))
    }

    fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
        <i32 as ParseScalarValue>::from_str(value)
    }
}

#[juniper::graphql_scalar(description = "A sample scalar, represented as an integer")]
impl GraphQLScalar for ScalarDescription {
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &juniper::InputValue) -> Option<ScalarDescription> {
        v.as_scalar_value::<i32>().map(|i| ScalarDescription(*i))
    }

    fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
        <i32 as ParseScalarValue>::from_str(value)
    }
}

#[juniper::graphql_object]
impl Root {
    fn default_name() -> DefaultName {
        DefaultName(0)
    }
    fn other_order() -> OtherOrder {
        OtherOrder(0)
    }
    fn named() -> Named {
        Named(0)
    }
    fn scalar_description() -> ScalarDescription {
        ScalarDescription(0)
    }
}

async fn run_type_info_query<F>(doc: &str, f: F)
where
    F: Fn(&Object<DefaultScalarValue>) -> (),
{
    let schema = RootNode::new(
        Root {},
        EmptyMutation::<()>::new(),
        EmptySubscription::<()>::new(),
    );

    let (result, errs) = juniper::execute(doc, None, &schema, &Variables::new(), &())
        .await
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:#?}", result);

    let type_info = result
        .as_object_value()
        .expect("Result is not an object")
        .get_field_value("__type")
        .expect("__type field missing")
        .as_object_value()
        .expect("__type field not an object value");

    f(type_info);
}

#[test]
fn path_in_resolve_return_type() {
    struct ResolvePath(i32);

    #[juniper::graphql_scalar]
    impl GraphQLScalar for ResolvePath {
        fn resolve(&self) -> self::Value {
            Value::scalar(self.0)
        }

        fn from_input_value(v: &juniper::InputValue) -> Option<ResolvePath> {
            v.as_scalar_value::<i32>().map(|i| ResolvePath(*i))
        }

        fn from_str<'a>(
            value: juniper::ScalarToken<'a>,
        ) -> ParseScalarResult<'a, DefaultScalarValue> {
            <i32 as ParseScalarValue>::from_str(value)
        }
    }
}

#[tokio::test]
async fn default_name_introspection() {
    let doc = r#"
    {
        __type(name: "DefaultName") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("DefaultName"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::null())
        );
    })
    .await;
}

#[tokio::test]
async fn other_order_introspection() {
    let doc = r#"
    {
        __type(name: "OtherOrder") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("OtherOrder"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::null())
        );
    })
    .await;
}

#[tokio::test]
async fn named_introspection() {
    let doc = r#"
    {
        __type(name: "ANamedScalar") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("ANamedScalar"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::null())
        );
    })
    .await;
}

#[tokio::test]
async fn scalar_description_introspection() {
    let doc = r#"
    {
        __type(name: "ScalarDescription") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("ScalarDescription"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::scalar("A sample scalar, represented as an integer"))
        );
    })
    .await;
}
<commit_msg>Test GraphQL scalar implementation using custom ScalarValue (#791)<commit_after>use juniper::{
    execute, graphql_object, graphql_scalar, graphql_value, DefaultScalarValue, EmptyMutation,
    EmptySubscription, Object, ParseScalarResult, ParseScalarValue, RootNode, Value, Variables,
};

use crate::custom_scalar::MyScalarValue;

struct DefaultName(i32);
struct OtherOrder(i32);
struct Named(i32);
struct ScalarDescription(i32);

struct Root;

/*

Syntax to validate:

* Default name vs. custom name
* Description vs. no description on the scalar

*/

#[graphql_scalar]
impl<S> GraphQLScalar for DefaultName
where
    S: ScalarValue,
{
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &InputValue) -> Option<DefaultName> {
        v.as_scalar_value()
            .and_then(|s| s.as_int())
            .map(|i| DefaultName(i))
    }

    fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
        <i32 as ParseScalarValue<S>>::from_str(value)
    }
}

#[graphql_scalar]
impl GraphQLScalar for OtherOrder {
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &InputValue) -> Option<OtherOrder> {
        v.as_scalar_value::<i32>().map(|i| OtherOrder(*i))
    }

    fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
        <i32 as ParseScalarValue>::from_str(value)
    }
}

#[graphql_scalar(name = "ANamedScalar")]
impl GraphQLScalar for Named {
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &InputValue) -> Option<Named> {
        v.as_scalar_value::<i32>().map(|i| Named(*i))
    }

    fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
        <i32 as ParseScalarValue>::from_str(value)
    }
}

#[graphql_scalar(description = "A sample scalar, represented as an integer")]
impl GraphQLScalar for ScalarDescription {
    fn resolve(&self) -> Value {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &InputValue) -> Option<ScalarDescription> {
        v.as_scalar_value::<i32>().map(|i| ScalarDescription(*i))
    }

    fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
        <i32 as ParseScalarValue>::from_str(value)
    }
}

#[graphql_object]
impl Root {
    fn default_name() -> DefaultName {
        DefaultName(0)
    }
    fn other_order() -> OtherOrder {
        OtherOrder(0)
    }
    fn named() -> Named {
        Named(0)
    }
    fn scalar_description() -> ScalarDescription {
        ScalarDescription(0)
    }
}

struct WithCustomScalarValue(i32);

#[graphql_scalar]
impl GraphQLScalar for WithCustomScalarValue {
    fn resolve(&self) -> Value<MyScalarValue> {
        Value::scalar(self.0)
    }

    fn from_input_value(v: &InputValue<MyScalarValue>) -> Option<WithCustomScalarValue> {
        v.as_scalar_value::<i32>()
            .map(|i| WithCustomScalarValue(*i))
    }

    fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, MyScalarValue> {
        <i32 as ParseScalarValue<MyScalarValue>>::from_str(value)
    }
}

struct RootWithCustomScalarValue;

#[graphql_object(scalar = MyScalarValue)]
impl RootWithCustomScalarValue {
    fn with_custom_scalar_value() -> WithCustomScalarValue {
        WithCustomScalarValue(0)
    }
}

async fn run_type_info_query<F>(doc: &str, f: F)
where
    F: Fn(&Object<DefaultScalarValue>) -> (),
{
    let schema = RootNode::new(
        Root {},
        EmptyMutation::<()>::new(),
        EmptySubscription::<()>::new(),
    );

    let (result, errs) = execute(doc, None, &schema, &Variables::new(), &())
        .await
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:#?}", result);

    let type_info = result
        .as_object_value()
        .expect("Result is not an object")
        .get_field_value("__type")
        .expect("__type field missing")
        .as_object_value()
        .expect("__type field not an object value");

    f(type_info);
}

#[test]
fn path_in_resolve_return_type() {
    struct ResolvePath(i32);

    #[graphql_scalar]
    impl GraphQLScalar for ResolvePath {
        fn resolve(&self) -> self::Value {
            Value::scalar(self.0)
        }

        fn from_input_value(v: &InputValue) -> Option<ResolvePath> {
            v.as_scalar_value::<i32>().map(|i| ResolvePath(*i))
        }

        fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
            <i32 as ParseScalarValue>::from_str(value)
        }
    }
}

#[tokio::test]
async fn default_name_introspection() {
    let doc = r#"
    {
        __type(name: "DefaultName") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("DefaultName"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::null())
        );
    })
    .await;
}

#[tokio::test]
async fn other_order_introspection() {
    let doc = r#"
    {
        __type(name: "OtherOrder") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("OtherOrder"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::null())
        );
    })
    .await;
}

#[tokio::test]
async fn named_introspection() {
    let doc = r#"
    {
        __type(name: "ANamedScalar") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("ANamedScalar"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::null())
        );
    })
    .await;
}

#[tokio::test]
async fn scalar_description_introspection() {
    let doc = r#"
    {
        __type(name: "ScalarDescription") {
            name
            description
        }
    }
    "#;

    run_type_info_query(doc, |type_info| {
        assert_eq!(
            type_info.get_field_value("name"),
            Some(&Value::scalar("ScalarDescription"))
        );
        assert_eq!(
            type_info.get_field_value("description"),
            Some(&Value::scalar("A sample scalar, represented as an integer"))
        );
    })
    .await;
}

#[tokio::test]
async fn resolves_with_custom_scalar_value() {
    const DOC: &str = r#"{ withCustomScalarValue }"#;

    let schema = RootNode::<_, _, _, MyScalarValue>::new(
        RootWithCustomScalarValue,
        EmptyMutation::<()>::new(),
        EmptySubscription::<()>::new(),
    );

    assert_eq!(
        execute(DOC, None, &schema, &Variables::new(), &()).await,
        Ok((graphql_value!({"withCustomScalarValue": 0}), vec![])),
    );
}
<|endoftext|>


<commit_before>//! Timer emulation

/// Timer state
pub struct Timer {
    /// Timer counter. Generates an interrupt on overflow.
    counter: u8,
    /// Timer modulo: on overflow `counter` gets reloaded with that
    /// value.
    modulo: u8,
    /// If true timer is counting and generating interrupts
    enabled: bool,
    /// System clock divider. When `enabled`, at each tick of the
    /// divider clock `counter` is incremented.
    divider: Divider,
    /// Free-running internal counter simulating the sysclk
    clk: u32,
    /// Free-running counter at sysclk/256. I need a separate counter
    /// because that one can be reset
    counter_16k: u32,
    /// True if interrupt is pending
    interrupt: bool,
}

impl Timer {
    pub fn new() -> Timer {
        Timer {
            counter:     0,
            modulo:      0,
            enabled:     false,
            divider:     Divider::Div1024,
            clk:         0,
            counter_16k: 0,
            interrupt:   false,
        }
    }

    pub fn step(&mut self) {
        self.clk         += 1;
        self.counter_16k += 1;

        if !self.enabled {
            return;
        }

        let mask = (1 << (self.divider as usize)) - 1;

        if self.clk & mask == 0 {
            // Divided clock ticked, increment counter
            self.counter += 1;

            if self.counter == 0 {
                // Timer overflowed.
                self.interrupt = true;
                self.counter = self.modulo;
            }
        }
    }

    /// Return current counter value
    pub fn counter(&self) -> u8 {
        self.counter
    }

    /// Reset counter value
    pub fn set_counter(&mut self, counter: u8) {
        self.counter = counter;
    }

    /// Get value of "DIV" register. It contains a free running
    /// counter of SysClk / 256 -> 16.384kHz
    pub fn div(&self) -> u8 {
        (self.counter_16k >> 8) as u8
    }

    /// Reset 16.384kHz counter to 0
    pub fn reset_div(&mut self) {
        self.counter_16k = 0;
    }

    /// Return the current value of the `modulo`
    pub fn modulo(&self) -> u8 {
        self.modulo
    }

    /// Set the value loaded into the counter when it overflows.
    pub fn set_modulo(&mut self, modulo: u8) {
        self.modulo = modulo;
    }

    /// Configure the timer using values specified in the config register
    pub fn set_config(&mut self, cfg: u8) {
        self.enabled = cfg & 4 != 0;

        self.divider = match cfg & 3 {
            0 => Divider::Div1024,
            1 => Divider::Div16,
            2 => Divider::Div64,
            3 => Divider::Div256,
            _ => unreachable!(),
        };
    }

    /// Return configuration register value
    pub fn config(&self) -> u8 {
        let mut r = 0;

        r |= (self.enabled as u8) << 2;
        r |= self.divider as u8;

        r
    }

    /// Return interrupt status
    pub fn interrupt(&self) -> bool {
        self.interrupt
    }

    /// Acknowledge interrupt
    pub fn ack_interrupt(&mut self) {
        self.interrupt = false;
    }

    /// Force interrupt state
    pub fn force_interrupt(&mut self, set: bool) {
        self.interrupt = set;
    }
}

/// Possible divider values usable as timer clock source.
#[derive(Copy)]
enum Divider {
    /// Divide sysclk by 16. Timer clock is 262.144kHz
    Div16   = 4,
    /// Divide sysclk by 64. Timer clock is 65.536kHz
    Div64   = 6,
    /// Divide sysclk by 256. Timer clock is 16.384kHz
    Div256  = 8,
    /// Divide sysclk by 1024. Timer clock is 4.096kHz
    Div1024 = 12,
}
<commit_msg>Simplified timer code and hopefully made it more accurate<commit_after>//! Timer emulation

/// Timer state
pub struct Timer {
    /// Timer counter. Generates an interrupt on overflow.
    counter: u8,
    /// Timer modulo: on overflow `counter` gets reloaded with that
    /// value.
    modulo: u8,
    /// If true timer is counting and generating interrupts
    enabled: bool,
    /// System clock divider. When `enabled`, at each tick of the
    /// divider clock `counter` is incremented.
    divider: Divider,
    /// Free-running counter used as a divider for the sysclk
    counter_16k: u32,
    /// True if interrupt is pending
    interrupt: bool,
}

impl Timer {
    pub fn new() -> Timer {
        Timer {
            counter:     0,
            modulo:      0,
            enabled:     false,
            divider:     Divider::Div1024,
            counter_16k: 0,
            interrupt:   false,
        }
    }

    pub fn step(&mut self) {
        self.counter_16k += 1;

        if !self.enabled {
            return;
        }

        let mask = (1 << (self.divider as usize)) - 1;

        if self.counter_16k & mask == 0 {
            // Divided clock ticked, increment counter
            self.counter += 1;

            if self.counter == 0 {
                // Timer overflowed.
                self.interrupt = true;
                self.counter = self.modulo;
            }
        }
    }

    /// Return current counter value
    pub fn counter(&self) -> u8 {
        self.counter
    }

    /// Reset counter value
    pub fn set_counter(&mut self, counter: u8) {
        self.counter = counter;
    }

    /// Get value of "DIV" register. It contains a free running
    /// counter of SysClk / 256 -> 16.384kHz
    pub fn div(&self) -> u8 {
        (self.counter_16k >> 8) as u8
    }

    /// Reset 16.384kHz counter to 0
    pub fn reset_div(&mut self) {
        self.counter_16k = 0;
    }

    /// Return the current value of the `modulo`
    pub fn modulo(&self) -> u8 {
        self.modulo
    }

    /// Set the value loaded into the counter when it overflows.
    pub fn set_modulo(&mut self, modulo: u8) {
        self.modulo = modulo;
    }

    /// Configure the timer using values specified in the config register
    pub fn set_config(&mut self, cfg: u8) {
        self.enabled = cfg & 4 != 0;

        self.divider = match cfg & 3 {
            0 => Divider::Div1024,
            1 => Divider::Div16,
            2 => Divider::Div64,
            3 => Divider::Div256,
            _ => unreachable!(),
        };
    }

    /// Return configuration register value
    pub fn config(&self) -> u8 {
        let mut r = 0;

        r |= (self.enabled as u8) << 2;
        r |= self.divider as u8;

        r
    }

    /// Return interrupt status
    pub fn interrupt(&self) -> bool {
        self.interrupt
    }

    /// Acknowledge interrupt
    pub fn ack_interrupt(&mut self) {
        self.interrupt = false;
    }

    /// Force interrupt state
    pub fn force_interrupt(&mut self, set: bool) {
        self.interrupt = set;
    }
}

/// Possible divider values usable as timer clock source.
#[derive(Copy)]
enum Divider {
    /// Divide sysclk by 16. Timer clock is 262.144kHz
    Div16   = 4,
    /// Divide sysclk by 64. Timer clock is 65.536kHz
    Div64   = 6,
    /// Divide sysclk by 256. Timer clock is 16.384kHz
    Div256  = 8,
    /// Divide sysclk by 1024. Timer clock is 4.096kHz
    Div1024 = 12,
}
<|endoftext|>


<commit_before>//! Implement sink for .sdc.

use std::io::Write;

use sdc;

use Result;
use error::Error;
use point::{FromPoint, Point};
use sink::Sink;

impl<W: Write> Sink for sdc::Writer<W> {
    fn sink<P: Point>(&mut self, point: &P) -> Result<()> {
        try!(self.write_point(&try!(sdc::Point::from_point(point))));
        Ok(())
    }
}

impl FromPoint for sdc::Point {
    fn from_point<P: Point>(point: &P) -> Result<sdc::Point> {
        Ok(sdc::Point {
            time: try!(point.gps_time().ok_or(Error::MissingDimension("time".to_string()))),
            range: point.range().unwrap_or_else(|| (point.x().powi(2) + point.y().powi(2) + point.z().powi(2)).sqrt()) as f32,
            theta: try!(point.scan_angle()
                        .ok_or(Error::MissingDimension("scan angle".to_string()))) as f32,
            x: point.x() as f32,
            y: point.y() as f32,
            z: point.z() as f32,
            amplitude: point.intensity().as_u16(),
            width: point.width().unwrap_or(0.0) as u16,
            target: point.return_number().unwrap_or(0) as u8,
            num_target: point.number_of_returns().unwrap_or(0) as u8,
            rg_index: point.rg_index().unwrap_or(0.0) as u16,
            target_type: try!(sdc::TargetType::from_u8(point.target_type().unwrap_or(3))),
            facet_number: point.facet_number().unwrap_or(0),
            high_channel: point.high_channel().unwrap_or(false),
        })
    }
}

#[cfg(test)]
mod tests {
    use std::fs::remove_file;

    use las;
    use sdc;

    use source::Source;
    use sink::Sink;

    #[test]
    fn sink_las() {
        let mut source = las::Stream::from_path("data/1.0_1.las").unwrap();
        {
            let mut sink = sdc::Writer::from_path("temp.sdc").unwrap();
            for ref point in source.source_to_end(100).unwrap() {
                sink.sink(point).unwrap();
            }
        }
        let mut source = sdc::Reader::from_path("temp.sdc").unwrap();
        let points = source.source_to_end(100).unwrap();
        assert_eq!(1, points.len());
        remove_file("temp.sdc").unwrap();
    }
}
<commit_msg>Update for the new sdc fields<commit_after>//! Implement sink for .sdc.

use std::io::Write;

use sdc;

use Result;
use error::Error;
use point::{FromPoint, Point};
use sink::Sink;

impl<W: Write> Sink for sdc::Writer<W> {
    fn sink<P: Point>(&mut self, point: &P) -> Result<()> {
        try!(self.write_point(&try!(sdc::Point::from_point(point))));
        Ok(())
    }
}

impl FromPoint for sdc::Point {
    fn from_point<P: Point>(point: &P) -> Result<sdc::Point> {
        Ok(sdc::Point {
            time: try!(point.gps_time().ok_or(Error::MissingDimension("time".to_string()))),
            range: point.range().unwrap_or_else(|| (point.x().powi(2) + point.y().powi(2) + point.z().powi(2)).sqrt()) as f32,
            theta: try!(point.scan_angle()
                        .ok_or(Error::MissingDimension("scan angle".to_string()))) as f32,
            x: point.x() as f32,
            y: point.y() as f32,
            z: point.z() as f32,
            amplitude: point.intensity().as_u16(),
            width: point.width().unwrap_or(0.0) as u16,
            target: point.return_number().unwrap_or(0) as u8,
            num_target: point.number_of_returns().unwrap_or(0) as u8,
            rg_index: point.rg_index().unwrap_or(0.0) as u16,
            target_type: try!(sdc::TargetType::from_u8(point.target_type().unwrap_or(3))),
            facet_number: point.facet_number().unwrap_or(0),
            high_channel: point.high_channel().unwrap_or(false),
            class_id: Some(point.classification()),
            rho: None,
            reflectance: None,
        })
    }
}

#[cfg(test)]
mod tests {
    use std::fs::remove_file;

    use las;
    use sdc;

    use source::Source;
    use sink::Sink;

    #[test]
    fn sink_las() {
        let mut source = las::Stream::from_path("data/1.0_1.las").unwrap();
        {
            let mut sink = sdc::Writer::from_path("temp.sdc").unwrap();
            for ref point in source.source_to_end(100).unwrap() {
                sink.sink(point).unwrap();
            }
        }
        let mut source = sdc::Reader::from_path("temp.sdc").unwrap();
        let points = source.source_to_end(100).unwrap();
        assert_eq!(1, points.len());
        remove_file("temp.sdc").unwrap();
    }
}
<|endoftext|>


<commit_before>use model::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// **Note**: Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// **Note**: Requires the [Read Message History] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<EmojiId> for ReactionType {
    fn from(emoji_id: EmojiId) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id,
            name: None
        }
    }
}

impl From<EmojiIdentifier> for ReactionType {
    fn from(emoji_id: EmojiIdentifier) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id.id,
            name: Some(emoji_id.name)
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<commit_msg>Add a method to get a message from a reaction (#220)<commit_after>use model::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// **Note**: Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// **Note**: Requires the [Read Message History] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }

    /// Retrieves the [`Message`] associated with this reaction.
    ///
    /// Requires the [Read Message History] permission.
    ///
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [`Message`]: struct.Message.html
    pub fn message(&self) -> Result<Message> {
        self.channel_id.message(self.message_id)
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<EmojiId> for ReactionType {
    fn from(emoji_id: EmojiId) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id,
            name: None
        }
    }
}

impl From<EmojiIdentifier> for ReactionType {
    fn from(emoji_id: EmojiIdentifier) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id.id,
            name: Some(emoji_id.name)
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<|endoftext|>