<commit_before>//! This module contains the code representing Mastodon nodes and API Clients
//!
use serde_json;
use url::Url;

use api::Client;
use api::oauth::{CreateApp, OAuthApp};
use errors::*;

use std::sync::{Arc, Mutex};

/// `Mastodon` is used to specify the base url of a Mastodon node.
/// Only HTTPS connections are supported.
#[derive(Debug)]
pub struct Mastodon(pub Url);

impl Mastodon {
    pub fn new(url: &str) -> Result<Mastodon> {
        Ok(Mastodon(Url::parse(url).chain_err(|| "Invalid URL")?))
    }

    pub fn url(&self) -> String {
        self.0.clone().into_string()
    }

    pub fn client(&self, token: &str) -> Client {
        Client {
            url_base: self.0.clone(),
            token: String::from(token)
        }
    }

    pub fn register_app(&self, name: &str, uris: &str, scopes: &str) -> OAuthApp {
        /// ```rust,no_run
        /// let herder_app: OAuthApp = serde_json::from_slice(&result).unwrap();
        /// println!("\n{:?}\n", &herder_app);
        /// println!("\n{}\n", serde_json::to_string(&herder_app).unwrap());
        /// ```
        let out = Arc::new(Mutex::new(Vec::new()));
        let social_app = CreateApp::new(name, uris, scopes);
        social_app.register(&self.endpoint_url_string("/api/v1/apps"), out.clone()).unwrap();

        let result = out.lock().unwrap();
        let json: OAuthApp = serde_json::from_slice(&result).expect("Could not parse OAuth from response");
        //format!("{}", &json)
        json
    }
}

pub trait ApiHandler {
    fn endpoint_url(&self, path: &str) -> Url;
    fn endpoint_url_string(&self, path: &str) -> String;
}

impl ApiHandler for Mastodon {
    fn endpoint_url(&self, path: &str) -> Url {
        self.0.clone().join(path).unwrap()
    }
    fn endpoint_url_string(&self, path: &str) -> String {
        self.endpoint_url(path).into_string()
    }
}
<commit_msg>refactor mastodon methods into traits<commit_after>//! This module contains the code representing Mastodon nodes and API Clients
//!
use serde_json;
use url::Url;

use api::Client;
use api::oauth::{CreateApp, OAuthApp};
use errors::*;

use std::sync::{Arc, Mutex};

/// `Mastodon` is used to specify the base url of a Mastodon node.
/// Only HTTPS connections are supported.
#[derive(Debug)]
pub struct Mastodon(pub Url);

impl Mastodon {
    /// Create a new Mastodon instance.
    pub fn new(url: &str) -> Result<Mastodon> {
        Ok(Mastodon(Url::parse(url).chain_err(|| "Invalid URL")?))
    }

}

trait NodeInstance {
    fn url(&self) -> String;
    fn client(&self, token: &str) -> Client;
    fn register_app(&self, name: &str, uris: &str, scopes: &str) -> OAuthApp;
}

impl NodeInstance for Mastodon {
    fn url(&self) -> String {
        self.0.clone().into_string()
    }

    fn client(&self, token: &str) -> Client {
        Client {
            url_base: self.0.clone(),
            token: String::from(token)
        }
    }

    fn register_app(&self, name: &str, uris: &str, scopes: &str) -> OAuthApp {
        /// ```rust,no_run
        /// let herder_app: OAuthApp = serde_json::from_slice(&result).unwrap();
        /// println!("\n{:?}\n", &herder_app);
        /// println!("\n{}\n", serde_json::to_string(&herder_app).unwrap());
        /// ```
        let out = Arc::new(Mutex::new(Vec::new()));
        let social_app = CreateApp::new(name, uris, scopes);
        social_app.register(&self.endpoint_url_string("/api/v1/apps"), out.clone()).unwrap();

        let result = out.lock().unwrap();
        let json: OAuthApp = serde_json::from_slice(&result).expect("Could not parse OAuth from response");
        //format!("{}", &json)
        json
    }
}

pub trait ApiHandler {
    fn endpoint_url(&self, path: &str) -> Url;
    fn endpoint_url_string(&self, path: &str) -> String;
}

impl ApiHandler for Mastodon {
    fn endpoint_url(&self, path: &str) -> Url {
        self.0.clone().join(path).unwrap()
    }
    fn endpoint_url_string(&self, path: &str) -> String {
        self.endpoint_url(path).into_string()
    }
}
<|endoftext|>


<commit_before>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use vec::Vec;
use string::String;

use num::PrimInt;

use net::Packet;

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    pub fn from_str(s: String) -> Result<Self, ()> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut i = 0;
        let mut ret = Self::empty();

        for b in split {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;

            i += 1;
        }

        Ok(ret)
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<commit_msg>net/defs: Add type IpAddr<commit_after>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use vec::Vec;
use string::String;

use num::PrimInt;

use net::Packet;

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IP address, either V4 or V6
pub enum IpAddr {
    /// An IPv4 address
    V4(Ipv4Addr),
    /// An IPv6 address
    V6(Ipv6Addr)
}

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    pub fn from_str(s: String) -> Result<Self, ()> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut i = 0;
        let mut ret = Self::empty();

        for b in split {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;

            i += 1;
        }

        Ok(ret)
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<|endoftext|>


<commit_before>//! Linear operator algebra

use crate::generate::hstack;
use crate::types::*;
use ndarray::*;

pub trait LinearOperator {
    type Elem: Scalar;

    /// Apply operator out-place
    fn apply<S>(&self, a: &ArrayBase<S, Ix1>) -> Array1<S::Elem>
    where
        S: Data<Elem = Self::Elem>,
    {
        let mut a = a.to_owned();
        self.apply_mut(&mut a);
        a
    }

    /// Apply operator in-place
    fn apply_mut<S>(&self, a: &mut ArrayBase<S, Ix1>)
    where
        S: DataMut<Elem = Self::Elem>,
    {
        let b = self.apply(a);
        azip!(mut a(a), b in { *a = b });
    }

    /// Apply operator with move
    fn apply_into<S>(&self, mut a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix1>
    where
        S: DataOwned<Elem = Self::Elem> + DataMut,
    {
        self.apply_mut(&mut a);
        a
    }

    /// Apply operator to matrix out-place
    fn apply2<S>(&self, a: &ArrayBase<S, Ix2>) -> Array2<S::Elem>
    where
        S: Data<Elem = Self::Elem>,
    {
        let cols: Vec<_> = a.axis_iter(Axis(1)).map(|col| self.apply(&col)).collect();
        hstack(&cols).unwrap()
    }

    /// Apply operator to matrix in-place
    fn apply2_mut<S>(&self, a: &mut ArrayBase<S, Ix2>)
    where
        S: DataMut<Elem = Self::Elem>,
    {
        for mut col in a.axis_iter_mut(Axis(1)) {
            self.apply_mut(&mut col)
        }
    }

    /// Apply operator to matrix with move
    fn apply2_into<S>(&self, mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where
        S: DataOwned<Elem = Self::Elem> + DataMut,
    {
        self.apply2_mut(&mut a);
        a
    }
}

impl LinearOperator for ArrayBase<Sa, Ix2>
where
    A: Scalar,
    Sa: Data<Elem = A>,
{
    type Elem = A;

    fn apply<S>(&self, a: &ArrayBase<S, Ix1>) -> Array1
    where
        S: Data<Elem = A>,
    {
        self.dot(a)
    }
}
<commit_msg>Add doc<commit_after>//! Linear operator algebra

use crate::generate::hstack;
use crate::types::*;
use ndarray::*;

/// Abstracted linear operator as an action to vector (`ArrayBase<S, Ix1>`) and matrix
/// (`ArrayBase<S, Ix2`)
pub trait LinearOperator {
    type Elem: Scalar;

    /// Apply operator out-place
    fn apply<S>(&self, a: &ArrayBase<S, Ix1>) -> Array1<S::Elem>
    where
        S: Data<Elem = Self::Elem>,
    {
        let mut a = a.to_owned();
        self.apply_mut(&mut a);
        a
    }

    /// Apply operator in-place
    fn apply_mut<S>(&self, a: &mut ArrayBase<S, Ix1>)
    where
        S: DataMut<Elem = Self::Elem>,
    {
        let b = self.apply(a);
        azip!(mut a(a), b in { *a = b });
    }

    /// Apply operator with move
    fn apply_into<S>(&self, mut a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix1>
    where
        S: DataOwned<Elem = Self::Elem> + DataMut,
    {
        self.apply_mut(&mut a);
        a
    }

    /// Apply operator to matrix out-place
    fn apply2<S>(&self, a: &ArrayBase<S, Ix2>) -> Array2<S::Elem>
    where
        S: Data<Elem = Self::Elem>,
    {
        let cols: Vec<_> = a.axis_iter(Axis(1)).map(|col| self.apply(&col)).collect();
        hstack(&cols).unwrap()
    }

    /// Apply operator to matrix in-place
    fn apply2_mut<S>(&self, a: &mut ArrayBase<S, Ix2>)
    where
        S: DataMut<Elem = Self::Elem>,
    {
        for mut col in a.axis_iter_mut(Axis(1)) {
            self.apply_mut(&mut col)
        }
    }

    /// Apply operator to matrix with move
    fn apply2_into<S>(&self, mut a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix2>
    where
        S: DataOwned<Elem = Self::Elem> + DataMut,
    {
        self.apply2_mut(&mut a);
        a
    }
}

impl LinearOperator for ArrayBase<Sa, Ix2>
where
    A: Scalar,
    Sa: Data<Elem = A>,
{
    type Elem = A;

    fn apply<S>(&self, a: &ArrayBase<S, Ix1>) -> Array1
    where
        S: Data<Elem = A>,
    {
        self.dot(a)
    }
}
<|endoftext|>


<commit_before>use std;

use bits;
use system::{SystemParams, P25Params};

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulse<T, S: SystemParams> {
    system: std::marker::PhantomData<S>,
    /// The dibit source to iterate over.
    src: T,
    /// Current global sample index.
    sample: usize,
}

impl<T, S = P25Params> C4FMImpulse<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    /// Construct a new `C4FMImpulse<T>` from the given source and sample rate.
    pub fn new(src: T) -> C4FMImpulse<T, S> {
        C4FMImpulse {
            system: std::marker::PhantomData,
            src: src,
            sample: 0,
        }
    }
}

impl<T, S> Iterator for C4FMImpulse<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % S::period() != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit.bits() {
                0b01 => Some(1800.0),
                0b00 => Some(600.0),
                0b10 => Some(-600.0),
                0b11 => Some(-1800.0),
                _ => unreachable!(),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            bits::Dibit::new(0b01)
        } else {
            bits::Dibit::new(0b11)
        })
    }
}

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

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = bits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulse::new(d);

        assert!(imp.next().unwrap() == 600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
    }
}
<commit_msg>s/C4FMImpulse/C4FMImpulses/<commit_after>use std;

use bits;
use system::{SystemParams, P25Params};

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulses<T, S: SystemParams> {
    system: std::marker::PhantomData<S>,
    /// The dibit source to iterate over.
    src: T,
    /// Current global sample index.
    sample: usize,
}

impl<T, S = P25Params> C4FMImpulses<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    /// Construct a new `C4FMImpulses<T>` from the given source and sample rate.
    pub fn new(src: T) -> C4FMImpulses<T, S> {
        C4FMImpulses {
            system: std::marker::PhantomData,
            src: src,
            sample: 0,
        }
    }
}

impl<T, S> Iterator for C4FMImpulses<T, S> where
    T: Iterator<Item = bits::Dibit>,
    S: SystemParams
{
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % S::period() != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit.bits() {
                0b01 => Some(1800.0),
                0b00 => Some(600.0),
                0b10 => Some(-600.0),
                0b11 => Some(-1800.0),
                _ => unreachable!(),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = bits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            bits::Dibit::new(0b01)
        } else {
            bits::Dibit::new(0b11)
        })
    }
}

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

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = bits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulses::new(d);

        assert!(imp.next().unwrap() == 600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b01);
        assert!(d.next().unwrap().bits() == 0b11);
        assert!(d.next().unwrap().bits() == 0b11);
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::sync::mpsc::TryRecvError;
use std::time::{Instant, Duration};
use std::thread;
use pbr::{ProgressBar, Units};

// like a beautiful film
static REFRESH_DELAY: u64 = 1000 / 15;

pub struct Progress {
    thread: thread::JoinHandle<()>,
    tx: mpsc::Sender<Msg>,
}

pub enum Msg {
    SetMessage(String),
    SetSize(u64),
    Add(u64),
    Finish(String),
}

fn new_pb(size: u64) -> ProgressBar<::std::io::Stdout> {
    let mut pb = ProgressBar::new(size);
    pb.set_units(Units::Bytes);
    pb.format(" =💃 ⛩");
    pb.tick_format("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏");
    pb
}

impl Progress {
    pub fn new() -> Progress {
        let (tx, rx) = mpsc::channel();
        let t = thread::spawn(move || {
            let mut pb = new_pb(0);
            let mut last_add = Instant::now();
            let mut frame_total: u64 = 0;
            let mut frame_message: Option<String> = None;

            loop {
                match rx.try_recv() {
                    Ok(Msg::SetMessage(msg)) => {
                        frame_message = Some(msg);
                    }
                    Ok(Msg::SetSize(size)) => {
                        pb = new_pb(size);
                    }
                    Ok(Msg::Add(size)) => {
                        frame_total += size;
                    }
                    Ok(Msg::Finish(msg)) => {
                        pb.finish_print(&msg);
                        break;
                    }
                    Err(TryRecvError::Empty) => {
                        if let Some(msg) = frame_message {
                            pb.message(&msg);
                        }
                        if pb.total > 0 {
                            pb.add(frame_total);
                        }
                        if frame_total > 0 {
                            last_add = Instant::now();
                            pb.add(frame_total);
                        } else if last_add.elapsed() < Duration::from_secs(5) {
                            pb.tick();
                        }

                        frame_message = None;
                        frame_total = 0;
                        thread::sleep(Duration::from_millis(REFRESH_DELAY));
                    }
                    _ => {
                        panic!("disconnected channel");
                    }
                }
            }
        });
        Progress {
            thread: t,
            tx: tx,
        }
    }

    pub fn message<S: Into<String>>(&self, msg: S) {
        self.tx.send(Msg::SetMessage(msg.into())).unwrap();
    }

    pub fn finish<S: Into<String>>(self, msg: S) {
        self.tx.send(Msg::Finish(msg.into())).unwrap();
        let _ = self.thread.join();
    }

    pub fn add(&self, amount: u64) {
        self.tx.send(Msg::Add(amount)).unwrap();
    }

    pub fn size(&self, size: u64) {
        self.tx.send(Msg::SetSize(size)).unwrap();
    }
}

<commit_msg>formatting fixes<commit_after>use std::sync::mpsc;
use std::sync::mpsc::TryRecvError;
use std::time::{Instant, Duration};
use std::thread;
use std::io::Stdout;
use pbr::{ProgressBar, Units};

// like a beautiful film
static REFRESH_DELAY: u64 = 1000 / 15;

pub struct Progress {
    thread: thread::JoinHandle<()>,
    tx: mpsc::Sender<Msg>,
}

pub enum Msg {
    SetMessage(String),
    SetSize(u64),
    Add(u64),
    Finish(String),
}

fn new_pb(size: u64) -> ProgressBar<Stdout> {
    let mut pb = ProgressBar::new(size);
    pb.set_units(Units::Bytes);
    pb.format(" =💃 ⛩");
    pb.tick_format("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏");
    pb
}

fn do_maybe<F>(pb_maybe: &mut Option<ProgressBar<Stdout>>, f: F)
    where F : Fn(&mut ProgressBar<Stdout>) -> ()
{
    if let Some(ref mut pb) = pb_maybe.as_mut() {
        f(pb);
    }
}

impl Progress {
    pub fn new() -> Progress {
        let (tx, rx) = mpsc::channel();
        let t = thread::spawn(move || {
            let mut pb = None;
            let mut last_add = Instant::now();
            let mut frame_total: u64 = 0;
            let mut frame_message: Option<String> = None;

            loop {
                match rx.try_recv() {
                    Ok(Msg::SetMessage(msg)) => {
                        frame_message = Some(msg);
                    }
                    Ok(Msg::SetSize(size)) => {
                        pb = Some(new_pb(size));
                    }
                    Ok(Msg::Add(size)) => {
                        frame_total += size;
                    }
                    Ok(Msg::Finish(msg)) => {
                        do_maybe(&mut pb, |pb| pb.finish_print(&msg));
                        break;
                    }
                    Err(TryRecvError::Empty) => {
                        if let Some(msg) = frame_message {
                            do_maybe(&mut pb, |pb| pb.message(&msg));
                        }
                        do_maybe(&mut pb, |pb| {
                            if pb.total > 0 {
                                pb.add(frame_total);
                            }
                        });
                        if frame_total > 0 {
                            last_add = Instant::now();
                            do_maybe(&mut pb, |pb| { pb.add(frame_total); });
                        } else if last_add.elapsed() < Duration::from_secs(5) {
                            do_maybe(&mut pb, |pb| pb.tick());
                        }

                        frame_message = None;
                        frame_total = 0;
                        thread::sleep(Duration::from_millis(REFRESH_DELAY));
                    }
                    _ => {
                        panic!("disconnected channel");
                    }
                }
            }
        });
        Progress {
            thread: t,
            tx: tx,
        }
    }

    pub fn message<S: Into<String>>(&self, msg: S) {
        self.tx.send(Msg::SetMessage(msg.into())).unwrap();
    }

    pub fn finish<S: Into<String>>(self, msg: S) {
        self.tx.send(Msg::Finish(msg.into())).unwrap();
        let _ = self.thread.join();
    }

    pub fn add(&self, amount: u64) {
        self.tx.send(Msg::Add(amount)).unwrap();
    }

    pub fn size(&self, size: u64) {
        self.tx.send(Msg::SetSize(size)).unwrap();
    }
}

<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::io::ErrorKind;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Illumos/Solaris requires explicit linking with libnsl
    if target.contains("solaris") {
        println!("cargo:rustc-flags=-l nsl");
    }

    // Next, fall back and try to use pkg-config if its available.
    if !target.contains("windows") {
        match pkg_config::find_library("libcurl") {
            Ok(lib) => {
                for path in lib.include_paths.iter() {
                    println!("cargo:include={}", path.display());
                }
                return
            }
            Err(e) => println!("Couldn't find libcurl from \
                               pkgconfig ({:?}), compiling it from source...", e),
        }
    }

    if !Path::new("curl/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=crypt32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    cmd.env("CC", compiler.path())
       .env("CFLAGS", cflags)
       .env("LD", &which("ld").unwrap())
       .env("VERBOSE", "1")
       .current_dir(&dst.join("build"))
       .arg(msys_compatible(&src.join("curl/configure")));

    // For now this build script doesn't support paths with spaces in them. This
    // is arguably a but in curl's configure script, but we could also try to
    // paper over it by using a tmp directory which *doesn't* have spaces in it.
    // As of now though that's not implemented so just give a nicer error for
    // the time being.
    let wants_space_error = windows &&
        (dst.to_str().map(|s| s.contains(" ")).unwrap_or(false) ||
         src.to_str().map(|s| s.contains(" ")).unwrap_or(false));
    if wants_space_error {
        panic!("\n\nunfortunately ./configure of libcurl is known to \
                fail if there's a space in the path to the current \
                directory\n\n\
                there's a space in either\n  {}\n  {}\nand this will cause the \
                build to fail\n\n\
                the MSVC build should work with a directory that has \
                spaces in it, and it would also work to move this to a \
                different directory without spaces\n\n",
               src.display(), dst.display())
    }

    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");
        register_dep("OPENSSL");
    }
    register_dep("Z");
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => {
            cmd.arg("--enable-optimize");
        }
        _ => {
            cmd.arg("--enable-debug");
            cmd.arg("--disable-optimize");
        }
    }
    cmd.arg(format!("--prefix={}", msys_compatible(&dst)));

    if target != host &&
       (!target.contains("windows") || !host.contains("windows")) {
        cmd.arg(format!("--host={}", host));
        cmd.arg(format!("--target={}", target));
    }

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--without-nghttp2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");
    cmd.arg("--disable-smb");
    cmd.arg("--disable-sspi");

    run(&mut cmd, "sh");
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")), "make");
    run(Command::new(make())
                .arg("install")
                .current_dir(&dst.join("build")), "make");
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn msys_compatible(path: &Path) -> String {
    let path = path.to_str().unwrap();
    if !cfg!(windows) {
        return path.to_string()
    }
    path.replace("C:\\", "/c/")
        .replace("\\", "/")
}

fn register_dep(dep: &str) {
    if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
        prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        return
    }
    if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
        let root = Path::new(&s).parent().unwrap();
        env::set_var(&format!("DEP_{}_ROOT", dep), root);
        let path = root.join("lib/pkgconfig");
        if path.exists() {
            prepend("PKG_CONFIG_PATH", path);
            return
        }
    }

    fn prepend(var: &str, val: PathBuf) {
        let prefix = env::var(var).unwrap_or(String::new());
        let mut v = vec![val];
        v.extend(env::split_paths(&prefix));
        env::set_var(var, &env::join_paths(v).unwrap());
    }
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd, "nmake");

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<commit_msg>Still pass --with args<commit_after>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::io::ErrorKind;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Illumos/Solaris requires explicit linking with libnsl
    if target.contains("solaris") {
        println!("cargo:rustc-flags=-l nsl");
    }

    // Next, fall back and try to use pkg-config if its available.
    if !target.contains("windows") {
        match pkg_config::find_library("libcurl") {
            Ok(lib) => {
                for path in lib.include_paths.iter() {
                    println!("cargo:include={}", path.display());
                }
                return
            }
            Err(e) => println!("Couldn't find libcurl from \
                               pkgconfig ({:?}), compiling it from source...", e),
        }
    }

    if !Path::new("curl/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=crypt32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    cmd.env("CC", compiler.path())
       .env("CFLAGS", cflags)
       .env("LD", &which("ld").unwrap())
       .env("VERBOSE", "1")
       .current_dir(&dst.join("build"))
       .arg(msys_compatible(&src.join("curl/configure")));

    // For now this build script doesn't support paths with spaces in them. This
    // is arguably a but in curl's configure script, but we could also try to
    // paper over it by using a tmp directory which *doesn't* have spaces in it.
    // As of now though that's not implemented so just give a nicer error for
    // the time being.
    let wants_space_error = windows &&
        (dst.to_str().map(|s| s.contains(" ")).unwrap_or(false) ||
         src.to_str().map(|s| s.contains(" ")).unwrap_or(false));
    if wants_space_error {
        panic!("\n\nunfortunately ./configure of libcurl is known to \
                fail if there's a space in the path to the current \
                directory\n\n\
                there's a space in either\n  {}\n  {}\nand this will cause the \
                build to fail\n\n\
                the MSVC build should work with a directory that has \
                spaces in it, and it would also work to move this to a \
                different directory without spaces\n\n",
               src.display(), dst.display())
    }

    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");
        if let Some(root) = register_dep("OPENSSL") {
            cmd.arg(format!("--with-ssl={}", root.display()));
        }
    }
    if let Some(root) = register_dep("Z") {
        cmd.arg(format!("--with-zlib={}", root.display()));
    }
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => {
            cmd.arg("--enable-optimize");
        }
        _ => {
            cmd.arg("--enable-debug");
            cmd.arg("--disable-optimize");
        }
    }
    cmd.arg(format!("--prefix={}", msys_compatible(&dst)));

    if target != host &&
       (!target.contains("windows") || !host.contains("windows")) {
        cmd.arg(format!("--host={}", host));
        cmd.arg(format!("--target={}", target));
    }

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--without-nghttp2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");
    cmd.arg("--disable-smb");
    cmd.arg("--disable-sspi");

    run(&mut cmd, "sh");
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")), "make");
    run(Command::new(make())
                .arg("install")
                .current_dir(&dst.join("build")), "make");
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn msys_compatible(path: &Path) -> String {
    let path = path.to_str().unwrap();
    if !cfg!(windows) {
        return path.to_string()
    }
    path.replace("C:\\", "/c/")
        .replace("\\", "/")
}

fn register_dep(dep: &str) -> Option<PathBuf> {
    if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
        prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        return Some(s.into())
    }
    if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
        let root = Path::new(&s).parent().unwrap();
        env::set_var(&format!("DEP_{}_ROOT", dep), root);
        let path = root.join("lib/pkgconfig");
        if path.exists() {
            prepend("PKG_CONFIG_PATH", path);
            return Some(root.to_path_buf())
        }
    }

    return None;

    fn prepend(var: &str, val: PathBuf) {
        let prefix = env::var(var).unwrap_or(String::new());
        let mut v = vec![val];
        v.extend(env::split_paths(&prefix));
        env::set_var(var, &env::join_paths(v).unwrap());
    }
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd, "nmake");

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<|endoftext|>


<commit_before>use qdowncast::QDowncastable;
use qindex_multi::MultiIndexable;

use std::any::{Any, TypeId};
use std::borrow::Borrow;
use std::collections::btree_map::{self, BTreeMap};
use std::ops::{Index, IndexMut};

// ++++++++++++++++++++ ServiceReflect ++++++++++++++++++++

/// Our `Reflect`-derivative.
/// This supplies necessary information for retrieving an service at compile-time.
pub trait ServiceReflect: Any {
    fn option_name() -> &'static str;
}

// ++++++++++++++++++++ GetSerectError ++++++++++++++++++++

#[derive(Debug, Clone)]
pub enum GetSerectError<'a> {
    TypeMismatch{ option_name: &'a str, expected: TypeId, found: TypeId },
    MissingOption(&'a str),
}

impl<'a> GetSerectError<'a> {
    pub fn type_mismatch<Expected>(found: TypeId) -> GetSerectError<'static>
        where Expected: ServiceReflect
    {
        GetSerectError::TypeMismatch{
            option_name: Expected::option_name(),
            expected: TypeId::of::<Expected>(),
            found: found,
        }
    }
}

pub type GetSerectResult<'a, T> = Result<T, GetSerectError<'a>>;

// ++++++++++++++++++++ WiringOption ++++++++++++++++++++

/// TODO expose this to the user?
enum WiringOption<Ser: Any + ?Sized> {
    /// An option with zero or more alternatives. May be wired to one of its services.
    Multi{
        wired: Option<usize>,
        alternatives: Vec<(String, Box<Ser>)>,
    },
    /// A single alternative option. Is always wired to exactly one service.
    Single(Box<Ser>),
}

impl<Ser: Any + ?Sized> WiringOption<Ser> {
    fn has_alternative(&self, alt_name: &str) -> bool {
        match self {
            &WiringOption::Multi{ ref alternatives, .. } => {
                alternatives.iter().any(|e| &*e.0 == alt_name)
            }
            _ => false,
        }
    }

    fn add_alternative(&mut self, alt_name: String, service: Box<Ser>){
        assert!(!self.has_alternative(&alt_name),
                "Alternative '{}' already exists,", alt_name);

        match self {
            &mut WiringOption::Multi{ ref mut alternatives, .. } => {
                alternatives.push((alt_name, service));
            }
            _ => {
                panic!("can't add alternative '{}' to single alternative option", alt_name);
            }
        }
    }

    fn wire_alternative(&mut self, alt_name: &str) {
        assert!(self.has_alternative(&alt_name),
                "Can't wire missing alternative '{}'", alt_name);

        match self {
            &mut WiringOption::Multi{ ref mut wired, ref alternatives } => {
                *wired = Some(alternatives.iter().position(|e| &*e.0 == alt_name).unwrap());
            }
            _ => { unreachable!() }
        }
    }

    fn service(&self) -> Option<&Ser> {
        match self {
            &WiringOption::Single(ref service) => Some(&**service),
            &WiringOption::Multi{ wired, ref alternatives } => match wired {
                Some(idx) => Some(&*alternatives[idx].1),
                None => None,
            }
        }
    }

    fn service_mut(&mut self) -> Option<&mut Ser> {
        match self {
            &mut WiringOption::Single(ref mut service) => Some(&mut**service),
            &mut WiringOption::Multi{ wired, ref mut alternatives } => match wired {
                Some(idx) => Some(&mut*alternatives[idx].1),
                None => None,
            }
        }
    }
}

// ++++++++++++++++++++ ServiceMap ++++++++++++++++++++

pub trait DefaultBase: Any {}
impl<T: Any + ?Sized> DefaultBase for T {}
qdowncastable!(DefaultBase);
qdowncast_methods!(DefaultBase);

pub struct ServiceMap<Ser: Any + ?Sized = DefaultBase> {
    options: BTreeMap<String, WiringOption<Ser>>,
}

impl<Ser: Any + ?Sized> ServiceMap<Ser> {
    /// Gets the service wired to option `opt_name` immutably.
    pub fn get_service(&self, opt_name: &str) -> Option<&Ser> {
        self.options.get(opt_name).and_then(|option| option.service())
    }

    /// Gets the service wired to option `opt_name` mutably.
    pub fn get_service_mut(&mut self, opt_name: &str) -> Option<&mut Ser> {
        self.options.get_mut(opt_name).and_then(|option| option.service_mut())
    }

    /// Gets the service wired to option `opt_name` immutably, then tries to downcast it.
    pub fn get<T>(&self) -> GetSerectResult<&T>
        where T: ServiceReflect, Ser: QDowncastable<T>
    {
        match self.get_service(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_ref(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetSerectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetSerectError::MissingOption(T::option_name()))
        }
    }

    /// Gets the service wired to option `opt_name` mutably, then tries to downcast it.
    pub fn get_mut<T>(&mut self) -> GetSerectResult<&mut T>
        where T: ServiceReflect, Ser: QDowncastable<T>
    {
        match self.get_service_mut(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_mut(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetSerectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetSerectError::MissingOption(T::option_name()))
        }
    }

    /// Iterate over all wired services immutably.
    pub fn iter(&self) -> Iter<Ser> {
        Iter{ options: self.options.iter() }
    }

    /// Iterate over all wired services mutably.
    pub fn iter_mut(&mut self) -> IterMut<Ser> {
        IterMut{ options: self.options.iter_mut() }
    }
}

/// TODO impl more Iterator-traits?
#[derive(Clone)]
pub struct Iter<'a, Ser: Any + ?Sized = DefaultBase> {
    options: btree_map::Iter<'a, String, WiringOption<Ser>>,
}

impl<'a, Ser: Any + ?Sized> Iterator for Iter<'a, Ser> {
    type Item = (&'a str, &'a Ser);
    fn next(&mut self) -> Option<Self::Item> {
        match self.options.next() {
            Some((opt_name, option)) => match option.service() {
                Some(service) => Some((&opt_name, service)),
                None => self.next(),
            },
            None => None,
        }
    }
}

/// TODO impl more Iterator-traits?
pub struct IterMut<'a, Ser: Any + ?Sized = DefaultBase> {
    options: btree_map::IterMut<'a, String, WiringOption<Ser>>,
}

impl<'a, Ser: Any + ?Sized> Iterator for IterMut<'a, Ser> {
    type Item = (&'a str, &'a mut Ser);
    fn next(&mut self) -> Option<Self::Item> {
        match self.options.next() {
            Some((opt_name, option)) => match option.service_mut() {
                Some(service) => Some((&opt_name, service)),
                None => self.next(),
            },
            None => None,
        }
    }
}

impl<'a, Ser: Any + ?Sized> IntoIterator for &'a ServiceMap<Ser> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Iter<'a, Ser>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

impl<'a, Ser: Any + ?Sized> IntoIterator for &'a mut ServiceMap<Ser> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = IterMut<'a, Ser>;
    fn into_iter(self) -> Self::IntoIter { self.iter_mut() }
}

impl<'a, Str, Ser: ?Sized> Index<&'a Str> for ServiceMap<Ser>
    where Str: Ord + Borrow<str>, Ser: Any
{
    type Output = Ser;
    fn index(&self, name: &'a Str) -> &Self::Output {
        self.get_service(name.borrow()).unwrap()
    }
}

impl<'a, Str, Ser: ?Sized> IndexMut<&'a Str> for ServiceMap<Ser>
    where Str: Ord + Borrow<str>, Ser: Any
{
    fn index_mut(&mut self, name: &'a Str) -> &mut Self::Output {
        self.get_service_mut(name.borrow()).unwrap()
    }
}

unsafe impl<'a, Str, Ser: ?Sized> MultiIndexable<&'a Str> for ServiceMap<Ser>
    where Str: Ord + Borrow<str>, Ser: Any
{}

// ++++++++++++++++++++ ServiceRegister ++++++++++++++++++++

pub struct ServiceRegister<Ser: Any + ?Sized = DefaultBase>{
    services: ServiceMap<Ser>
}

// TODO: remove duplicated code
impl<Ser: Any + ?Sized> ServiceRegister<Ser> {
    pub fn new() -> ServiceRegister<Ser> {
        ServiceRegister{
            services: ServiceMap{ options: BTreeMap::new() }
        }
    }

    pub fn services(&self) -> &ServiceMap<Ser> { &self.services }
    pub fn services_mut(&mut self) -> &mut ServiceMap<Ser> { &mut self.services }
    pub fn into_services(self) -> ServiceMap<Ser> { self.services }

    /// Adds a option to the register.
    pub fn add_option(&mut self, name: String){
        assert!(!self.services.options.contains_key(&name), "option '{}' already exists!", &name);

        self.services.options.insert(name, WiringOption::Multi{
            wired: None, alternatives: Vec::new()
        });
    }

    /// Adds an alternative to an option of the register.
    pub fn add_alternative(&mut self, opt_name: &str, alt_name: String, service: Box<Ser>){
        let option = self.services.options.get_mut(opt_name);
        let option = option.expect(&format!("option '{}' doesn't exist", &opt_name));

        option.add_alternative(alt_name, service);
    }

    /// Wires an alternative of an option of this register.
    pub fn wire_alternative(&mut self, opt_name: &str, alt_name: &str){
        let option = self.services.options.get_mut(opt_name);
        let option = option.expect(&format!("option '{}' doesn't exist", &opt_name));

        option.wire_alternative(alt_name);
    }

    /// Adds a single alternative option to the register.
    pub fn add_single(&mut self, name: String, service: Box<Ser>){
        assert!(self.services.options.contains_key(&name), "option '{}' already exists!", &name);

        self.services.options.insert(name, WiringOption::Single(service));
    }
}

<commit_msg>rename GetSerectError => GetServiceError<commit_after>use qdowncast::QDowncastable;
use qindex_multi::MultiIndexable;

use std::any::{Any, TypeId};
use std::borrow::Borrow;
use std::collections::btree_map::{self, BTreeMap};
use std::ops::{Index, IndexMut};

// ++++++++++++++++++++ ServiceReflect ++++++++++++++++++++

/// Our `Reflect`-derivative.
/// This supplies necessary information for retrieving an service at compile-time.
pub trait ServiceReflect: Any {
    fn option_name() -> &'static str;
}

// ++++++++++++++++++++ GetSerectError ++++++++++++++++++++

#[derive(Debug, Clone)]
pub enum GetSerivceError<'a> {
    TypeMismatch{ option_name: &'a str, expected: TypeId, found: TypeId },
    MissingOption(&'a str),
}

impl<'a> GetSerectError<'a> {
    pub fn type_mismatch<Expected>(found: TypeId) -> GetSerivceError<'static>
        where Expected: ServiceReflect
    {
        GetSerectError::TypeMismatch{
            option_name: Expected::option_name(),
            expected: TypeId::of::<Expected>(),
            found: found,
        }
    }
}

pub type GetSerectResult<'a, T> = Result<T, GetSerectError<'a>>;

// ++++++++++++++++++++ WiringOption ++++++++++++++++++++

/// TODO expose this to the user?
enum WiringOption<Ser: Any + ?Sized> {
    /// An option with zero or more alternatives. May be wired to one of its services.
    Multi{
        wired: Option<usize>,
        alternatives: Vec<(String, Box<Ser>)>,
    },
    /// A single alternative option. Is always wired to exactly one service.
    Single(Box<Ser>),
}

impl<Ser: Any + ?Sized> WiringOption<Ser> {
    fn has_alternative(&self, alt_name: &str) -> bool {
        match self {
            &WiringOption::Multi{ ref alternatives, .. } => {
                alternatives.iter().any(|e| &*e.0 == alt_name)
            }
            _ => false,
        }
    }

    fn add_alternative(&mut self, alt_name: String, service: Box<Ser>){
        assert!(!self.has_alternative(&alt_name),
                "Alternative '{}' already exists,", alt_name);

        match self {
            &mut WiringOption::Multi{ ref mut alternatives, .. } => {
                alternatives.push((alt_name, service));
            }
            _ => {
                panic!("can't add alternative '{}' to single alternative option", alt_name);
            }
        }
    }

    fn wire_alternative(&mut self, alt_name: &str) {
        assert!(self.has_alternative(&alt_name),
                "Can't wire missing alternative '{}'", alt_name);

        match self {
            &mut WiringOption::Multi{ ref mut wired, ref alternatives } => {
                *wired = Some(alternatives.iter().position(|e| &*e.0 == alt_name).unwrap());
            }
            _ => { unreachable!() }
        }
    }

    fn service(&self) -> Option<&Ser> {
        match self {
            &WiringOption::Single(ref service) => Some(&**service),
            &WiringOption::Multi{ wired, ref alternatives } => match wired {
                Some(idx) => Some(&*alternatives[idx].1),
                None => None,
            }
        }
    }

    fn service_mut(&mut self) -> Option<&mut Ser> {
        match self {
            &mut WiringOption::Single(ref mut service) => Some(&mut**service),
            &mut WiringOption::Multi{ wired, ref mut alternatives } => match wired {
                Some(idx) => Some(&mut*alternatives[idx].1),
                None => None,
            }
        }
    }
}

// ++++++++++++++++++++ ServiceMap ++++++++++++++++++++

pub trait DefaultBase: Any {}
impl<T: Any + ?Sized> DefaultBase for T {}
qdowncastable!(DefaultBase);
qdowncast_methods!(DefaultBase);

pub struct ServiceMap<Ser: Any + ?Sized = DefaultBase> {
    options: BTreeMap<String, WiringOption<Ser>>,
}

impl<Ser: Any + ?Sized> ServiceMap<Ser> {
    /// Gets the service wired to option `opt_name` immutably.
    pub fn get_service(&self, opt_name: &str) -> Option<&Ser> {
        self.options.get(opt_name).and_then(|option| option.service())
    }

    /// Gets the service wired to option `opt_name` mutably.
    pub fn get_service_mut(&mut self, opt_name: &str) -> Option<&mut Ser> {
        self.options.get_mut(opt_name).and_then(|option| option.service_mut())
    }

    /// Gets the service wired to option `opt_name` immutably, then tries to downcast it.
    pub fn get<T>(&self) -> GetSerectResult<&T>
        where T: ServiceReflect, Ser: QDowncastable<T>
    {
        match self.get_service(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_ref(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetSerectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetSerectError::MissingOption(T::option_name()))
        }
    }

    /// Gets the service wired to option `opt_name` mutably, then tries to downcast it.
    pub fn get_mut<T>(&mut self) -> GetSerectResult<&mut T>
        where T: ServiceReflect, Ser: QDowncastable<T>
    {
        match self.get_service_mut(T::option_name()) {
            Some(base) => {
                let ty = (&*base).get_type_id();
                match QDowncastable::downcast_mut(base) {
                    Some(ret) => Ok(ret),
                    None => Err(GetSerectError::type_mismatch::<T>(ty))
                }
            }
            None => Err(GetSerectError::MissingOption(T::option_name()))
        }
    }

    /// Iterate over all wired services immutably.
    pub fn iter(&self) -> Iter<Ser> {
        Iter{ options: self.options.iter() }
    }

    /// Iterate over all wired services mutably.
    pub fn iter_mut(&mut self) -> IterMut<Ser> {
        IterMut{ options: self.options.iter_mut() }
    }
}

/// TODO impl more Iterator-traits?
#[derive(Clone)]
pub struct Iter<'a, Ser: Any + ?Sized = DefaultBase> {
    options: btree_map::Iter<'a, String, WiringOption<Ser>>,
}

impl<'a, Ser: Any + ?Sized> Iterator for Iter<'a, Ser> {
    type Item = (&'a str, &'a Ser);
    fn next(&mut self) -> Option<Self::Item> {
        match self.options.next() {
            Some((opt_name, option)) => match option.service() {
                Some(service) => Some((&opt_name, service)),
                None => self.next(),
            },
            None => None,
        }
    }
}

/// TODO impl more Iterator-traits?
pub struct IterMut<'a, Ser: Any + ?Sized = DefaultBase> {
    options: btree_map::IterMut<'a, String, WiringOption<Ser>>,
}

impl<'a, Ser: Any + ?Sized> Iterator for IterMut<'a, Ser> {
    type Item = (&'a str, &'a mut Ser);
    fn next(&mut self) -> Option<Self::Item> {
        match self.options.next() {
            Some((opt_name, option)) => match option.service_mut() {
                Some(service) => Some((&opt_name, service)),
                None => self.next(),
            },
            None => None,
        }
    }
}

impl<'a, Ser: Any + ?Sized> IntoIterator for &'a ServiceMap<Ser> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Iter<'a, Ser>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

impl<'a, Ser: Any + ?Sized> IntoIterator for &'a mut ServiceMap<Ser> {
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = IterMut<'a, Ser>;
    fn into_iter(self) -> Self::IntoIter { self.iter_mut() }
}

impl<'a, Str, Ser: ?Sized> Index<&'a Str> for ServiceMap<Ser>
    where Str: Ord + Borrow<str>, Ser: Any
{
    type Output = Ser;
    fn index(&self, name: &'a Str) -> &Self::Output {
        self.get_service(name.borrow()).unwrap()
    }
}

impl<'a, Str, Ser: ?Sized> IndexMut<&'a Str> for ServiceMap<Ser>
    where Str: Ord + Borrow<str>, Ser: Any
{
    fn index_mut(&mut self, name: &'a Str) -> &mut Self::Output {
        self.get_service_mut(name.borrow()).unwrap()
    }
}

unsafe impl<'a, Str, Ser: ?Sized> MultiIndexable<&'a Str> for ServiceMap<Ser>
    where Str: Ord + Borrow<str>, Ser: Any
{}

// ++++++++++++++++++++ ServiceRegister ++++++++++++++++++++

pub struct ServiceRegister<Ser: Any + ?Sized = DefaultBase>{
    services: ServiceMap<Ser>
}

// TODO: remove duplicated code
impl<Ser: Any + ?Sized> ServiceRegister<Ser> {
    pub fn new() -> ServiceRegister<Ser> {
        ServiceRegister{
            services: ServiceMap{ options: BTreeMap::new() }
        }
    }

    pub fn services(&self) -> &ServiceMap<Ser> { &self.services }
    pub fn services_mut(&mut self) -> &mut ServiceMap<Ser> { &mut self.services }
    pub fn into_services(self) -> ServiceMap<Ser> { self.services }

    /// Adds a option to the register.
    pub fn add_option(&mut self, name: String){
        assert!(!self.services.options.contains_key(&name), "option '{}' already exists!", &name);

        self.services.options.insert(name, WiringOption::Multi{
            wired: None, alternatives: Vec::new()
        });
    }

    /// Adds an alternative to an option of the register.
    pub fn add_alternative(&mut self, opt_name: &str, alt_name: String, service: Box<Ser>){
        let option = self.services.options.get_mut(opt_name);
        let option = option.expect(&format!("option '{}' doesn't exist", &opt_name));

        option.add_alternative(alt_name, service);
    }

    /// Wires an alternative of an option of this register.
    pub fn wire_alternative(&mut self, opt_name: &str, alt_name: &str){
        let option = self.services.options.get_mut(opt_name);
        let option = option.expect(&format!("option '{}' doesn't exist", &opt_name));

        option.wire_alternative(alt_name);
    }

    /// Adds a single alternative option to the register.
    pub fn add_single(&mut self, name: String, service: Box<Ser>){
        assert!(self.services.options.contains_key(&name), "option '{}' already exists!", &name);

        self.services.options.insert(name, WiringOption::Single(service));
    }
}

<|endoftext|>