<commit_before>// Copyright (c) 2014-2016 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Interface listing implementation for all non-Windows platforms

use std::mem;
use std::ffi::{CStr, CString};
use std::str::from_utf8_unchecked;
use std::net::IpAddr;

use libc;

use util::MacAddr;
use datalink::NetworkInterface;

use internal;

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac,
        };
        match (&mut old.ips, &new.ips) {
            (&mut Some(ref mut old_ips), &Some(ref new_ips)) => {
                old_ips.extend_from_slice(&new_ips[..])
            }
            (&mut ref mut old_ips @ None, &Some(ref new_ips)) => *old_ips = Some(new_ips.clone()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while !addr.is_null() {
            let c_str = (*addr).ifa_name as *const i8;
            let bytes = CStr::from_ptr(c_str).to_bytes();
            let name = from_utf8_unchecked(bytes).to_owned();
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| [ip].to_vec()),
                flags: (*addr).ifa_flags,
            };
            let mut found: bool = false;
            for iface in &mut ifaces {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in &mut ifaces {
            let name = CString::new(iface.name.as_bytes());
            iface.index = libc::if_nametoindex(name.unwrap().as_ptr());
        }

        ifaces
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0],
                              (*sll).sll_addr[1],
                              (*sll).sll_addr[2],
                              (*sll).sll_addr[3],
                              (*sll).sll_addr[4],
                              (*sll).sll_addr[5]);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<libc::sockaddr_storage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as usize;
            let mac = MacAddr((*sdl).sdl_data[nlen] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<libc::sockaddr_storage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}
<commit_msg>Auto merge of #212 - rschifflin:patch-1, r=mrmonday<commit_after>// Copyright (c) 2014-2016 Robert Clipsham <robert@octarineparrot.com>
//
// 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.

//! Interface listing implementation for all non-Windows platforms

use std::mem;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::str::from_utf8_unchecked;
use std::net::IpAddr;
use libc;

use util::MacAddr;
use datalink::NetworkInterface;

use internal;

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac,
        };
        match (&mut old.ips, &new.ips) {
            (&mut Some(ref mut old_ips), &Some(ref new_ips)) => {
                old_ips.extend_from_slice(&new_ips[..])
            }
            (&mut ref mut old_ips @ None, &Some(ref new_ips)) => *old_ips = Some(new_ips.clone()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while !addr.is_null() {
            let c_str = (*addr).ifa_name as *const c_char;
            let bytes = CStr::from_ptr(c_str).to_bytes();
            let name = from_utf8_unchecked(bytes).to_owned();
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| [ip].to_vec()),
                flags: (*addr).ifa_flags,
            };
            let mut found: bool = false;
            for iface in &mut ifaces {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in &mut ifaces {
            let name = CString::new(iface.name.as_bytes());
            iface.index = libc::if_nametoindex(name.unwrap().as_ptr());
        }

        ifaces
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0],
                              (*sll).sll_addr[1],
                              (*sll).sll_addr[2],
                              (*sll).sll_addr[3],
                              (*sll).sll_addr[4],
                              (*sll).sll_addr[5]);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<libc::sockaddr_storage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    use std::net::SocketAddr;

    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as usize;
            let mac = MacAddr((*sdl).sdl_data[nlen] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8);

            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                                  mem::size_of::<libc::sockaddr_storage>());

            match addr {
                Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
                Ok(SocketAddr::V6(sa)) => (None, Some(IpAddr::V6(*sa.ip()))),
                Err(_) => (None, None),
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Abstract Factory Design Pattern
 * http://joshldavis.com/rust-design-patterns/abstract-factory/
 */

/*
 * Core Trait that defines a Phone
 */
trait Phone {
    fn call(&self);
}

/*
 * Core Trait that defines a Tablet
 */
trait Tablet {
    fn play_games(&self);
}

/*
 * Core Trait that defines a Factory
 */
trait Factory {
    fn new_phone<T: Phone>(&self) -> T;
    fn new_tablet<T: Tablet>(&self) -> T;
}

/*
 * Define our Apple products. Normally these structs would contain a lot more
 * data.
 */
struct iPhone;

impl Phone for iPhone {
    fn call(&self) {
        println("Look! I'm calling on an iPhone!");
    }
}

struct iPad;

impl Tablet for iPad {
    fn play_games(&self) {
        println("Just playing some games on my iPad.");
    }
}

/*
 * This would contain all stuff required to make Apple devices.
 */
struct AppleFactory;

impl Factory for AppleFactory {
    fn new_phone<T: Phone>(&self) -> T {
        return iPhone;
    }

    fn new_tablet<T: Tablet>(&self) -> T {
        return iPad;
    }
}

/*
 * Define our Google products. Like with Apple's products, these are
 * simplified.
 */

struct Nexus4;

impl Phone for Nexus4 {
    fn call(&self) {
        println("Look! I'm calling on a Nexus 4!");
    }
}

struct Nexus10;

impl Tablet for Nexus10 {
    fn play_games(&self) {
        println("Just playing some games on my Nexus 10.");
    }
}

/*
 * This would contain all stuff required to make Google devices.
 */
struct GoogleFactory;

impl Factory for GoogleFactory {
    fn new_phone<T: Phone>(&self) -> T {
        return Nexus4;
    }

    fn new_tablet<T: Tablet>(&self) -> T {
        return Nexus10;
    }
}

fn main() {

}
<commit_msg>Fix up examples, add main function<commit_after>/*
 * Abstract Factory Design Pattern
 * http://joshldavis.com/rust-design-patterns/abstract-factory/
 */

/*
 * Core Trait that defines a Phone
 */
trait Phone {
    fn call(&self);
}

/*
 * Core Trait that defines a Tablet
 */
trait Tablet {
    fn play_games(&self);
}

/*
 * Core Trait that defines a Factory
 */
trait Factory<P: Phone, T: Tablet> {
    fn new_phone(&self) -> P;
    fn new_tablet(&self) -> T;
}

/*
 * Define our Apple products. Normally these structs would contain a lot more
 * data.
 */
struct iPhone;

impl Phone for iPhone {
    fn call(&self) {
        println("Look! I'm calling on an iPhone!");
    }
}

struct iPad;

impl Tablet for iPad {
    fn play_games(&self) {
        println("Just playing some games on my iPad.");
    }
}

/*
 * This would contain all stuff required to make Apple devices.
 */
struct AppleFactory;

impl Factory<iPhone, iPad> for AppleFactory {
    fn new_phone(&self) -> iPhone {
        return iPhone;
    }

    fn new_tablet(&self) -> iPad {
        return iPad;
    }
}

/*
 * Define our Google products. Like with Apple's products, these are
 * simplified.
 */

struct Nexus4;

impl Phone for Nexus4 {
    fn call(&self) {
        println("Look! I'm calling on a Nexus 4!");
    }
}

struct Nexus10;

impl Tablet for Nexus10 {
    fn play_games(&self) {
        println("Just playing some games on my Nexus 10.");
    }
}

/*
 * This would contain all stuff required to make Google devices.
 */
struct GoogleFactory;

impl Factory<Nexus4, Nexus10> for GoogleFactory {
    fn new_phone(&self) -> Nexus4 {
        return Nexus4;
    }

    fn new_tablet(&self) -> Nexus10 {
        return Nexus10;
    }
}

fn main() {
    let google = AppleFactory;
    let apple = GoogleFactory;

    let phone = apple.new_phone();
    phone.call();

    let phone = google.new_phone();
    phone.call();

    let tablet = apple.new_tablet();
    tablet.play_games();

    let tablet = google.new_tablet();
    tablet.play_games();
}
<|endoftext|>


<commit_before>use std::f64;
use rand::Rng;
use {Result, StatsError};

/// Implements the [Categorical](https://en.wikipedia.org/wiki/Categorical_distribution)
/// distribution, also known as the generalized Bernoulli or discrete distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Categorical, Discrete};
/// use statrs::statistics::Mode;
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Categorical<R>
    where R: Rng
{
    norm_pmf: Vec<f64>,
    cdf: Vec<f64>,
    r: R,
}

impl<R> Categorical<R>
    where R: Rng
{
    pub fn new(prob_mass: &[f64], r: R) -> Result<Categorical<R>>
        where R: Rng
    {
        if !is_valid_prob_mass(prob_mass) {
            Err(StatsError::BadParams)
        } else {
            // extract un-normalized cdf
            let mut cdf = vec![0.0; prob_mass.len()];
            cdf[0] = prob_mass[0];
            for i in 1..prob_mass.len() {
                unsafe {
                    let val = cdf.get_unchecked(i - 1) + prob_mass.get_unchecked(i);
                    let elem = cdf.get_unchecked_mut(i);
                    *elem = val;
                }
            }

            // extract normalized probability mass
            let sum = cdf[cdf.len() - 1];
            let mut norm_pmf = vec![0.0; prob_mass.len()];
            for i in 0..prob_mass.len() {
                unsafe {
                    let elem = norm_pmf.get_unchecked_mut(i);
                    *elem = prob_mass.get_unchecked(i) / sum;
                }
            }
            Ok(Categorical {
                norm_pmf: norm_pmf,
                cdf: cdf,
                r: r,
            })
        }
    }
}

// determines if `p` is a valid probability mass array
// for the Categorical distribution
fn is_valid_prob_mass(p: &[f64]) -> bool {
    !p.iter().any(|&x| x < 0.0 || x.is_nan()) && !p.iter().all(|&x| x == 0.0)
}

#[test]
fn test_is_valid_prob_mass() {
    let invalid = [1.0, f64::NAN, 3.0];
    assert!(!is_valid_prob_mass(&invalid));
    let invalid2 = [-2.0, 5.0, 1.0, 6.2];
    assert!(!is_valid_prob_mass(&invalid2));
    let invalid3 = [0.0, 0.0, 0.0];
    assert!(!is_valid_prob_mass(&invalid3));
    let invalid4: [f64; 0] = [];
    assert!(!is_valid_prob_mass(&invalid4));
    let valid = [5.2, 0.00001, 1e-15, 1000000.12];
    assert!(is_valid_prob_mass(&valid));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use rand::StdRng;
    use distribution::Categorical;

    fn try_create(prob_mass: &[f64]) -> Categorical<StdRng> {
        let r = StdRng::new().unwrap();
        let n = Categorical::new(prob_mass, r);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(prob_mass: &[f64]) {
        try_create(prob_mass);
    }

    fn bad_create_case(prob_mass: &[f64]) {
        let r = StdRng::new().unwrap();
        let n = Categorical::new(prob_mass, r);
        assert!(n.is_err());
    }

    #[test]
    fn test_create() {
        create_case(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(&[-1.0, 1.0]);
        bad_create_case(&[0.0, 0.0]);
    }
}<commit_msg>feat: categorical sampling implemented<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Distribution};
use {Result, StatsError};

/// Implements the [Categorical](https://en.wikipedia.org/wiki/Categorical_distribution)
/// distribution, also known as the generalized Bernoulli or discrete distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Categorical, Discrete};
/// use statrs::statistics::Mode;
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Categorical
{
    norm_pmf: Vec<f64>,
    cdf: Vec<f64>,
}

impl Categorical
{
    pub fn new(prob_mass: &[f64]) -> Result<Categorical>
    {
        if !is_valid_prob_mass(prob_mass) {
            Err(StatsError::BadParams)
        } else {
            // extract un-normalized cdf
            let mut cdf = vec![0.0; prob_mass.len()];
            cdf[0] = prob_mass[0];
            for i in 1..prob_mass.len() {
                unsafe {
                    let val = cdf.get_unchecked(i - 1) + prob_mass.get_unchecked(i);
                    let elem = cdf.get_unchecked_mut(i);
                    *elem = val;
                }
            }

            // extract normalized probability mass
            let sum = cdf[cdf.len() - 1];
            let mut norm_pmf = vec![0.0; prob_mass.len()];
            for i in 0..prob_mass.len() {
                unsafe {
                    let elem = norm_pmf.get_unchecked_mut(i);
                    *elem = prob_mass.get_unchecked(i) / sum;
                }
            }
            Ok(Categorical {
                norm_pmf: norm_pmf,
                cdf: cdf,
            })
        }
    }
}

impl Sample<f64> for Categorical
{
    /// Generate a random sample from a categorical
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Categorical
{
    /// Generate a random independent sample from a categorical
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Categorical
{
    /// Generate a random sample from the categorical distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Categorical, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Categorical::new(&[1.0, 2.0, 3.0]).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let draw = r.next_f64() * unsafe { self.cdf.get_unchecked(self.cdf.len() - 1) };
        let mut idx = 0;

        if draw == 0.0 {
            // skip zero-probability categories
            let mut el = unsafe { self.cdf.get_unchecked(idx) };
            while *el == 0.0 {
                // don't need bounds checking because we do not allow
                // creating Categorical distributions with all 0.0 probs
                idx += 1;
                el = unsafe { self.cdf.get_unchecked(idx) }
            }
        }
        let mut el = unsafe { self.cdf.get_unchecked(idx) };
        while draw > *el {
            idx += 1;
            el = unsafe { self.cdf.get_unchecked(idx) };
        }
        return idx as f64;
    }
}

// determines if `p` is a valid probability mass array
// for the Categorical distribution
fn is_valid_prob_mass(p: &[f64]) -> bool {
    !p.iter().any(|&x| x < 0.0 || x.is_nan()) && !p.iter().all(|&x| x == 0.0)
}

#[test]
fn test_is_valid_prob_mass() {
    let invalid = [1.0, f64::NAN, 3.0];
    assert!(!is_valid_prob_mass(&invalid));
    let invalid2 = [-2.0, 5.0, 1.0, 6.2];
    assert!(!is_valid_prob_mass(&invalid2));
    let invalid3 = [0.0, 0.0, 0.0];
    assert!(!is_valid_prob_mass(&invalid3));
    let invalid4: [f64; 0] = [];
    assert!(!is_valid_prob_mass(&invalid4));
    let valid = [5.2, 0.00001, 1e-15, 1000000.12];
    assert!(is_valid_prob_mass(&valid));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use distribution::Categorical;

    fn try_create(prob_mass: &[f64]) -> Categorical {
        let n = Categorical::new(prob_mass);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(prob_mass: &[f64]) {
        try_create(prob_mass);
    }

    fn bad_create_case(prob_mass: &[f64]) {
        let n = Categorical::new(prob_mass);
        assert!(n.is_err());
    }

    #[test]
    fn test_create() {
        create_case(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(&[-1.0, 1.0]);
        bad_create_case(&[0.0, 0.0]);
    }
}<|endoftext|>


<commit_before>//! Module contianing the core functionality for OAuth2 Authentication.
use crate::authenticator_delegate::{DeviceFlowDelegate, InstalledFlowDelegate};
use crate::device::DeviceFlow;
use crate::error::Error;
use crate::installed::{InstalledFlow, InstalledFlowReturnMethod};
use crate::refresh::RefreshFlow;
use crate::service_account::{ServiceAccountFlow, ServiceAccountFlowOpts, ServiceAccountKey};
use crate::storage::{self, Storage};
use crate::types::{AccessToken, ApplicationSecret, TokenInfo};
use private::AuthFlow;

use std::borrow::Cow;
use std::fmt;
use std::io;
use std::path::PathBuf;
use std::sync::Mutex;

/// Authenticator is responsible for fetching tokens, handling refreshing tokens,
/// and optionally persisting tokens to disk.
pub struct Authenticator<C> {
    hyper_client: hyper::Client<C>,
    storage: Storage,
    auth_flow: AuthFlow,
}

struct DisplayScopes<'a, T>(&'a [T]);
impl<'a, T> fmt::Display for DisplayScopes<'a, T>
where
    T: AsRef<str>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("[")?;
        let mut iter = self.0.iter();
        if let Some(first) = iter.next() {
            f.write_str(first.as_ref())?;
            for scope in iter {
                f.write_str(", ")?;
                f.write_str(scope.as_ref())?;
            }
        }
        f.write_str("]")
    }
}

impl<C> Authenticator<C>
where
    C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
{
    /// Return the current token for the provided scopes.
    pub async fn token<'a, T>(&'a self, scopes: &'a [T]) -> Result<AccessToken, Error>
    where
        T: AsRef<str>,
    {
        log::debug!(
            "access token requested for scopes: {}",
            DisplayScopes(scopes)
        );
        let hashed_scopes = storage::ScopeSet::from(scopes);
        match (self.storage.get(hashed_scopes), self.auth_flow.app_secret()) {
            (Some(t), _) if !t.is_expired() => {
                // unexpired token found
                log::debug!("found valid token in cache: {:?}", t);
                Ok(t.into())
            }
            (
                Some(TokenInfo {
                    refresh_token: Some(refresh_token),
                    ..
                }),
                Some(app_secret),
            ) => {
                // token is expired but has a refresh token.
                let token_info =
                    RefreshFlow::refresh_token(&self.hyper_client, app_secret, &refresh_token)
                        .await?;
                self.storage.set(hashed_scopes, token_info.clone()).await?;
                Ok(token_info.into())
            }
            _ => {
                // no token in the cache or the token returned can't be refreshed.
                let token_info = self.auth_flow.token(&self.hyper_client, scopes).await?;
                self.storage.set(hashed_scopes, token_info.clone()).await?;
                Ok(token_info.into())
            }
        }
    }
}

/// Configure an Authenticator using the builder pattern.
pub struct AuthenticatorBuilder<C, F> {
    hyper_client_builder: C,
    storage_type: StorageType,
    auth_flow: F,
}

/// Create an authenticator that uses the installed flow.
/// ```
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
///         app_secret,
///         InstalledFlowReturnMethod::HTTPRedirect,
///     )
///     .build()
///     .await
///     .expect("failed to create authenticator");
/// # }
/// ```
pub struct InstalledFlowAuthenticator;
impl InstalledFlowAuthenticator {
    /// Use the builder pattern to create an Authenticator that uses the installed flow.
    pub fn builder(
        app_secret: ApplicationSecret,
        method: InstalledFlowReturnMethod,
    ) -> AuthenticatorBuilder<DefaultHyperClient, InstalledFlow> {
        AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(InstalledFlow::new(
            app_secret, method,
        ))
    }
}

/// Create an authenticator that uses the device flow.
/// ```
/// # async fn foo() {
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
pub struct DeviceFlowAuthenticator;
impl DeviceFlowAuthenticator {
    /// Use the builder pattern to create an Authenticator that uses the device flow.
    pub fn builder(
        app_secret: ApplicationSecret,
    ) -> AuthenticatorBuilder<DefaultHyperClient, DeviceFlow> {
        AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(DeviceFlow::new(app_secret))
    }
}

/// Create an authenticator that uses a service account.
/// ```
/// # async fn foo() {
/// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_account_key)
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
pub struct ServiceAccountAuthenticator;
impl ServiceAccountAuthenticator {
    /// Use the builder pattern to create an Authenticator that uses a service account.
    pub fn builder(
        service_account_key: ServiceAccountKey,
    ) -> AuthenticatorBuilder<DefaultHyperClient, ServiceAccountFlowOpts> {
        AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(ServiceAccountFlowOpts {
            key: service_account_key,
            subject: None,
        })
    }
}

/// ## Methods available when building any Authenticator.
/// ```
/// # async fn foo() {
/// # let custom_hyper_client = hyper::Client::new();
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
///         .hyper_client(custom_hyper_client)
///         .persist_tokens_to_disk("/tmp/tokenfile.json")
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
impl<C, F> AuthenticatorBuilder<C, F> {
    async fn common_build(
        hyper_client_builder: C,
        storage_type: StorageType,
        auth_flow: AuthFlow,
    ) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        let hyper_client = hyper_client_builder.build_hyper_client();
        let storage = match storage_type {
            StorageType::Memory => Storage::Memory {
                tokens: Mutex::new(storage::JSONTokens::new()),
            },
            StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?),
        };

        Ok(Authenticator {
            hyper_client,
            storage,
            auth_flow,
        })
    }

    fn with_auth_flow(auth_flow: F) -> AuthenticatorBuilder<DefaultHyperClient, F> {
        AuthenticatorBuilder {
            hyper_client_builder: DefaultHyperClient,
            storage_type: StorageType::Memory,
            auth_flow,
        }
    }

    /// Use the provided hyper client.
    pub fn hyper_client<NewC>(
        self,
        hyper_client: hyper::Client<NewC>,
    ) -> AuthenticatorBuilder<hyper::Client<NewC>, F> {
        AuthenticatorBuilder {
            hyper_client_builder: hyper_client,
            storage_type: self.storage_type,
            auth_flow: self.auth_flow,
        }
    }

    /// Persist tokens to disk in the provided filename.
    pub fn persist_tokens_to_disk<P: Into<PathBuf>>(self, path: P) -> AuthenticatorBuilder<C, F> {
        AuthenticatorBuilder {
            storage_type: StorageType::Disk(path.into()),
            ..self
        }
    }
}

/// ## Methods available when building a device flow Authenticator.
/// ```
/// # async fn foo() {
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultDeviceFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
///         .device_code_url("foo")
///         .flow_delegate(Box::new(custom_flow_delegate))
///         .grant_type("foo")
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, DeviceFlow> {
    /// Use the provided device code url.
    pub fn device_code_url(self, url: impl Into<Cow<'static, str>>) -> Self {
        AuthenticatorBuilder {
            auth_flow: DeviceFlow {
                device_code_url: url.into(),
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Use the provided DeviceFlowDelegate.
    pub fn flow_delegate(self, flow_delegate: Box<dyn DeviceFlowDelegate>) -> Self {
        AuthenticatorBuilder {
            auth_flow: DeviceFlow {
                flow_delegate,
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Use the provided grant type.
    pub fn grant_type(self, grant_type: impl Into<Cow<'static, str>>) -> Self {
        AuthenticatorBuilder {
            auth_flow: DeviceFlow {
                grant_type: grant_type.into(),
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Create the authenticator.
    pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        Self::common_build(
            self.hyper_client_builder,
            self.storage_type,
            AuthFlow::DeviceFlow(self.auth_flow),
        )
        .await
    }
}

/// ## Methods available when building an installed flow Authenticator.
/// ```
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
///         app_secret,
///         InstalledFlowReturnMethod::HTTPRedirect,
///     )
///     .flow_delegate(Box::new(custom_flow_delegate))
///     .build()
///     .await
///     .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, InstalledFlow> {
    /// Use the provided InstalledFlowDelegate.
    pub fn flow_delegate(self, flow_delegate: Box<dyn InstalledFlowDelegate>) -> Self {
        AuthenticatorBuilder {
            auth_flow: InstalledFlow {
                flow_delegate,
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Create the authenticator.
    pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        Self::common_build(
            self.hyper_client_builder,
            self.storage_type,
            AuthFlow::InstalledFlow(self.auth_flow),
        )
        .await
    }
}

/// ## Methods available when building a service account authenticator.
/// ```
/// # async fn foo() {
/// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(
///         service_account_key,
///     )
///     .subject("mysubject")
///     .build()
///     .await
///     .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, ServiceAccountFlowOpts> {
    /// Use the provided subject.
    pub fn subject(self, subject: impl Into<String>) -> Self {
        AuthenticatorBuilder {
            auth_flow: ServiceAccountFlowOpts {
                subject: Some(subject.into()),
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Create the authenticator.
    pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        let service_account_auth_flow = ServiceAccountFlow::new(self.auth_flow)?;
        Self::common_build(
            self.hyper_client_builder,
            self.storage_type,
            AuthFlow::ServiceAccountFlow(service_account_auth_flow),
        )
        .await
    }
}

mod private {
    use crate::device::DeviceFlow;
    use crate::error::Error;
    use crate::installed::InstalledFlow;
    use crate::service_account::ServiceAccountFlow;
    use crate::types::{ApplicationSecret, TokenInfo};

    pub enum AuthFlow {
        DeviceFlow(DeviceFlow),
        InstalledFlow(InstalledFlow),
        ServiceAccountFlow(ServiceAccountFlow),
    }

    impl AuthFlow {
        pub(crate) fn app_secret(&self) -> Option<&ApplicationSecret> {
            match self {
                AuthFlow::DeviceFlow(device_flow) => Some(&device_flow.app_secret),
                AuthFlow::InstalledFlow(installed_flow) => Some(&installed_flow.app_secret),
                AuthFlow::ServiceAccountFlow(_) => None,
            }
        }

        pub(crate) async fn token<'a, C, T>(
            &'a self,
            hyper_client: &'a hyper::Client<C>,
            scopes: &'a [T],
        ) -> Result<TokenInfo, Error>
        where
            T: AsRef<str>,
            C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
        {
            match self {
                AuthFlow::DeviceFlow(device_flow) => device_flow.token(hyper_client, scopes).await,
                AuthFlow::InstalledFlow(installed_flow) => {
                    installed_flow.token(hyper_client, scopes).await
                }
                AuthFlow::ServiceAccountFlow(service_account_flow) => {
                    service_account_flow.token(hyper_client, scopes).await
                }
            }
        }
    }
}

/// A trait implemented for any hyper::Client as well as the DefaultHyperClient.
pub trait HyperClientBuilder {
    /// The hyper connector that the resulting hyper client will use.
    type Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static;

    /// Create a hyper::Client
    fn build_hyper_client(self) -> hyper::Client<Self::Connector>;
}

/// The builder value used when the default hyper client should be used.
pub struct DefaultHyperClient;
impl HyperClientBuilder for DefaultHyperClient {
    type Connector = hyper_rustls::HttpsConnector<hyper::client::connect::HttpConnector>;

    fn build_hyper_client(self) -> hyper::Client<Self::Connector> {
        hyper::Client::builder()
            .keep_alive(false)
            .build::<_, hyper::Body>(hyper_rustls::HttpsConnector::new())
    }
}

impl<C> HyperClientBuilder for hyper::Client<C>
where
    C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
{
    type Connector = C;

    fn build_hyper_client(self) -> hyper::Client<C> {
        self
    }
}

enum StorageType {
    Memory,
    Disk(PathBuf),
}

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

    #[test]
    fn ensure_send_sync() {
        fn is_send_sync<T: Send + Sync>() {}
        is_send_sync::<Authenticator<<DefaultHyperClient as HyperClientBuilder>::Connector>>()
    }
}
<commit_msg>feat(refresh): Allow forcing Authenticator to refresh a token<commit_after>//! Module contianing the core functionality for OAuth2 Authentication.
use crate::authenticator_delegate::{DeviceFlowDelegate, InstalledFlowDelegate};
use crate::device::DeviceFlow;
use crate::error::Error;
use crate::installed::{InstalledFlow, InstalledFlowReturnMethod};
use crate::refresh::RefreshFlow;
use crate::service_account::{ServiceAccountFlow, ServiceAccountFlowOpts, ServiceAccountKey};
use crate::storage::{self, Storage};
use crate::types::{AccessToken, ApplicationSecret, TokenInfo};
use private::AuthFlow;

use std::borrow::Cow;
use std::fmt;
use std::io;
use std::path::PathBuf;
use std::sync::Mutex;

/// Authenticator is responsible for fetching tokens, handling refreshing tokens,
/// and optionally persisting tokens to disk.
pub struct Authenticator<C> {
    hyper_client: hyper::Client<C>,
    storage: Storage,
    auth_flow: AuthFlow,
}

struct DisplayScopes<'a, T>(&'a [T]);
impl<'a, T> fmt::Display for DisplayScopes<'a, T>
where
    T: AsRef<str>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("[")?;
        let mut iter = self.0.iter();
        if let Some(first) = iter.next() {
            f.write_str(first.as_ref())?;
            for scope in iter {
                f.write_str(", ")?;
                f.write_str(scope.as_ref())?;
            }
        }
        f.write_str("]")
    }
}

impl<C> Authenticator<C>
where
    C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
{
    /// Return the current token for the provided scopes.
    pub async fn token<'a, T>(&'a self, scopes: &'a [T]) -> Result<AccessToken, Error>
    where
        T: AsRef<str>,
    {
        self.find_token(scopes, /* force_refresh = */ false).await
    }

    /// Return a token for the provided scopes, but don't reuse cached tokens. Instead,
    /// always fetch a new token from the OAuth server.
    pub async fn force_refreshed_token<'a, T>(&'a self, scopes: &'a [T]) -> Result<AccessToken, Error>
        where T: AsRef<str>
    {
        self.find_token(scopes, /* force_refresh = */ true).await
    }

    /// Return a cached token or fetch a new one from the server.
    async fn find_token<'a, T>(&'a self, scopes: &'a [T], force_refresh: bool) -> Result<AccessToken, Error>
        where T: AsRef<str>
    {
        log::debug!(
            "access token requested for scopes: {}",
            DisplayScopes(scopes)
        );
        let hashed_scopes = storage::ScopeSet::from(scopes);
        match (self.storage.get(hashed_scopes), self.auth_flow.app_secret()) {
            (Some(t), _) if !t.is_expired() && !force_refresh => {
                // unexpired token found
                log::debug!("found valid token in cache: {:?}", t);
                Ok(t.into())
            }
            (
                Some(TokenInfo {
                    refresh_token: Some(refresh_token),
                    ..
                }),
                Some(app_secret),
            ) => {
                // token is expired but has a refresh token.
                let token_info =
                    RefreshFlow::refresh_token(&self.hyper_client, app_secret, &refresh_token)
                        .await?;
                self.storage.set(hashed_scopes, token_info.clone()).await?;
                Ok(token_info.into())
            }
            _ => {
                // no token in the cache or the token returned can't be refreshed.
                let token_info = self.auth_flow.token(&self.hyper_client, scopes).await?;
                self.storage.set(hashed_scopes, token_info.clone()).await?;
                Ok(token_info.into())
            }
        }
    }
}

/// Configure an Authenticator using the builder pattern.
pub struct AuthenticatorBuilder<C, F> {
    hyper_client_builder: C,
    storage_type: StorageType,
    auth_flow: F,
}

/// Create an authenticator that uses the installed flow.
/// ```
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
///         app_secret,
///         InstalledFlowReturnMethod::HTTPRedirect,
///     )
///     .build()
///     .await
///     .expect("failed to create authenticator");
/// # }
/// ```
pub struct InstalledFlowAuthenticator;
impl InstalledFlowAuthenticator {
    /// Use the builder pattern to create an Authenticator that uses the installed flow.
    pub fn builder(
        app_secret: ApplicationSecret,
        method: InstalledFlowReturnMethod,
    ) -> AuthenticatorBuilder<DefaultHyperClient, InstalledFlow> {
        AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(InstalledFlow::new(
            app_secret, method,
        ))
    }
}

/// Create an authenticator that uses the device flow.
/// ```
/// # async fn foo() {
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
pub struct DeviceFlowAuthenticator;
impl DeviceFlowAuthenticator {
    /// Use the builder pattern to create an Authenticator that uses the device flow.
    pub fn builder(
        app_secret: ApplicationSecret,
    ) -> AuthenticatorBuilder<DefaultHyperClient, DeviceFlow> {
        AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(DeviceFlow::new(app_secret))
    }
}

/// Create an authenticator that uses a service account.
/// ```
/// # async fn foo() {
/// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(service_account_key)
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
pub struct ServiceAccountAuthenticator;
impl ServiceAccountAuthenticator {
    /// Use the builder pattern to create an Authenticator that uses a service account.
    pub fn builder(
        service_account_key: ServiceAccountKey,
    ) -> AuthenticatorBuilder<DefaultHyperClient, ServiceAccountFlowOpts> {
        AuthenticatorBuilder::<DefaultHyperClient, _>::with_auth_flow(ServiceAccountFlowOpts {
            key: service_account_key,
            subject: None,
        })
    }
}

/// ## Methods available when building any Authenticator.
/// ```
/// # async fn foo() {
/// # let custom_hyper_client = hyper::Client::new();
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
///         .hyper_client(custom_hyper_client)
///         .persist_tokens_to_disk("/tmp/tokenfile.json")
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
impl<C, F> AuthenticatorBuilder<C, F> {
    async fn common_build(
        hyper_client_builder: C,
        storage_type: StorageType,
        auth_flow: AuthFlow,
    ) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        let hyper_client = hyper_client_builder.build_hyper_client();
        let storage = match storage_type {
            StorageType::Memory => Storage::Memory {
                tokens: Mutex::new(storage::JSONTokens::new()),
            },
            StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?),
        };

        Ok(Authenticator {
            hyper_client,
            storage,
            auth_flow,
        })
    }

    fn with_auth_flow(auth_flow: F) -> AuthenticatorBuilder<DefaultHyperClient, F> {
        AuthenticatorBuilder {
            hyper_client_builder: DefaultHyperClient,
            storage_type: StorageType::Memory,
            auth_flow,
        }
    }

    /// Use the provided hyper client.
    pub fn hyper_client<NewC>(
        self,
        hyper_client: hyper::Client<NewC>,
    ) -> AuthenticatorBuilder<hyper::Client<NewC>, F> {
        AuthenticatorBuilder {
            hyper_client_builder: hyper_client,
            storage_type: self.storage_type,
            auth_flow: self.auth_flow,
        }
    }

    /// Persist tokens to disk in the provided filename.
    pub fn persist_tokens_to_disk<P: Into<PathBuf>>(self, path: P) -> AuthenticatorBuilder<C, F> {
        AuthenticatorBuilder {
            storage_type: StorageType::Disk(path.into()),
            ..self
        }
    }
}

/// ## Methods available when building a device flow Authenticator.
/// ```
/// # async fn foo() {
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultDeviceFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::DeviceFlowAuthenticator::builder(app_secret)
///         .device_code_url("foo")
///         .flow_delegate(Box::new(custom_flow_delegate))
///         .grant_type("foo")
///         .build()
///         .await
///         .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, DeviceFlow> {
    /// Use the provided device code url.
    pub fn device_code_url(self, url: impl Into<Cow<'static, str>>) -> Self {
        AuthenticatorBuilder {
            auth_flow: DeviceFlow {
                device_code_url: url.into(),
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Use the provided DeviceFlowDelegate.
    pub fn flow_delegate(self, flow_delegate: Box<dyn DeviceFlowDelegate>) -> Self {
        AuthenticatorBuilder {
            auth_flow: DeviceFlow {
                flow_delegate,
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Use the provided grant type.
    pub fn grant_type(self, grant_type: impl Into<Cow<'static, str>>) -> Self {
        AuthenticatorBuilder {
            auth_flow: DeviceFlow {
                grant_type: grant_type.into(),
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Create the authenticator.
    pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        Self::common_build(
            self.hyper_client_builder,
            self.storage_type,
            AuthFlow::DeviceFlow(self.auth_flow),
        )
        .await
    }
}

/// ## Methods available when building an installed flow Authenticator.
/// ```
/// # async fn foo() {
/// # use yup_oauth2::InstalledFlowReturnMethod;
/// # let custom_flow_delegate = yup_oauth2::authenticator_delegate::DefaultInstalledFlowDelegate;
/// # let app_secret = yup_oauth2::read_application_secret("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::InstalledFlowAuthenticator::builder(
///         app_secret,
///         InstalledFlowReturnMethod::HTTPRedirect,
///     )
///     .flow_delegate(Box::new(custom_flow_delegate))
///     .build()
///     .await
///     .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, InstalledFlow> {
    /// Use the provided InstalledFlowDelegate.
    pub fn flow_delegate(self, flow_delegate: Box<dyn InstalledFlowDelegate>) -> Self {
        AuthenticatorBuilder {
            auth_flow: InstalledFlow {
                flow_delegate,
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Create the authenticator.
    pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        Self::common_build(
            self.hyper_client_builder,
            self.storage_type,
            AuthFlow::InstalledFlow(self.auth_flow),
        )
        .await
    }
}

/// ## Methods available when building a service account authenticator.
/// ```
/// # async fn foo() {
/// # let service_account_key = yup_oauth2::read_service_account_key("/tmp/foo").await.unwrap();
///     let authenticator = yup_oauth2::ServiceAccountAuthenticator::builder(
///         service_account_key,
///     )
///     .subject("mysubject")
///     .build()
///     .await
///     .expect("failed to create authenticator");
/// # }
/// ```
impl<C> AuthenticatorBuilder<C, ServiceAccountFlowOpts> {
    /// Use the provided subject.
    pub fn subject(self, subject: impl Into<String>) -> Self {
        AuthenticatorBuilder {
            auth_flow: ServiceAccountFlowOpts {
                subject: Some(subject.into()),
                ..self.auth_flow
            },
            ..self
        }
    }

    /// Create the authenticator.
    pub async fn build(self) -> io::Result<Authenticator<C::Connector>>
    where
        C: HyperClientBuilder,
    {
        let service_account_auth_flow = ServiceAccountFlow::new(self.auth_flow)?;
        Self::common_build(
            self.hyper_client_builder,
            self.storage_type,
            AuthFlow::ServiceAccountFlow(service_account_auth_flow),
        )
        .await
    }
}

mod private {
    use crate::device::DeviceFlow;
    use crate::error::Error;
    use crate::installed::InstalledFlow;
    use crate::service_account::ServiceAccountFlow;
    use crate::types::{ApplicationSecret, TokenInfo};

    pub enum AuthFlow {
        DeviceFlow(DeviceFlow),
        InstalledFlow(InstalledFlow),
        ServiceAccountFlow(ServiceAccountFlow),
    }

    impl AuthFlow {
        pub(crate) fn app_secret(&self) -> Option<&ApplicationSecret> {
            match self {
                AuthFlow::DeviceFlow(device_flow) => Some(&device_flow.app_secret),
                AuthFlow::InstalledFlow(installed_flow) => Some(&installed_flow.app_secret),
                AuthFlow::ServiceAccountFlow(_) => None,
            }
        }

        pub(crate) async fn token<'a, C, T>(
            &'a self,
            hyper_client: &'a hyper::Client<C>,
            scopes: &'a [T],
        ) -> Result<TokenInfo, Error>
        where
            T: AsRef<str>,
            C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
        {
            match self {
                AuthFlow::DeviceFlow(device_flow) => device_flow.token(hyper_client, scopes).await,
                AuthFlow::InstalledFlow(installed_flow) => {
                    installed_flow.token(hyper_client, scopes).await
                }
                AuthFlow::ServiceAccountFlow(service_account_flow) => {
                    service_account_flow.token(hyper_client, scopes).await
                }
            }
        }
    }
}

/// A trait implemented for any hyper::Client as well as the DefaultHyperClient.
pub trait HyperClientBuilder {
    /// The hyper connector that the resulting hyper client will use.
    type Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static;

    /// Create a hyper::Client
    fn build_hyper_client(self) -> hyper::Client<Self::Connector>;
}

/// The builder value used when the default hyper client should be used.
pub struct DefaultHyperClient;
impl HyperClientBuilder for DefaultHyperClient {
    type Connector = hyper_rustls::HttpsConnector<hyper::client::connect::HttpConnector>;

    fn build_hyper_client(self) -> hyper::Client<Self::Connector> {
        hyper::Client::builder()
            .keep_alive(false)
            .build::<_, hyper::Body>(hyper_rustls::HttpsConnector::new())
    }
}

impl<C> HyperClientBuilder for hyper::Client<C>
where
    C: hyper::client::connect::Connect + Clone + Send + Sync + 'static,
{
    type Connector = C;

    fn build_hyper_client(self) -> hyper::Client<C> {
        self
    }
}

enum StorageType {
    Memory,
    Disk(PathBuf),
}

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

    #[test]
    fn ensure_send_sync() {
        fn is_send_sync<T: Send + Sync>() {}
        is_send_sync::<Authenticator<<DefaultHyperClient as HyperClientBuilder>::Connector>>()
    }
}
<|endoftext|>


<commit_before>extern crate mio;

use client::GameClient;

//use mio::{TryRead, TryWrite};
use mio::tcp::*;
use mio::util::Slab;
use mio::Token;
use mio::{EventLoop, EventSet, PollOpt, Handler};
//use bytes::{Buf, Take};
//use std::mem;
use std::net::SocketAddr;
//use std::io::Cursor;
//use std::thread;
//use std::sync::mpsc;
use std::sync::{Arc, RwLock};
//use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::atomic::AtomicUsize;
//use std::collections::HashMap;

const SERVER_TOKEN: mio::Token = mio::Token(1);

#[derive(Clone)]
pub struct AuthoritativeServerState{
    clients: Arc<RwLock<Slab<GameClient>>>,
    token_counter: Arc<AtomicUsize>
}

impl AuthoritativeServerState{
    pub fn new() -> AuthoritativeServerState{
        AuthoritativeServerState{
            token_counter: Arc::new(AtomicUsize::new(1)),
            // Max 128 connections
            clients: Arc::new(RwLock::new(Slab::new_starting_at(Token(2), 128)))
        }
    }
}

pub struct AuthoritativeServer{
    // The socket on which this server is listening
    socket: TcpListener,

    // The token assigned to this server's own connection
    token: Token,

    // Current state for the server
    state: AuthoritativeServerState
}

impl AuthoritativeServer{
    pub fn new(address: SocketAddr) -> AuthoritativeServer{
        let server_state = AuthoritativeServerState::new();
        let server_state_clone = server_state.clone();

        println!("Starting authoritative server");
        let server_socket = TcpListener::bind(&address).expect("Failed to start socket listener!");

        let mut server = AuthoritativeServer{
            socket: server_socket,
            token: SERVER_TOKEN,
            state: server_state_clone
        };

        let mut event_loop = EventLoop::new().expect("Failed to create server event loop!");

        event_loop.register(&server.socket,
                            SERVER_TOKEN,
                            EventSet::readable(),
                            PollOpt::edge()).expect("Failed to register server with event loop!");

        println!("Running event loop...");
        event_loop.run(&mut server).expect("Failed to run event loop!");

        return server;
    }

    fn start_accept_loop(&mut self, event_loop: &mut EventLoop<AuthoritativeServer>){
        println!("Beginning server accept loop");

        loop{
            let socket = match self.socket.accept(){
                Ok(s) => {
                    match s{
                        Some((socket,_)) => socket,
                        None => {
                            println!("Accept loop encountered WouldBlock");
                            return;
                        }
                    }
                },
                Err(e) => {
                    println!("Failed to accept new socket. Error: {:?}", e);
                    return;
                }
            };

            if let Ok(ref mut clients) = self.state.clients.write(){
                match &clients.insert_with(|token| {
                    println!("Inserting new connection from {:?}", token);
                    GameClient::new(socket, token)
                }) {
                    &Some(token) => {
                        println!("Insertion successful!");
                        let ref mut client: GameClient = clients[token];
                        match client.register(event_loop){
                            Ok(_) => { println!("Registration successful!"); },
                            Err(e) => {
                                println!("Failed to register connection {:?} with event loop, error: {:?}", token, e);
                                //clients.remove(token);
                            }
                        }
                    },
                    &None => {
                        println!("Failed to insert!");
                    }
                }
            };
        }
    }

    fn get_client_mut<'a, F>(&'a mut self, token: Token, mut action: F) -> Result<(), String>
        where F: FnMut(&mut GameClient) {
        if let Ok(mut clients) = self.state.clients.write(){
            if clients.contains(token){
                let ref mut client = clients.get_mut(token).unwrap();

                action(client);

                return Ok(());
            }
        }
        Err(String::from(format!("No client exists with token {:?}", token)))
    }
}

impl Handler for AuthoritativeServer{
    type Timeout = ();
    type Message = ();

    fn tick(&mut self, event_loop: &mut EventLoop<AuthoritativeServer>) {
        println!("Begin server tick!");

        if let Ok(mut clients) = self.state.clients.write(){
            for client in clients.iter_mut(){
                client.reregister(event_loop).ok();
            }
        }

        println!("End server tick!");
    }

    fn ready(&mut self, event_loop: &mut EventLoop<AuthoritativeServer>, token: Token, events: EventSet) {
        assert!(token != Token(0), "We're not supposed to get a Token(0)!");

        if events.is_error(){
            println!("Error event for token {:?}", token);
            //Reset token?
            return;
        }

        if events.is_hup(){
            println!("OH FUCK NO, {:?} DID NOT JUST FUCKING HANG UP ON ME!", token);
            println!("I'M GOING TO FUCKING MURDER YOU FUCKER");
            //Reset?
            return;
        }

        if events.is_writable(){
            println!("Oh shit, motherfucking {:?} is writable! Look at this guy!", token);

            //fucking write some shit
        }
        else{
            println!("[{:?} silence intensifies]", token);
        }

        if events.is_readable(){
            println!("GOT SHIT TO READ FROM MY BRAH {:?} HELLLL YEAH", token);

            if self.token == token{
                self.start_accept_loop(event_loop);
            }
            else{
                self.get_client_mut(token, |client|{
                    if client.read().is_ok(){
                        client.reregister(event_loop).expect("Failed to reregister!");
                    }
                }).ok();
            }
        }
    }
}
<commit_msg>Added a get_client function<commit_after>extern crate mio;

use client::GameClient;

//use mio::{TryRead, TryWrite};
use mio::tcp::*;
use mio::util::Slab;
use mio::Token;
use mio::{EventLoop, EventSet, PollOpt, Handler};
//use bytes::{Buf, Take};
//use std::mem;
use std::net::SocketAddr;
//use std::io::Cursor;
//use std::thread;
//use std::sync::mpsc;
use std::sync::{Arc, RwLock};
//use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::atomic::AtomicUsize;
//use std::collections::HashMap;

const SERVER_TOKEN: mio::Token = mio::Token(1);

#[derive(Clone)]
pub struct AuthoritativeServerState{
    clients: Arc<RwLock<Slab<GameClient>>>,
    token_counter: Arc<AtomicUsize>
}

impl AuthoritativeServerState{
    pub fn new() -> AuthoritativeServerState{
        AuthoritativeServerState{
            token_counter: Arc::new(AtomicUsize::new(1)),
            // Max 128 connections
            clients: Arc::new(RwLock::new(Slab::new_starting_at(Token(2), 128)))
        }
    }
}

pub struct AuthoritativeServer{
    // The socket on which this server is listening
    socket: TcpListener,

    // The token assigned to this server's own connection
    token: Token,

    // Current state for the server
    state: AuthoritativeServerState
}

impl AuthoritativeServer{
    pub fn new(address: SocketAddr) -> AuthoritativeServer{
        let server_state = AuthoritativeServerState::new();
        let server_state_clone = server_state.clone();

        println!("Starting authoritative server");
        let server_socket = TcpListener::bind(&address).expect("Failed to start socket listener!");

        let mut server = AuthoritativeServer{
            socket: server_socket,
            token: SERVER_TOKEN,
            state: server_state_clone
        };

        let mut event_loop = EventLoop::new().expect("Failed to create server event loop!");

        event_loop.register(&server.socket,
                            SERVER_TOKEN,
                            EventSet::readable(),
                            PollOpt::edge()).expect("Failed to register server with event loop!");

        println!("Running event loop...");
        event_loop.run(&mut server).expect("Failed to run event loop!");

        return server;
    }

    fn start_accept_loop(&mut self, event_loop: &mut EventLoop<AuthoritativeServer>){
        println!("Beginning server accept loop");

        loop{
            let socket = match self.socket.accept(){
                Ok(s) => {
                    match s{
                        Some((socket,_)) => socket,
                        None => {
                            println!("Accept loop encountered WouldBlock");
                            return;
                        }
                    }
                },
                Err(e) => {
                    println!("Failed to accept new socket. Error: {:?}", e);
                    return;
                }
            };

            if let Ok(ref mut clients) = self.state.clients.write(){
                match &clients.insert_with(|token| {
                    println!("Inserting new connection from {:?}", token);
                    GameClient::new(socket, token)
                }) {
                    &Some(token) => {
                        println!("Insertion successful!");
                        let ref mut client: GameClient = clients[token];
                        match client.register(event_loop){
                            Ok(_) => { println!("Registration successful!"); },
                            Err(e) => {
                                println!("Failed to register connection {:?} with event loop, error: {:?}", token, e);
                                //clients.remove(token);
                            }
                        }
                    },
                    &None => {
                        println!("Failed to insert!");
                    }
                }
            };
        }
    }

    fn get_client_mut<'a, F>(&'a mut self, token: Token, mut action: F) -> Result<(), String>
        where F: FnMut(&mut GameClient) {
        if let Ok(mut clients) = self.state.clients.write(){
            if clients.contains(token){
                let ref mut client = clients.get_mut(token).unwrap();

                action(client);

                return Ok(());
            }
        }
        Err(String::from(format!("No client exists with token {:?}", token)))
    }

    fn get_client<'a, F>(&'a mut self, token: Token, action: F) -> Result<(), String>
        where F: Fn(&GameClient) {
        if let Ok(mut clients) = self.state.clients.read(){
            if clients.contains(token){
                let ref mut client = clients.get(token).expect("Clients contains token, but was unable to access client!");

                action(client);

                return Ok(());
            }
        }
        Err(String::from(format!("No client exists with token {:?}", token)))
    }
}

impl Handler for AuthoritativeServer{
    type Timeout = ();
    type Message = ();

    fn tick(&mut self, event_loop: &mut EventLoop<AuthoritativeServer>) {
        println!("Begin server tick!");

        if let Ok(mut clients) = self.state.clients.write(){
            for client in clients.iter_mut(){
                client.reregister(event_loop).ok();
            }
        }

        println!("End server tick!");
    }

    fn ready(&mut self, event_loop: &mut EventLoop<AuthoritativeServer>, token: Token, events: EventSet) {
        assert!(token != Token(0), "We're not supposed to get a Token(0)!");

        if events.is_error(){
            println!("Error event for token {:?}", token);
            //Reset token?
            return;
        }

        if events.is_hup(){
            println!("OH FUCK NO, {:?} DID NOT JUST FUCKING HANG UP ON ME!", token);
            println!("I'M GOING TO FUCKING MURDER YOU FUCKER");
            //Reset?
            return;
        }

        if events.is_writable(){
            println!("Oh shit, motherfucking {:?} is writable! Look at this guy!", token);

            //fucking write some shit
        }
        else{
            println!("[{:?} silence intensifies]", token);
        }

        if events.is_readable(){
            println!("GOT SHIT TO READ FROM MY BRAH {:?} HELLLL YEAH", token);

            if self.token == token{
                self.start_accept_loop(event_loop);
            }
            else{
                self.get_client_mut(token, |client|{
                    if client.read().is_ok(){
                        client.reregister(event_loop).expect("Failed to reregister!");
                    }
                }).ok();
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate serialize;
extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::os;

use cargo::ops;
use cargo::{execute_main_without_stdin};
use cargo::core::{MultiShell};
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::find_project_manifest;

docopt!(Options, "
Build a package's documentation

Usage:
    cargo-doc [options]

Options:
    -h, --help              Print this message
    --no-deps               Don't build documentation for dependencies
    -j N, --jobs N          The number of jobs to run in parallel
    -u, --update-remotes    Deprecated option, use `cargo update` instead
    --manifest-path PATH    Path to the manifest to document
    -v, --verbose           Use verbose output

By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.
",  flag_jobs: Option<uint>,
    flag_manifest_path: Option<String>)

fn main() {
    execute_main_without_stdin(execute, false)
}

fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
    shell.set_verbose(options.flag_verbose);
    let root = match options.flag_manifest_path {
        Some(path) => Path::new(path),
        None => try!(find_project_manifest(&os::getcwd(), "Cargo.toml")
                    .map_err(|_| {
                        CliError::new("Could not find Cargo.toml in this \
                                       directory or any parent directory",
                                      102)
                    }))
    };

    let mut doc_opts = ops::DocOptions {
        all: !options.flag_no_deps,
        compile_opts: ops::CompileOptions {
            update: options.flag_update_remotes,
            env: if options.flag_no_deps {"doc"} else {"doc-all"},
            shell: shell,
            jobs: options.flag_jobs,
            target: None,
        },
    };

    try!(ops::doc(&root, &mut doc_opts).map_err(|err| {
        CliError::from_boxed(err, 101)
    }));

    Ok(None)
}

<commit_msg>Use same method to load manifest with doc sub-command<commit_after>#![feature(phase)]

extern crate serialize;
extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use cargo::ops;
use cargo::{execute_main_without_stdin};
use cargo::core::{MultiShell};
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};

docopt!(Options, "
Build a package's documentation

Usage:
    cargo-doc [options]

Options:
    -h, --help              Print this message
    --no-deps               Don't build documentation for dependencies
    -j N, --jobs N          The number of jobs to run in parallel
    -u, --update-remotes    Deprecated option, use `cargo update` instead
    --manifest-path PATH    Path to the manifest to document
    -v, --verbose           Use verbose output

By default the documentation for the local package and all dependencies is
built. The output is all placed in `target/doc` in rustdoc's usual format.
",  flag_jobs: Option<uint>,
    flag_manifest_path: Option<String>)

fn main() {
    execute_main_without_stdin(execute, false)
}

fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
    shell.set_verbose(options.flag_verbose);

    let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));

    let mut doc_opts = ops::DocOptions {
        all: !options.flag_no_deps,
        compile_opts: ops::CompileOptions {
            update: options.flag_update_remotes,
            env: if options.flag_no_deps {"doc"} else {"doc-all"},
            shell: shell,
            jobs: options.flag_jobs,
            target: None,
        },
    };

    try!(ops::doc(&root, &mut doc_opts).map_err(|err| {
        CliError::from_boxed(err, 101)
    }));

    Ok(None)
}

<|endoftext|>


<commit_before>use std::mem;
use std::sync::atomic::{AtomicUsize};
use std::sync::atomic::Ordering::{Acquire, Release, SeqCst};
use std::ops::Deref;

use super::pool::*;

lazy_static! {
    pub static ref ARC_INNER_SIZE: usize = mem::size_of::<ArcByteSliceInner>();
}

/// ArcByteSlices are free floating and are not persisted
pub struct ArcByteSlice {
    pub _ptr: *mut ArcByteSliceInner,
    _pool: *const Pool,
}

/// ArcByteSliceInners are persisted in the mem map
pub struct ArcByteSliceInner {
    pub strong: AtomicUsize,
    pub weak: AtomicUsize,
    pub size: usize,
}

/// Public Api for ArcByteSlice
impl ArcByteSlice {
    pub fn new(inner: &mut ArcByteSliceInner, pool: &Pool) -> ArcByteSlice {
        inner.strong.fetch_add(1, Acquire);
        ArcByteSlice {
            _ptr: inner as *mut ArcByteSliceInner,
            _pool: pool as *const Pool,
        }
    }

    pub fn clone_to_persisted(&self) -> PersistedArcByteSlice {
        let inner = self.inner();
        // Persisted counts as a strong reference
        inner.strong.fetch_add(1, SeqCst);
        unsafe {
            PersistedArcByteSlice {
                arc_inner_index: (*self._pool)._inner_offset(&self),
                id_tag: (*self._pool)._get_id_tag(&self),
            }
        }
    }

    /// Stolen from std::sync::arc https://doc.rust-lang.org/src/alloc/arc.rs.html
    #[inline]
    pub fn inner(&self) -> &ArcByteSliceInner {
        // This unsafety is ok because while this arc is alive we're guaranteed
        // that the inner pointer is valid.
        unsafe { &*self._ptr }
    }

    /// Convert the Arc to a reference. Panics if the
    /// Arc does not point to a correctly sized piece of
    /// memory.
    pub fn deref_as<'a, T>(&'a self) -> &'a T {
        assert_eq!(self.inner().size, mem::size_of::<T>());
        unsafe {
            (*self._pool).deref_as(self)
        }
    }

    /// Convert the Arc to a reference. Panics if the
    /// Arc does not point to a correctly sized piece of
    /// memory.
    pub fn deref_as_mut<'a, T>(&'a self) -> &'a mut T {
        assert_eq!(self.inner().size, mem::size_of::<T>());
        unsafe {
            (*self._pool).deref_as_mut(self)
        }
    }
}

/// Public Api for ArcByteSliceInner
impl ArcByteSliceInner {
    pub fn init(&mut self, data: &[u8]) {
        self.strong.store(0, SeqCst);
        self.weak.store(0, SeqCst);
        self.size = data.len();
    }
}

/// Deref for ArcByteSlice -- No DerefMut since map contents are Read Only.
impl Deref for ArcByteSlice {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        unsafe {
            (*self._pool).deref(self)
        }
    }
}

impl  Drop for ArcByteSlice {
    fn drop(&mut self) {
        let inner = self.inner();
        if inner.strong.fetch_sub(1, Release) == 1 {
            // This was the last strong ref, let's release
            unsafe {
                (*self._pool).free(self);
            }
        }
    }
}

/// A PersistedArcByteSlice is a serializable version of an ArcByteSlice
/// You can freely trade Arcs for PersistedArcs and vice versa.
/// However, you must always manually release the PersistedArcByteSlice
/// since releasing requires reference to a pool. The Drop impl will panic
/// if you forget to release the persist.
pub struct PersistedArcByteSlice {
    pub arc_inner_index: usize,
    id_tag: usize,
}

impl PersistedArcByteSlice {
    pub fn clone_to_arc_byte_slice(&self, pool: &Pool) -> Result<ArcByteSlice, &'static str> {
        pool.clone_persisted_to_arc(self)
    }

    pub fn get_id_tag(&self) -> usize {
        self.id_tag
    }

    pub fn release(&mut self, pool: &Pool) -> Result<(), &'static str> {
        self.id_tag = 0;
        pool.release(self)
    }
}

impl Drop for PersistedArcByteSlice {
    fn drop(&mut self) {
        if self.id_tag != 0 {
            panic!("You MUST call release on a PersistedArcByteSlice before it can be dropped cleanly")
        }
    }
}
<commit_msg>Added clones for both types of arcs<commit_after>use std::mem;
use std::sync::atomic::{AtomicUsize};
use std::sync::atomic::Ordering::{Acquire, Release, SeqCst};
use std::ops::Deref;

use super::pool::*;

lazy_static! {
    pub static ref ARC_INNER_SIZE: usize = mem::size_of::<ArcByteSliceInner>();
}

/// ArcByteSlices are free floating and are not persisted
pub struct ArcByteSlice {
    pub _ptr: *mut ArcByteSliceInner,
    _pool: *const Pool,
}

/// ArcByteSliceInners are persisted in the mem map
pub struct ArcByteSliceInner {
    pub strong: AtomicUsize,
    pub weak: AtomicUsize,
    pub size: usize,
}

/// Public Api for ArcByteSlice
impl ArcByteSlice {
    pub fn new(inner: &mut ArcByteSliceInner, pool: &Pool) -> ArcByteSlice {
        inner.strong.fetch_add(1, Acquire);
        ArcByteSlice {
            _ptr: inner as *mut ArcByteSliceInner,
            _pool: pool as *const Pool,
        }
    }

    pub fn clone_to_persisted(&self) -> PersistedArcByteSlice {
        let inner = self.inner();
        // Persisted counts as a strong reference
        inner.strong.fetch_add(1, SeqCst);
        unsafe {
            PersistedArcByteSlice {
                arc_inner_index: (*self._pool)._inner_offset(&self),
                id_tag: (*self._pool)._get_id_tag(&self),
            }
        }
    }

    /// Stolen from std::sync::arc https://doc.rust-lang.org/src/alloc/arc.rs.html
    #[inline]
    pub fn inner(&self) -> &ArcByteSliceInner {
        // This unsafety is ok because while this arc is alive we're guaranteed
        // that the inner pointer is valid.
        unsafe { &*self._ptr }
    }

    /// Convert the Arc to a reference. Panics if the
    /// Arc does not point to a correctly sized piece of
    /// memory.
    pub fn deref_as<'a, T>(&'a self) -> &'a T {
        assert_eq!(self.inner().size, mem::size_of::<T>());
        unsafe {
            (*self._pool).deref_as(self)
        }
    }

    /// Convert the Arc to a reference. Panics if the
    /// Arc does not point to a correctly sized piece of
    /// memory.
    pub fn deref_as_mut<'a, T>(&'a self) -> &'a mut T {
        assert_eq!(self.inner().size, mem::size_of::<T>());
        unsafe {
            (*self._pool).deref_as_mut(self)
        }
    }
}

/// Public Api for ArcByteSliceInner
impl ArcByteSliceInner {
    pub fn init(&mut self, data: &[u8]) {
        self.strong.store(0, SeqCst);
        self.weak.store(0, SeqCst);
        self.size = data.len();
    }
}

impl Clone for ArcByteSlice {
    fn clone(&self) -> ArcByteSlice {
        self.inner().strong.fetch_add(1, Acquire);
        ArcByteSlice {
            _ptr: self._ptr,
            _pool: self._pool,
        }
    }
}

/// Deref for ArcByteSlice -- No DerefMut since map contents are Read Only.
impl Deref for ArcByteSlice {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        unsafe {
            (*self._pool).deref(self)
        }
    }
}

impl  Drop for ArcByteSlice {
    fn drop(&mut self) {
        let inner = self.inner();
        if inner.strong.fetch_sub(1, Release) == 1 {
            // This was the last strong ref, let's release
            unsafe {
                (*self._pool).free(self);
            }
        }
    }
}

/// A PersistedArcByteSlice is a serializable version of an ArcByteSlice
/// You can freely trade Arcs for PersistedArcs and vice versa.
/// However, you must always manually release the PersistedArcByteSlice
/// since releasing requires reference to a pool. The Drop impl will panic
/// if you forget to release the persist.
pub struct PersistedArcByteSlice {
    pub arc_inner_index: usize,
    id_tag: usize,
}

impl PersistedArcByteSlice {
    pub fn clone_to_arc_byte_slice(&self, pool: &Pool) -> Result<ArcByteSlice, &'static str> {
        pool.clone_persisted_to_arc(self)
    }

    pub fn get_id_tag(&self) -> usize {
        self.id_tag
    }

    pub fn clone(&self, pool: &Pool) -> Result<PersistedArcByteSlice, &'static str> {
        try!(pool.retain(self));
        Ok(PersistedArcByteSlice {
            arc_inner_index: self.arc_inner_index,
            id_tag: self.id_tag,
        })
    }

    pub fn release(&mut self, pool: &Pool) -> Result<(), &'static str> {
        self.id_tag = 0;
        pool.release(self)
    }
}

impl Drop for PersistedArcByteSlice {
    fn drop(&mut self) {
        if self.id_tag != 0 {
            panic!("You MUST call release on a PersistedArcByteSlice before it can be dropped cleanly")
        }
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate rusqlite;
extern crate pibq;

use std::env;
use std::time::{Duration, Instant};
use getopts::Options;

use pibq::bluetherm;
use pibq::sql;
use pibq::models::{ConnectionStatus, Reading};

// interval between sending query packtets, in ms
const QUERY_INTERVAL: u64 = 3000;

// if no packets are returned, amount of time to wait before creating a timeout error, in ms
const TIMEOUT_INTERVAL: u64 = 15000;

const HEARTBEAT_INTERVAL: u64 = 1000;

struct Harvester {
    sql_conn: rusqlite::Connection,
    bt_conn: Option<bluetherm::Connection>,
    serial: String,
    disconnected: bool,
    disconnect_reason: Option<bluetherm::ConnectionEvent>,
    send_interval: Duration,
    timeout_interval: Duration,
    last_send: Option<Instant>,
    last_receive: Option<Instant>
}

impl Harvester {
    fn new(sql_conn: rusqlite::Connection, serial: &str) -> Harvester {
        Harvester {
            sql_conn: sql_conn,
            bt_conn: Some(Harvester::connect_bluetherm(serial)),
            serial: serial.to_string(),
            disconnected: true,
            disconnect_reason: None,
            send_interval: Duration::from_millis(QUERY_INTERVAL),
            timeout_interval: Duration::from_millis(TIMEOUT_INTERVAL),
            last_send: None,
            last_receive: None
        }
    }

    fn connect_bluetherm(serial: &str) -> bluetherm::Connection {
        bluetherm::Connection::new(serial, Some(HEARTBEAT_INTERVAL)).unwrap()
    }

    fn start(&mut self) {
        loop {
            match (self.last_send, self.last_receive) {
                (Some(sent), _) if sent.elapsed() < self.send_interval => {},
                //(Some(sent), Some(received)) if sent > received => {},
                _ => {
                    self.send_packet();
                    self.last_send = Some(Instant::now());
                }
            }

            let event = self.get_bt_conn().wait().unwrap();

            println!("{}", event);
            match event {
                bluetherm::ConnectionEvent::Packet(p) => {
                    self.record_packet(p);
                    self.last_send = Some(Instant::now());
                    self.last_receive = Some(Instant::now());
                },
                e @ bluetherm::ConnectionEvent::InvalidPacket(_) => { self.bt_error(e); },
                e @ bluetherm::ConnectionEvent::ReadError(_) => { self.bt_error(e); },
                e @ bluetherm::ConnectionEvent::BadData(_) => { self.bt_error(e); },
                e @ bluetherm::ConnectionEvent::Heartbeat => {
                    match self.last_receive {
                        None => {
                            match self.last_send {
                                None => {},
                                Some(sent) => {
                                    if sent.elapsed() > self.timeout_interval {
                                        self.bt_error(e);
                                    }
                                }
                            }
                        },
                        Some(rec) => {
                            if rec.elapsed() > self.timeout_interval {
                                self.bt_error(e);
                            }
                        }
                    }
                }
            }
        }
    }

    fn get_bt_conn(&mut self) -> &mut bluetherm::Connection {
        self.bt_conn.as_mut().unwrap()
    }

    fn record_packet(&mut self, packet: bluetherm::Packet) {
        let mut reading = Reading::new();
        reading.value1 = packet.get_sensor1_reading();
        reading.value2 = packet.get_sensor2_reading();
        sql::insert_reading(&self.sql_conn, &mut reading).unwrap();
    }

    fn send_packet(&mut self) {
        println!("sending packet...");
        let p = bluetherm::Packet::temp_packet();
        match self.get_bt_conn().send(&p) {
            Err(e) => {
                self.bt_error(bluetherm::ConnectionEvent::ReadError(e));
            },
            Ok(_) => {}
        }
        println!("done sending packet.");
    }

    fn bt_error(&mut self, evt: bluetherm::ConnectionEvent) {
        let mut report_error = true;

        if self.disconnected {
            match &self.disconnect_reason {
                &None => {},
                &Some(ref reason) => {
                    match (reason, &evt) {
                        (&bluetherm::ConnectionEvent::InvalidPacket(_), &bluetherm::ConnectionEvent::InvalidPacket(_)) |
                        (&bluetherm::ConnectionEvent::ReadError(_), &bluetherm::ConnectionEvent::ReadError(_)) |
                        (&bluetherm::ConnectionEvent::BadData(_), &bluetherm::ConnectionEvent::BadData(_)) |
                        (&bluetherm::ConnectionEvent::Heartbeat, &bluetherm::ConnectionEvent::Heartbeat) => {
                            report_error = false;
                        },
                        _ => {},
                    }
                }
            }
        }

        if report_error {
            let msg = match evt {
                bluetherm::ConnectionEvent::InvalidPacket(ref p) => { format!("Invalid Packet: [{}]", p) },
                bluetherm::ConnectionEvent::ReadError(ref err) => { format!("Read Error: {}", err) },
                bluetherm::ConnectionEvent::BadData(_) => { format!("Bad Data Read") },
                bluetherm::ConnectionEvent::Heartbeat => { "Timeout".to_string() },
                _ => "Unknown Error".to_string()
            };

            let mut s = ConnectionStatus::new();
            s.is_disconnect = true;
            s.info = Some(msg);
            sql::insert_connection_status(&self.sql_conn, &mut s).unwrap();
        }

        self.disconnected = true;
        self.last_send = None;
        self.last_receive = None;

        println!("error, killing old connection. {}", evt);

        let old = self.bt_conn.take();
        drop(old.unwrap());

        println!("old conneciton dropped; making new");

        self.bt_conn = Some(Harvester::connect_bluetherm(&self.serial));

        println!("new connection made");
    }
}

// fn harvest(sql_conn: rusqlite::Connection, serial: &str) {
//
//     loop {
//         // if disconnected {
//         //     bt_conn = bluetherm::Connection::new(serial, Some(1000)).unwrap();
//         //     let mut s = ConnectionStatus::new();
//         //     s.is_disconnect = true;
//         //     sql::insert_connection_status(&sql_conn, &mut s).unwrap();
//         // }
//
//
//     }
//
// }

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.reqopt("s", "serial", "tty serial device", "DEV");
    opts.optopt("d", "dbfile", "sqlite DB file", "FILE");
    opts.optopt("m", "migrations", "migration folder", "DIR");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            println!("{}", f.to_string());
            print_usage(&program, opts);
            return;
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let serial = matches.opt_str("s").unwrap();
    let dbfile = matches.opt_str("d").unwrap_or("pibq.sqlite".to_string());
    let migrations = matches.opt_str("m").unwrap_or("migrations".to_string());

    let db = sql::get_connection(&dbfile, Some(migrations)).unwrap();

    let mut h = Harvester::new(db, &serial);
    h.start();
}
<commit_msg>changed error handling<commit_after>extern crate getopts;
extern crate rusqlite;
extern crate pibq;

use std::env;
use std::time::{Duration, Instant};
use getopts::Options;

use pibq::bluetherm;
use pibq::sql;
use pibq::models::{ConnectionStatus, Reading};

// interval between sending query packtets, in ms
const QUERY_INTERVAL: u64 = 3000;

// if no packets are returned, amount of time to wait before creating a timeout error, in ms
const TIMEOUT_INTERVAL: u64 = 15000;

const HEARTBEAT_INTERVAL: u64 = 1000;

struct Harvester {
    sql_conn: rusqlite::Connection,
    bt_conn: Option<bluetherm::Connection>,
    serial: String,
    disconnected: bool,
    disconnect_reason: Option<bluetherm::ConnectionEvent>,
    error_count: i64,
    send_interval: Duration,
    timeout_interval: Duration,
    last_send: Option<Instant>,
    last_receive: Option<Instant>
}

impl Harvester {
    fn new(sql_conn: rusqlite::Connection, serial: &str) -> Harvester {
        Harvester {
            sql_conn: sql_conn,
            bt_conn: Some(Harvester::connect_bluetherm(serial)),
            serial: serial.to_string(),
            disconnected: true,
            disconnect_reason: None,
            error_count: 0,
            send_interval: Duration::from_millis(QUERY_INTERVAL),
            timeout_interval: Duration::from_millis(TIMEOUT_INTERVAL),
            last_send: None,
            last_receive: None
        }
    }

    fn connect_bluetherm(serial: &str) -> bluetherm::Connection {
        bluetherm::Connection::new(serial, Some(HEARTBEAT_INTERVAL)).unwrap()
    }

    fn start(&mut self) {
        loop {
            match (self.last_send, self.last_receive) {
                (Some(sent), _) if sent.elapsed() < self.send_interval => {},
                //(Some(sent), Some(received)) if sent > received => {},
                _ => {
                    self.send_packet();
                    self.last_send = Some(Instant::now());
                }
            }

            let event = self.get_bt_conn().wait().unwrap();

            println!("{}", event);
            match event {
                bluetherm::ConnectionEvent::Packet(p) => {
                    self.record_packet(p);
                    self.last_send = Some(Instant::now());
                    self.last_receive = Some(Instant::now());
                },
                e @ bluetherm::ConnectionEvent::InvalidPacket(_) => { self.bt_error(e); },
                e @ bluetherm::ConnectionEvent::ReadError(_) => { self.bt_error(e); },
                e @ bluetherm::ConnectionEvent::BadData(_) => { self.bt_error(e); },
                e @ bluetherm::ConnectionEvent::Heartbeat => {
                    match self.last_receive {
                        None => {
                            match self.last_send {
                                None => {},
                                Some(sent) => {
                                    if sent.elapsed() > self.timeout_interval {
                                        self.bt_error(e);
                                    }
                                }
                            }
                        },
                        Some(rec) => {
                            if rec.elapsed() > self.timeout_interval {
                                self.bt_error(e);
                            }
                        }
                    }
                }
            }
        }
    }

    fn get_bt_conn(&mut self) -> &mut bluetherm::Connection {
        self.bt_conn.as_mut().unwrap()
    }

    fn record_packet(&mut self, packet: bluetherm::Packet) {
        let mut reading = Reading::new();
        reading.value1 = packet.get_sensor1_reading();
        reading.value2 = packet.get_sensor2_reading();
        sql::insert_reading(&self.sql_conn, &mut reading).unwrap();
    }

    fn send_packet(&mut self) {
        println!("sending packet...");
        let p = bluetherm::Packet::temp_packet();
        match self.get_bt_conn().send(&p) {
            Err(e) => {
                self.bt_error(bluetherm::ConnectionEvent::ReadError(e));
            },
            Ok(_) => {}
        }
        println!("done sending packet.");
    }

    fn bt_error(&mut self, evt: bluetherm::ConnectionEvent) {
        let mut report_error = true;

        if self.disconnected {
            match &self.disconnect_reason {
                &None => {},
                &Some(ref reason) => {
                    match (reason, &evt) {
                        (&bluetherm::ConnectionEvent::InvalidPacket(_), &bluetherm::ConnectionEvent::InvalidPacket(_)) |
                        (&bluetherm::ConnectionEvent::ReadError(_), &bluetherm::ConnectionEvent::ReadError(_)) |
                        (&bluetherm::ConnectionEvent::BadData(_), &bluetherm::ConnectionEvent::BadData(_)) |
                        (&bluetherm::ConnectionEvent::Heartbeat, &bluetherm::ConnectionEvent::Heartbeat) => {
                            report_error = false;
                        },
                        _ => {},
                    }
                }
            }
        }

        if report_error {
            let msg = match evt {
                bluetherm::ConnectionEvent::InvalidPacket(ref p) => { format!("Invalid Packet: [{}]", p) },
                bluetherm::ConnectionEvent::ReadError(ref err) => { format!("Read Error: {}", err) },
                bluetherm::ConnectionEvent::BadData(_) => { format!("Bad Data Read") },
                bluetherm::ConnectionEvent::Heartbeat => { "Timeout".to_string() },
                _ => "Unknown Error".to_string()
            };

            let mut s = ConnectionStatus::new();
            s.is_disconnect = true;
            s.info = Some(msg);
            sql::insert_connection_status(&self.sql_conn, &mut s).unwrap();
        }

        println!("error: {}", evt);

        self.disconnected = true;
        self.disconnect_reason = Some(evt);
        self.last_send = None;
        self.last_receive = None;

        self.error_count = self.error_count + 1;

        if self.error_count > 3 {
            self.error_count = 0;
            println!("killing old connection.");

            let old = self.bt_conn.take();
            drop(old.unwrap());

            println!("old conneciton dropped; making new");

            self.bt_conn = Some(Harvester::connect_bluetherm(&self.serial));

            println!("new connection made");
        }
    }
}

// fn harvest(sql_conn: rusqlite::Connection, serial: &str) {
//
//     loop {
//         // if disconnected {
//         //     bt_conn = bluetherm::Connection::new(serial, Some(1000)).unwrap();
//         //     let mut s = ConnectionStatus::new();
//         //     s.is_disconnect = true;
//         //     sql::insert_connection_status(&sql_conn, &mut s).unwrap();
//         // }
//
//
//     }
//
// }

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.reqopt("s", "serial", "tty serial device", "DEV");
    opts.optopt("d", "dbfile", "sqlite DB file", "FILE");
    opts.optopt("m", "migrations", "migration folder", "DIR");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            println!("{}", f.to_string());
            print_usage(&program, opts);
            return;
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let serial = matches.opt_str("s").unwrap();
    let dbfile = matches.opt_str("d").unwrap_or("pibq.sqlite".to_string());
    let migrations = matches.opt_str("m").unwrap_or("migrations".to_string());

    let db = sql::get_connection(&dbfile, Some(migrations)).unwrap();

    let mut h = Harvester::new(db, &serial);
    h.start();
}
<|endoftext|>