<commit_before>extern crate futures;
extern crate env_logger;
extern crate futuremio;
extern crate ssl;

#[macro_use]
extern crate cfg_if;

use std::io::{Write, ErrorKind, Error};
use std::net::ToSocketAddrs;

use futures::Future;
use futures::stream::Stream;
use futures::io::{self, Ready};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl as ossl;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let errs = match *err.downcast_ref::<ossl::Error>().unwrap() {
                ossl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            };
            assert!(errs.iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", errs);
        }
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }
    } else {
        extern crate winapi;

        fn assert_bad_hostname_error(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }
    }
}

#[test]
fn fetch_google() {
    drop(env_logger::init());

    // First up, resolve google.com
    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    // Create an event loop and connect a socket to our resolved address.c
    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);

    // Send off the request by first negotiating an SSL handshake, then writing
    // of our request, then flushing, then finally read off the response.
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("google.com", socket)
    }).and_then(|socket| {
        write_all(socket, b"GET / HTTP/1.0\r\n\r\n")
    }).and_then(|socket| {
        io::flush(socket)
    }).and_then(|socket| {
        io::read_to_end(socket, Vec::new())
    });

    let data = t!(l.run(data));
    assert!(data.starts_with(b"HTTP/1.0 200 OK"));
    assert!(data.ends_with(b""));
}

#[test]
fn wrong_hostname_error() {
    drop(env_logger::init());

    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("rust-lang.org", socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    assert_bad_hostname_error(&res.err().unwrap());
}

fn write_all<W>(mut socket: W, mut data: &'static [u8])
                -> Box<Future<Item=W, Error=Error>>
    where W: Write + Stream<Item=Ready, Error=Error>,
{
    while data.len() > 0 {
        match socket.write(data) {
            Ok(n) => {
                println!("wrote: {}", n);
                data = &data[n..];
            }
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
            Err(e) => return futures::failed(e).boxed(),
        }
    }
    if data.len() == 0 {
        futures::finished(socket).boxed()
    } else {
        socket.into_future().map_err(|e| e.0).and_then(move |(_, w)| {
            write_all(w, data)
        }).boxed()
    }
}
<commit_msg>Same ignore reason on OSX for another test<commit_after>extern crate futures;
extern crate env_logger;
extern crate futuremio;
extern crate ssl;

#[macro_use]
extern crate cfg_if;

use std::io::{Write, ErrorKind, Error};
use std::net::ToSocketAddrs;

use futures::Future;
use futures::stream::Stream;
use futures::io::{self, Ready};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

cfg_if! {
    if #[cfg(any(feature = "force-openssl",
                 all(not(target_os = "macos"),
                     not(target_os = "windows"))))] {
        extern crate openssl;

        use openssl::ssl as ossl;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let errs = match *err.downcast_ref::<ossl::Error>().unwrap() {
                ossl::Error::Ssl(ref v) => v,
                ref e => panic!("not an ssl eror: {:?}", e),
            };
            assert!(errs.iter().any(|e| {
                e.reason() == "certificate verify failed"
            }), "bad errors: {:?}", errs);
        }
    } else if #[cfg(target_os = "macos")] {
        extern crate security_framework;

        use security_framework::base::Error as SfError;

        fn assert_bad_hostname_error(err: &Error) {
            let err = err.get_ref().unwrap();
            let err = err.downcast_ref::<SfError>().unwrap();
            assert_eq!(err.message().unwrap(), "invalid certificate chain");
        }
    } else {
        extern crate winapi;

        fn assert_bad_hostname_error(err: &Error) {
            let code = err.raw_os_error().unwrap();
            assert_eq!(code as usize, winapi::CERT_E_CN_NO_MATCH as usize);
        }
    }
}

#[test]
fn fetch_google() {
    drop(env_logger::init());

    // First up, resolve google.com
    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    // Create an event loop and connect a socket to our resolved address.c
    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);

    // Send off the request by first negotiating an SSL handshake, then writing
    // of our request, then flushing, then finally read off the response.
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("google.com", socket)
    }).and_then(|socket| {
        write_all(socket, b"GET / HTTP/1.0\r\n\r\n")
    }).and_then(|socket| {
        io::flush(socket)
    }).and_then(|socket| {
        io::read_to_end(socket, Vec::new())
    });

    let data = t!(l.run(data));
    assert!(data.starts_with(b"HTTP/1.0 200 OK"));
    assert!(data.ends_with(b""));
}

// see comment in bad.rs for ignore reason
#[cfg_attr(all(target_os = "macos", feature = "force-openssl"), ignore)]
#[test]
fn wrong_hostname_error() {
    drop(env_logger::init());

    let addr = t!("google.com:443".to_socket_addrs()).next().unwrap();

    let mut l = t!(futuremio::Loop::new());
    let client = l.handle().tcp_connect(&addr);
    let data = client.and_then(move |socket| {
        t!(ssl::ClientContext::new()).handshake("rust-lang.org", socket)
    });

    let res = l.run(data);
    assert!(res.is_err());
    assert_bad_hostname_error(&res.err().unwrap());
}

fn write_all<W>(mut socket: W, mut data: &'static [u8])
                -> Box<Future<Item=W, Error=Error>>
    where W: Write + Stream<Item=Ready, Error=Error>,
{
    while data.len() > 0 {
        match socket.write(data) {
            Ok(n) => {
                println!("wrote: {}", n);
                data = &data[n..];
            }
            Err(ref e) if e.kind() == ErrorKind::WouldBlock => break,
            Err(e) => return futures::failed(e).boxed(),
        }
    }
    if data.len() == 0 {
        futures::finished(socket).boxed()
    } else {
        socket.into_future().map_err(|e| e.0).and_then(move |(_, w)| {
            write_all(w, data)
        }).boxed()
    }
}
<|endoftext|>


<commit_before>use errors::{self, Error};
use methods::Method;
use reflect;

use downcast::{self, Downcast};

use std::any::Any;
use std::collections::BTreeMap;
use std::sync::{TryLockError, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};

fn type_name<T: Any>() -> &'static str {
    "NOT IMPLEMENTED"
    //unsafe { ::std::intrinsics::type_name::<T>() }
}

// ++++++++++++++++++++ Container ++++++++++++++++++++

pub type ReadGuard<'a, T, Base> = downcast::Guard<T, RwLockReadGuard<'a, Box<Base>>>;
pub type WriteGuard<'a, T, Base> = downcast::Guard<T, RwLockWriteGuard<'a, Box<Base>>>;

pub struct Container<Key, SvcBase: ?Sized> {
    services: BTreeMap<Key, RwLock<Box<SvcBase>>>,
    deadlock_protection: Mutex<()>,
}

impl<Key, SvcBase: ?Sized> Container<Key, SvcBase>
    where Key: reflect::Key, SvcBase: Any
{
    #[doc(hidden)]
    pub fn new() -> Self {
        Container{ services: BTreeMap::new(), deadlock_protection: Mutex::new(()) }
    }

    #[doc(hidden)]
    pub fn register_service(&mut self, key: Key, svc: Box<SvcBase>) -> &mut Self {
        self.services.insert(key, RwLock::new(svc));
        self
    }

    #[doc(hidden)]
    pub fn register<Svc>(&mut self, svc: Svc) -> &mut Self
    where
        Svc: reflect::Service<Key = Key> + Into<Box<SvcBase>>,
    {
        self.register_service(Svc::key().clone(), svc.into())
    }

    pub fn services(&self) -> &BTreeMap<Key, RwLock<Box<SvcBase>>> {
        &self.services
    }

    pub fn get_service(&self, key: &Key) -> Option<&RwLock<Box<SvcBase>>> {
        self.services.get(key)
    }

    pub fn read_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockReadGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.read()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn write_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockWriteGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.write()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn read_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.read_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::wrap(base).ok().unwrap())
    }

    pub fn write_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.write_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::wrap(base).ok().unwrap())
    }

    pub fn read<'a, Svc>(
        &'a self
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.read_service(Svc::key())
    }

    pub fn write<'a, Svc>(
        &'a self
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.write_service(Svc::key())
    }

    pub fn try_read_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockReadGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.read()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn try_write_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockWriteGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.write()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn try_read_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.try_read_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::wrap(base).ok().unwrap())
    }

    pub fn try_write_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.try_write_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::wrap(base).ok().unwrap())
    }

    pub fn try_read<'a, Svc>(
        &'a self
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.try_read_service(Svc::key())
    }

    pub fn try_write<'a, Svc>(
        &'a self
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.try_write_service(Svc::key())
    }

    pub fn resolve<'a, M>(&'a self) -> Result<M::Ret, Error<Key>>
        where M: Method<'a, Key, SvcBase>
    {
        let _ = self.deadlock_protection.lock();
        M::resolve_unprotected(self)
    }
    pub fn try_resolve<'a, M>(&'a self) -> Result<M::Ret, Error<Key>>
        where M: Method<'a, Key, SvcBase>
    {
        let _ = self.deadlock_protection.lock();
        M::try_resolve_unprotected(self)
    }
}

// ++++++++++++++++++++ ContainerBuilder ++++++++++++++++++++

pub struct ContainerBuilder<Key, SvcBase: ?Sized> {
    cont: Container<Key, SvcBase>
}

impl<Key, SvcBase: ?Sized> ContainerBuilder<Key, SvcBase>
    where Key: reflect::Key, SvcBase: Any
{
    pub fn new() -> Self {
        ContainerBuilder{ cont: Container::new() }
    }

    pub fn register_service(&mut self, key: Key, svc: Box<SvcBase>) -> &mut Self {
        self.cont.register_service(key, svc);
        self
    }

    /// NOTE: The `Box<Svc>: Into<Box<Base>>`-clause is needed due to rusts lack of
    /// HKT or a `Coercible`-trait (to name two solutions).
    pub fn register<Svc>(&mut self, svc: Svc) -> &mut Self
    where
        Svc: reflect::Service<Key = Key> + Into<Box<SvcBase>>,
    {
        self.cont.register::<Svc>(svc);
        self
    }

    pub fn build(self) -> Container<Key, SvcBase> {
        self.cont
    }
}

impl<Key, SvcBase: ?Sized> Default for ContainerBuilder<Key, SvcBase>
    where Key: reflect::Key, SvcBase: Any
{
    fn default() -> Self { Self::new() }
}
<commit_msg>impl Method for Read<()>, Write<()><commit_after>use errors::{self, Error};
use methods::Method;
use reflect;

use downcast::{self, Downcast};

use std::any::Any;
use std::collections::BTreeMap;
use std::sync::{TryLockError, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};

fn type_name<T: Any>() -> &'static str {
    "NOT IMPLEMENTED"
    //unsafe { ::std::intrinsics::type_name::<T>() }
}

// ++++++++++++++++++++ Container ++++++++++++++++++++

pub type ReadGuard<'a, T, Base: ?Sized> = downcast::Guard<T, RwLockReadGuard<'a, Box<Base>>>;
pub type WriteGuard<'a, T, Base: ?Sized> = downcast::Guard<T, RwLockWriteGuard<'a, Box<Base>>>;

pub struct Container<Key, SvcBase: ?Sized> {
    services: BTreeMap<Key, RwLock<Box<SvcBase>>>,
    deadlock_protection: Mutex<()>,
}

impl<Key, SvcBase: ?Sized> Container<Key, SvcBase>
    where Key: reflect::Key, SvcBase: Any
{
    #[doc(hidden)]
    pub fn new() -> Self {
        Container{ services: BTreeMap::new(), deadlock_protection: Mutex::new(()) }
    }

    #[doc(hidden)]
    pub fn register_service(&mut self, key: Key, svc: Box<SvcBase>) -> &mut Self {
        self.services.insert(key, RwLock::new(svc));
        self
    }

    #[doc(hidden)]
    pub fn register<Svc>(&mut self, svc: Svc) -> &mut Self
    where
        Svc: reflect::Service<Key = Key> + Into<Box<SvcBase>>,
    {
        self.register_service(Svc::key().clone(), svc.into())
    }

    pub fn services(&self) -> &BTreeMap<Key, RwLock<Box<SvcBase>>> {
        &self.services
    }

    pub fn get_service(&self, key: &Key) -> Option<&RwLock<Box<SvcBase>>> {
        self.services.get(key)
    }

    pub fn read_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockReadGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.read()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn write_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockWriteGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.write()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn read_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.read_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::wrap(base).ok().unwrap())
    }

    pub fn write_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.write_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::wrap(base).ok().unwrap())
    }

    pub fn read<'a, Svc>(
        &'a self
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.read_service(Svc::key())
    }

    pub fn write<'a, Svc>(
        &'a self
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.write_service(Svc::key())
    }

    pub fn try_read_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockReadGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.read()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn try_write_service_base<'a>(
        &'a self,
        key: &'a Key
    ) -> Result<RwLockWriteGuard<Box<SvcBase>>, Error<'a, Key>> {
        match self.get_service(key) {
            Some(service) => errors::or_err(key, service.write()),
            None => Err(Error::NotFound{ key: key })
        }
    }

    pub fn try_read_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.try_read_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(ReadGuard::wrap(base).ok().unwrap())
    }

    pub fn try_write_service<'a, Svc>(
        &'a self,
        key: &'a Key
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: Any, SvcBase: Downcast<Svc>
    {
        let base = try!{self.try_write_service_base(key)};
        if !base.is_type() {
            return Err(Error::MismatchedType{
                key: key,
                expected: type_name::<Svc>(),
                found: type_name::<Svc>(),
            })
        };
        Ok(WriteGuard::wrap(base).ok().unwrap())
    }

    pub fn try_read<'a, Svc>(
        &'a self
    ) -> Result<ReadGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.try_read_service(Svc::key())
    }

    pub fn try_write<'a, Svc>(
        &'a self
    ) -> Result<WriteGuard<Svc, SvcBase>, Error<'a, Key>>
        where Svc: reflect::Service<Key = Key>, SvcBase: Downcast<Svc>
    {
        self.try_write_service(Svc::key())
    }

    pub fn resolve<'a, M>(&'a self) -> Result<M::Ret, Error<Key>>
        where M: Method<'a, Key, SvcBase>
    {
        let _ = self.deadlock_protection.lock();
        M::resolve_unprotected(self)
    }
    pub fn try_resolve<'a, M>(&'a self) -> Result<M::Ret, Error<Key>>
        where M: Method<'a, Key, SvcBase>
    {
        let _ = self.deadlock_protection.lock();
        M::try_resolve_unprotected(self)
    }
}

// ++++++++++++++++++++ ContainerBuilder ++++++++++++++++++++

pub struct ContainerBuilder<Key, SvcBase: ?Sized> {
    cont: Container<Key, SvcBase>
}

impl<Key, SvcBase: ?Sized> ContainerBuilder<Key, SvcBase>
    where Key: reflect::Key, SvcBase: Any
{
    pub fn new() -> Self {
        ContainerBuilder{ cont: Container::new() }
    }

    pub fn register_service(&mut self, key: Key, svc: Box<SvcBase>) -> &mut Self {
        self.cont.register_service(key, svc);
        self
    }

    /// NOTE: The `Box<Svc>: Into<Box<Base>>`-clause is needed due to rusts lack of
    /// HKT or a `Coercible`-trait (to name two solutions).
    pub fn register<Svc>(&mut self, svc: Svc) -> &mut Self
    where
        Svc: reflect::Service<Key = Key> + Into<Box<SvcBase>>,
    {
        self.cont.register::<Svc>(svc);
        self
    }

    pub fn build(self) -> Container<Key, SvcBase> {
        self.cont
    }
}

impl<Key, SvcBase: ?Sized> Default for ContainerBuilder<Key, SvcBase>
    where Key: reflect::Key, SvcBase: Any
{
    fn default() -> Self { Self::new() }
}
<|endoftext|>


<commit_before>extern crate cairo;
extern crate gio;
extern crate gtk;

use std::cell::RefCell;
use std::env::args;

use std::mem;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use cairo::prelude::*;
use cairo::{Context, Format, ImageSurface};
use gio::prelude::*;
use gtk::prelude::*;
use gtk::{ApplicationWindow, DrawingArea};

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

// This example runs four worker threads rendering parts of the image
// independently at different paces in a sort of double buffered way.
//
// +---+---+
// | 0 | 1 |
// +---+---+
// | 2 | 3 |
// +---+---+
//
// Each worker thread waits for an image (cairo::ImageSurface) to render into, sleeps for a while,
// does the drawing, then sends the image back and waits for the next one.
//
// The GUI thread holds an ImageSurface per image part at all times, these
// surfaces are painted on a DrawingArea in its 'draw' signal handler. This
// thread periodically checks if any worker has sent a freshly rendered image.
// Upon receipt it's wrapped in ImageSurface and swapped with the previously
// held surface, whose image is sent to the worker thread again. Then the
// appropriate part of the DrawingArea is invalidated prompting a redraw.
//
// The two images per thread are allocated and initialized once and sent back
// and forth repeatedly.

fn build_ui(application: &gtk::Application) {
    let window = ApplicationWindow::new(application);
    let area = DrawingArea::new();
    window.add(&area);

    let format = Format::Rgb24;
    let width = 200;
    let height = 200;
    area.set_size_request(width * 2, height * 2);

    let initial_image = draw_initial(format, width, height);
    let (ready_tx, ready_rx) = mpsc::channel();

    let mut images = Vec::new();
    let mut origins = Vec::new();
    let mut workers = Vec::new();

    for thread_num in 0..4 {
        let (tx, rx) = mpsc::channel();
        // copy the initial image in two images for the workers
        let image0 = duplicate_image(&initial_image);
        let image1 = duplicate_image(&initial_image);
        // store the first one in our vec
        images.push(image0);
        // send the second one immediately
        let _ = tx.send(image1);
        origins.push(match thread_num {
            0 => (0, 0),
            1 => (width, 0),
            2 => (0, height),
            _ => (width, height),
        });
        workers.push(tx);

        let x = (width - origins[thread_num].0) as f64;
        let y = (height - origins[thread_num].1) as f64;
        let delay = Duration::from_millis((100 << thread_num) - 5);

        // spawn the worker thread
        thread::spawn(clone!(ready_tx => move || {
            let mut n = 0;
            for image in rx.iter() {
                n = (n + 1) % 0x10000;
                let cr = Context::new(&image);
                // draw an arc with a weirdly calculated radius
                draw_slow(&cr, delay, x, y, 1.2_f64.powi(((n as i32) << thread_num) % 32));
                image.flush();
                let _ = ready_tx.send((thread_num, image));
            }
        }));
    }

    // our signal and timeout handler closures have to be 'static,
    // so they can't just borrow these
    let cell = Rc::new(RefCell::new((images, origins, workers)));

    area.connect_draw(clone!(cell => move |_, cr| {
        let (ref images, ref origins, _) = *cell.borrow();
        for (image, origin) in images.iter().zip(origins.iter()) {
            draw_image_if_dirty(&cr, image, *origin, (width, height));
        }
        Inhibit(false)
    }));

    gtk::timeout_add(100, move || {
        while let Ok((thread_num, mut image)) = ready_rx.try_recv() {
            let &mut (ref mut images, ref origins, ref workers) = &mut *cell.borrow_mut();
            let tx = &workers[thread_num];
            mem::swap(&mut images[thread_num], &mut image);
            let _ = tx.send(image);
            area.queue_draw_area(origins[thread_num].0, origins[thread_num].1, width, height);
        }
        Continue(true)
    });

    window.show_all();
}

fn main() {
    let application = gtk::Application::new("com.github.gtk-rs.examples.cairo_threads",
                                            Default::default())
                                       .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}

fn draw_initial(format: Format, width: i32, height: i32) -> ImageSurface {
    let image = ImageSurface::create(format, width, height).expect("Can't create surface");
    {
        let cr = Context::new(&image);
        cr.set_source_rgb(0., 1., 0.);
        cr.paint();
        // Destroying the context releases its reference to `image`.
    }
    // We have a unique reference to `image` again and return it
    image
}

fn draw_slow(cr: &Context, delay: Duration, x: f64, y: f64, radius: f64) {
    thread::sleep(delay);
    cr.set_source_rgb(0., 0., 0.);
    cr.paint();
    cr.set_source_rgb(1., 1., 1.);
    cr.arc(x, y, radius, 0.0, 3.1416 * 2.);
    cr.stroke();
}

fn draw_image_if_dirty(cr: &Context, image: &ImageSurface, origin: (i32, i32),
        dimensions: (i32, i32)) {
    let x = origin.0 as f64;
    let y = origin.1 as f64;
    let w = dimensions.0 as f64;
    let h = dimensions.1 as f64;
    let (clip_x1, clip_y1, clip_x2, clip_y2) = cr.clip_extents();
    if clip_x1 >= x + w || clip_y1 >= y + h || clip_x2 <= x || clip_y2 <= y {
        return;
    }
    cr.set_source_surface(image, x, y);
    cr.paint();
}

fn duplicate_image(image: &ImageSurface) -> ImageSurface {
    let image_dup = ImageSurface::create(image.get_format(), image.get_width(), image.get_height()).expect("Can't create surface");
    {
        let cr = Context::new(&image_dup);
        cr.set_source_surface(image, 0.0, 0.0);
        cr.paint();
    }

    image_dup
}
<commit_msg>Fix-up cairo-threads example now that ImageSurface does not implement Send anymore<commit_after>extern crate cairo;
extern crate gio;
extern crate gtk;

use std::thread;
use std::env::args;
use std::sync::mpsc;
use std::rc::Rc;
use std::cell::RefCell;
use std::time::Duration;

use cairo::prelude::*;
use cairo::{Context, Format, ImageSurface};
use gio::prelude::*;
use gtk::prelude::*;
use gtk::{ApplicationWindow, DrawingArea};

const WIDTH: i32 = 200;
const HEIGHT: i32 = 200;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

// Our custom image type. This stores a heap allocated byte array for the pixels for each of our
// images, can be sent safely between threads and can be temporarily converted to a Cairo image
// surface for drawing operations
#[derive(Clone)]
struct Image(Option<Box<[u8]>>);

impl Image {
    // Creates a new, black image
    fn new() -> Self {
        Image(Some(vec![0; 4 * WIDTH as usize * HEIGHT as usize].into()))
    }

    // Calls the given closure with a temporary Cairo image surface. After the closure has returned
    // there must be no further references to the surface.
    fn with_surface<F: FnOnce(&ImageSurface)>(&mut self, func: F) {
        // Helper struct that allows passing the pixels to the Cairo image surface and once the
        // image surface is destroyed the pixels will be stored in the return_location.
        //
        // This allows us to give temporary ownership of the pixels to the Cairo surface and later
        // retrieve them back in a safe way while ensuring that nothing else still has access to
        // it.
        struct ImageHolder {
            image: Option<Box<[u8]>>,
            return_location: Rc<RefCell<Option<Box<[u8]>>>>,
        }

        // This stores the pixels back into the return_location as now nothing
        // references the pixels anymore
        impl Drop for ImageHolder {
            fn drop(&mut self) {
                *self.return_location.borrow_mut() = Some(self.image.take().expect("Holding no image"));
            }
        }

        // Needed for ImageSurface::create_for_data() to be able to access the pixels
        impl AsRef<[u8]> for ImageHolder {
            fn as_ref(&self) -> &[u8] {
                self.image.as_ref().expect("Holding no image").as_ref()
            }
        }

        impl AsMut<[u8]> for ImageHolder {
            fn as_mut(&mut self) -> &mut [u8] {
                self.image.as_mut().expect("Holding no image").as_mut()
            }
        }

        // Temporary move out the pixels
        let image = self.0.take().expect("Empty image");

        // A new return location that is then passed to our helper struct below
        let return_location = Rc::new(RefCell::new(None));
        {
            let holder = ImageHolder {
                image: Some(image),
                return_location: return_location.clone(),
            };

            // The surface will own the image for the scope of the block below
            let surface = ImageSurface::create_for_data(holder, Format::Rgb24, WIDTH, HEIGHT, 4 * WIDTH).expect("Can't create surface");
            func(&surface);

            // Now the surface will be destroyed and the pixels are stored in the return_location
        }

        // And here move the pixels back again
        self.0 = Some(return_location.borrow_mut().take().expect("Image not returned"));
    }
}

// This example runs four worker threads rendering parts of the image independently at different
// paces in a sort of double buffered way.
//
// +---+---+
// | 0 | 1 |
// +---+---+
// | 2 | 3 |
// +---+---+
//
// Each worker thread waits for an image to render into, sleeps for a while, does the drawing, then
// sends the image back and waits for the next one.
//
// The GUI thread holds an image per image part at all times and these images are painted on a
// DrawingArea in its 'draw' signal handler whenever needed.
//
// Additionally the GUI thread checks periodically every 100ms if any worker has sent a freshly
// rendered image. If there is a new image, the old image stored by the GUI thread is replaced with
// the new one and the old image is sent back to the worker thread. Then the appropriate part of
// the DrawingArea is invalidated prompting a redraw.
//
// The two images per thread are allocated and initialized once and sent back and forth repeatedly.

fn build_ui(application: &gtk::Application) {
    let window = ApplicationWindow::new(application);
    let area = DrawingArea::new();
    window.add(&area);

    area.set_size_request(WIDTH * 2, HEIGHT * 2);

    // Create the initial, green image
    let initial_image = draw_initial();

    // This is the channel for sending results from the worker thread to the main thread
    let (ready_tx, ready_rx) = mpsc::channel();

    let mut images = Vec::new();
    let mut origins = Vec::new();
    let mut workers = Vec::new();

    for thread_num in 0..4 {
        // This is the channel for sending image from the GUI thread to the workers so that the
        // worker can draw the new content into them
        let (tx, rx) = mpsc::channel();

        // Copy the initial image in two images for the workers
        let image0 = initial_image.clone();
        let image1 = initial_image.clone();

        // Store the first one in our vec. This is the one that would be drawn in the very
        // beginning by the DrawingArea.
        images.push(RefCell::new(image0));

        // Send the second one immediately to the worker thread for drawing the new content
        let _ = tx.send(image1);

        // Store for each worker thread its render rectangle inside the DrawingArea
        origins.push(match thread_num {
            0 => (0, 0),
            1 => (WIDTH, 0),
            2 => (0, HEIGHT),
            3 => (WIDTH, HEIGHT),
            _ => unreachable!(),
        });

        // And remember the sender side of the channel that allows the GUI thread to send back
        // images to the worker thread
        workers.push(tx);

        let x = (WIDTH - origins[thread_num].0) as f64;
        let y = (HEIGHT - origins[thread_num].1) as f64;
        let delay = Duration::from_millis((100 << thread_num) - 5);

        // Spawn the worker thread
        thread::spawn(clone!(ready_tx => move || {
            let mut n = 0;
            for mut image in rx.iter() {
                n = (n + 1) % 0x10000;

                // Draw an arc with a weirdly calculated radius
                image.with_surface(|surface| {
                    let cr = Context::new(surface);
                    draw_slow(&cr, delay, x, y, 1.2_f64.powi(((n as i32) << thread_num) % 32));
                    surface.flush();
                });

                // Send the finished image back to the GUI thread
                let _ = ready_tx.send((thread_num, image));
            }
        }));
    }

    // The connect-draw signal and the timeout handler closures have to be 'static, and both need
    // to have access to our images and related state.
    let workspace = Rc::new((images, origins, workers));

    // Whenever the drawing area has to be redrawn, render the latest images in the correct
    // locations
    area.connect_draw(clone!(workspace => move |_, cr| {
        let (ref images, ref origins, _) = &*workspace;

        for (image, origin) in images.iter().zip(origins.iter()) {
            image.borrow_mut().with_surface(|surface| {
                draw_image_if_dirty(&cr, surface, *origin, (WIDTH, HEIGHT));
            });
        }

        Inhibit(false)
    }));

    // Check every 100ms if there are new images from any worker threads and if so queue the
    // corresponding part of the DrawingArea for redrawing
    gtk::timeout_add(100, move || {
        while let Ok((thread_num, image)) = ready_rx.try_recv() {
            let (ref images, ref origins, ref workers) = &*workspace;

            // Swap the newly received image with the old stored one and send the old one back to
            // the worker thread
            let tx = &workers[thread_num];
            let image = images[thread_num].replace(image);
            let _ = tx.send(image);

            area.queue_draw_area(origins[thread_num].0, origins[thread_num].1, WIDTH, HEIGHT);
        }
        Continue(true)
    });

    window.show_all();
}

fn main() {
    let application = gtk::Application::new("com.github.gtk-rs.examples.cairo_threads",
                                            Default::default())
                                       .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}

// Creates a new image and fill it with green
fn draw_initial() -> Image {
    let mut image = Image::new();

    image.with_surface(|surface| {
        let cr = Context::new(surface);
        cr.set_source_rgb(0., 1., 0.);
        cr.paint();
    });

    image
}

// Sleep for a while and then draw an arc with a given radius
fn draw_slow(cr: &Context, delay: Duration, x: f64, y: f64, radius: f64) {
    use std::f64::consts::PI;

    thread::sleep(delay);
    cr.set_source_rgb(0., 0., 0.);
    cr.paint();
    cr.set_source_rgb(1., 1., 1.);
    cr.arc(x, y, radius, 0.0, 2. * PI);
    cr.stroke();
}

// Render the image surface into the context at the given position
fn draw_image_if_dirty(cr: &Context, image: &ImageSurface, origin: (i32, i32),
        dimensions: (i32, i32)) {
    let x = origin.0 as f64;
    let y = origin.1 as f64;
    let w = dimensions.0 as f64;
    let h = dimensions.1 as f64;
    let (clip_x1, clip_y1, clip_x2, clip_y2) = cr.clip_extents();
    if clip_x1 >= x + w || clip_y1 >= y + h || clip_x2 <= x || clip_y2 <= y {
        return;
    }
    cr.set_source_surface(image, x, y);
    cr.paint();

    // Release the reference to the surface again
    cr.set_source_rgba(0.0, 0.0, 0.0, 0.0);
}

<|endoftext|>


<commit_before>extern crate bincode;
extern crate ogg;
extern crate ogg_clock;
extern crate rustc_serialize;
extern crate serde;
extern crate ireul_interface;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate byteorder;

use std::thread;
use std::sync::mpsc::{self};
use std::net::{TcpStream, TcpListener};
use std::collections::VecDeque;
use std::io::{self, Read, Write};
use std::fs::File;

use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

use ogg::{OggTrack, OggTrackBuf, OggPageBuf};
use ogg_clock::OggClock;
use ireul_interface::proxy::{
    SIZE_LIMIT,
    RequestWrapper,
    RequestType,
    BinderError,
    EnqueueTrackRequest,
    EnqueueTrackError,
    TrackSkipToEndRequest,
    TrackSkipToEndError,
};

mod icecastwriter;

use icecastwriter::{
    IceCastWriter,
    IceCastWriterOptions,
};

fn main() {
    env_logger::init().unwrap();

    let mut icecast_options = IceCastWriterOptions::default();
    icecast_options
        .set_endpoint("lollipop.hiphop:8000")
        .set_mount("/ireul")
        .set_user_pass("source:x");

    let connector = IceCastWriter::new(icecast_options).unwrap();

    let mut file = File::open("howbigisthis.ogg").unwrap();
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer).unwrap();
    let offline_track = OggTrackBuf::new(buffer).unwrap();

    let output_manager = OutputManager {
        connector: connector,
        cur_serial: 0,
        clock: OggClock::new(48000),
        playing_offline: false,
        buffer: VecDeque::new(),
        play_queue: VecDeque::new(),
        offline_track: offline_track,
    };

    let control = TcpListener::bind("0.0.0.0:3001").unwrap();
    let mut core = Core::new(control, output_manager).unwrap();
    loop {
        core.tick();
        debug!("copied page");
    }
}

fn validate_positions(track: &OggTrack) -> Result<(), ()> {
    let mut current = 0;
    let mut is_first = true;

    for page in track.pages() {
        let position = page.position();

        if is_first {
            is_first = false;

            if position != 0 {
                return Err(());
            }
        }

        if position < current {
            return Err(());
        }
        current = position;
    }

    Ok(())
}

fn check_sample_rate(req: u32, track: &OggTrack) -> Result<(), ()> {
    warn!("check_sample_rate: STUB");
    Ok(())
}

fn update_serial(serial: u32, track: &mut OggTrack) {
    for page in track.pages_mut() {
        page.set_serial(serial);
    }
}

fn update_positions(start_pos: u64, track: &mut OggTrack) {
    for page in track.pages_mut() {
        let old_pos = page.position();
        page.set_position(start_pos + old_pos);
    }
}

struct Core {
    output: OutputManager,
    // proxy_tx: mpsc::SyncSender<RequestWrapper>,
    proxy_rx: mpsc::Receiver<RequestWrapper>,
}

impl Core {
    fn new(control: TcpListener, om: OutputManager) -> io::Result<Core> {
        let (tx, rx) = mpsc::sync_channel(5);

        let proxy_tx_client = tx.clone();
        thread::spawn(move || {
            client_acceptor(control, proxy_tx_client);
        });

        Ok(Core {
            output: om,
            // proxy_tx: tx,
            proxy_rx: rx,
        })
    }

    fn enqueue_track(&mut self, req: EnqueueTrackRequest) -> Result<(), EnqueueTrackError> {
        let EnqueueTrackRequest { mut track } = req;

        try!(validate_positions(&track)
            .map_err(|()| EnqueueTrackError::InvalidTrack));

        try!(check_sample_rate(self.output.clock.sample_rate(), &track)
            .map_err(|()| EnqueueTrackError::BadSampleRate));

        self.output.play_queue.push_back(track);

        Ok(())
    }

    fn track_skip_to_end(&mut self, req: TrackSkipToEndRequest) -> Result<(), TrackSkipToEndError> {
        unimplemented!();
    }

    fn handle_command(&mut self, req_wr: RequestWrapper) {
        let mut binder = CoreBinder { core: self };
        binder.handle_command(req_wr)
    }

    fn tick(&mut self) {
        loop {
            match self.proxy_rx.try_recv() {
                Ok(cmd) => self.handle_command(cmd),
                Err(err) => break,
            }
        }
        self.output.copy_page();
    }
}

fn client_worker(mut stream: TcpStream, chan: mpsc::SyncSender<RequestWrapper>) -> io::Result<()> {
    const BUFFER_SIZE_LIMIT: usize = 20 * 1 << 20;
    loop {
        let version = try!(stream.read_u8());
        if version != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "invalid version"));
        }

        let op_code = try!(stream.read_u32::<BigEndian>());
        let req_type = try!(RequestType::from_op_code(op_code).map_err(|_| {
            let err_msg = format!("unknown op-code {:?}", op_code);
            io::Error::new(io::ErrorKind::Other, err_msg)
        }));

        let frame_length = try!(stream.read_u32::<BigEndian>()) as usize;
        if BUFFER_SIZE_LIMIT < frame_length {
            let err_msg = format!("datagram too large: {} bytes (limit is {})",
                frame_length, BUFFER_SIZE_LIMIT);
            return Err(io::Error::new(io::ErrorKind::Other, err_msg));
        }

        let mut req_buf = Vec::new();

        {
            let mut limit_reader = Read::by_ref(&mut stream).take(frame_length as u64);
            try!(limit_reader.read_to_end(&mut req_buf));
        }

        if req_buf.len() != frame_length {
            let err_msg = format!(
                "datagram truncated: got {} bytes, expected {}",
                req_buf.len(), frame_length);
            return Err(io::Error::new(io::ErrorKind::Other, err_msg));
        }

        let (resp_tx, resp_rx) = mpsc::sync_channel(1);
        chan.send(RequestWrapper {
            response_queue: resp_tx,
            req_type: req_type,
            req_buf: req_buf,
        }).unwrap();

        let response = resp_rx.recv().unwrap();
        try!(stream.write_u32::<BigEndian>(response.len() as u32));
        try!(stream.write_all(&response));
    }
}

fn client_acceptor(server: TcpListener, chan: mpsc::SyncSender<RequestWrapper>) {
    for stream in server.incoming() {
        match stream {
            Ok(stream) => {
                let client_chan = chan.clone();

                thread::spawn(move || {
                    client_worker(stream, client_chan);
                });
            },
            Err(err) => {
                info!("error accepting new client: {:?}", err);
            }
        }
    }
}

struct CoreBinder<'a> {
    core: &'a mut Core,
}

impl<'a> CoreBinder<'a> {
    fn handle_command(&mut self, req_wr: RequestWrapper) {
        let RequestWrapper {
            response_queue: response_queue,
            req_type: req_type,
            req_buf: req_buf,
        } = req_wr;
        let response = match req_type {
            RequestType::EnqueueTrack => {
                self.enqueue_track(&req_buf)
            },
            RequestType::TrackSkipToEnd => {
                self.track_skip_to_end(&req_buf)
            },
        };
        response_queue.send(response).unwrap();
    }

    fn enqueue_track(&mut self, req: &[u8]) -> Vec<u8> {
        let res = bincode::serde::deserialize(req)
            .map_err(|_| BinderError::RemoteSerdeError)
            .and_then(|req| {
                self.core.enqueue_track(req)
                    .map_err(BinderError::CallError)
            });

        bincode::serde::serialize(&res, SIZE_LIMIT).unwrap()
    }

    fn track_skip_to_end(&mut self, req: &[u8]) -> Vec<u8> {
        warn!("unimplemented: client request TrackSkipToEndRequest");
         let res: Result<(), BinderError<TrackSkipToEndError>> =
            bincode::serde::deserialize::<TrackSkipToEndRequest>(req)
                .map_err(|_| BinderError::RemoteSerdeError)
                .and_then(|req| {
                    Err(BinderError::StubImplementation)
                });

        bincode::serde::serialize(&res, SIZE_LIMIT).unwrap()
    }
}

/// Connects to IceCast and holds references to streamable content.
struct OutputManager {
    // TODO: this needs a helper to fix OggPage positions, so that the stream
    //       starts with position of zero and strictly increases with time,
    //       by the number of samples played.
    //
    // TODO: this needs a helper to fix OggPage sequences, so that the stream
    //       starts with a sequence of zero and increases by one each time a
    //       page is emitted.
    //
    connector: IceCastWriter,
    cur_serial: u32,
    clock: OggClock,
    playing_offline: bool,
    buffer: VecDeque<OggPageBuf>,
    play_queue: VecDeque<OggTrackBuf>,
    offline_track: OggTrackBuf,
}

impl OutputManager {
    fn fill_buffer(&mut self) {
        let mut track = match self.play_queue.pop_front() {
            Some(track) => track,
            None => self.offline_track.clone(),
        };

        // not sure why we as_mut instead of just using &mut track
        update_serial(self.cur_serial, track.as_mut());
        self.cur_serial = self.cur_serial.wrapping_add(1);
        update_positions(0, track.as_mut());

        self.buffer.extend(track.pages().map(|x| x.to_owned()));
    }

    fn get_next_page(&mut self) -> OggPageBuf {
        if self.buffer.is_empty() {
            self.fill_buffer();
        }
        self.buffer.pop_front().unwrap()
    }

    fn copy_page(&mut self) {
        let page = self.get_next_page();
        self.clock.wait(&page).unwrap();
        self.connector.send_ogg_page(&page).unwrap();
    }
}

// impl OutputManager {
//     pub fn new(backup_track: OggTrack) -> OutputManager {
//         OutputManager {
//             connector: IceCastConnector,
//             clock: OggClock::new(48000),
//             play_queue: VecDeque::new(),
//             offline_track: backup_track,
//         }
//     }
// }

<commit_msg>core: Backup track plays properly!<commit_after>extern crate bincode;
extern crate ogg;
extern crate ogg_clock;
extern crate rustc_serialize;
extern crate serde;
extern crate ireul_interface;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate byteorder;

use std::thread;
use std::sync::mpsc::{self};
use std::net::{TcpStream, TcpListener};
use std::collections::VecDeque;
use std::io::{self, Read, Write};
use std::fs::File;

use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};

use ogg::{OggTrack, OggTrackBuf, OggPageBuf};
use ogg_clock::OggClock;
use ireul_interface::proxy::{
    SIZE_LIMIT,
    RequestWrapper,
    RequestType,
    BinderError,
    EnqueueTrackRequest,
    EnqueueTrackError,
    TrackSkipToEndRequest,
    TrackSkipToEndError,
};

mod icecastwriter;

use icecastwriter::{
    IceCastWriter,
    IceCastWriterOptions,
};

fn main() {
    env_logger::init().unwrap();

    let mut icecast_options = IceCastWriterOptions::default();
    icecast_options
        .set_endpoint("lollipop.hiphop:8000")
        .set_mount("/ireul")
        .set_user_pass("source:x");

    let connector = IceCastWriter::new(icecast_options).unwrap();

    let mut file = File::open("howbigisthis.ogg").unwrap();
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer).unwrap();
    let offline_track = OggTrackBuf::new(buffer).unwrap();

    let output_manager = OutputManager {
        connector: connector,
        cur_serial: 0,
        position: 0,
        clock: OggClock::new(48000),
        playing_offline: false,
        buffer: VecDeque::new(),
        play_queue: VecDeque::new(),
        offline_track: offline_track,
    };

    let control = TcpListener::bind("0.0.0.0:3001").unwrap();
    let mut core = Core::new(control, output_manager).unwrap();
    loop {
        core.tick();
        debug!("copied page");
    }
}

fn validate_positions(track: &OggTrack) -> Result<(), ()> {
    let mut current = 0;
    let mut is_first = true;

    for page in track.pages() {
        let position = page.position();

        if is_first {
            is_first = false;

            if position != 0 {
                return Err(());
            }
        }

        if position < current {
            return Err(());
        }
        current = position;
    }

    Ok(())
}

fn check_sample_rate(req: u32, track: &OggTrack) -> Result<(), ()> {
    warn!("check_sample_rate: STUB");
    Ok(())
}

fn update_serial(serial: u32, track: &mut OggTrack) {
    for page in track.pages_mut() {
        page.set_serial(serial);
    }
}

fn update_positions(start_pos: u64, track: &mut OggTrack) {
    for page in track.pages_mut() {
        let old_pos = page.position();
        page.set_position(start_pos + old_pos);
    }
}

fn final_position(track: &OggTrack) -> Option<u64> {
    let mut position = None;
    for page in track.pages() {
        position = Some(page.position());
    }
    position
}

struct Core {
    output: OutputManager,
    // proxy_tx: mpsc::SyncSender<RequestWrapper>,
    proxy_rx: mpsc::Receiver<RequestWrapper>,
}

impl Core {
    fn new(control: TcpListener, om: OutputManager) -> io::Result<Core> {
        let (tx, rx) = mpsc::sync_channel(5);

        let proxy_tx_client = tx.clone();
        thread::spawn(move || {
            client_acceptor(control, proxy_tx_client);
        });

        Ok(Core {
            output: om,
            // proxy_tx: tx,
            proxy_rx: rx,
        })
    }

    fn enqueue_track(&mut self, req: EnqueueTrackRequest) -> Result<(), EnqueueTrackError> {
        let EnqueueTrackRequest { mut track } = req;

        try!(validate_positions(&track)
            .map_err(|()| EnqueueTrackError::InvalidTrack));

        try!(check_sample_rate(self.output.clock.sample_rate(), &track)
            .map_err(|()| EnqueueTrackError::BadSampleRate));

        self.output.play_queue.push_back(track);

        Ok(())
    }

    fn track_skip_to_end(&mut self, req: TrackSkipToEndRequest) -> Result<(), TrackSkipToEndError> {
        unimplemented!();
    }

    fn handle_command(&mut self, req_wr: RequestWrapper) {
        let mut binder = CoreBinder { core: self };
        binder.handle_command(req_wr)
    }

    fn tick(&mut self) {
        loop {
            match self.proxy_rx.try_recv() {
                Ok(cmd) => self.handle_command(cmd),
                Err(err) => break,
            }
        }
        self.output.copy_page();
    }
}

fn client_worker(mut stream: TcpStream, chan: mpsc::SyncSender<RequestWrapper>) -> io::Result<()> {
    const BUFFER_SIZE_LIMIT: usize = 20 * 1 << 20;
    loop {
        let version = try!(stream.read_u8());
        if version != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "invalid version"));
        }

        let op_code = try!(stream.read_u32::<BigEndian>());
        let req_type = try!(RequestType::from_op_code(op_code).map_err(|_| {
            let err_msg = format!("unknown op-code {:?}", op_code);
            io::Error::new(io::ErrorKind::Other, err_msg)
        }));

        let frame_length = try!(stream.read_u32::<BigEndian>()) as usize;
        if BUFFER_SIZE_LIMIT < frame_length {
            let err_msg = format!("datagram too large: {} bytes (limit is {})",
                frame_length, BUFFER_SIZE_LIMIT);
            return Err(io::Error::new(io::ErrorKind::Other, err_msg));
        }

        let mut req_buf = Vec::new();

        {
            let mut limit_reader = Read::by_ref(&mut stream).take(frame_length as u64);
            try!(limit_reader.read_to_end(&mut req_buf));
        }

        if req_buf.len() != frame_length {
            let err_msg = format!(
                "datagram truncated: got {} bytes, expected {}",
                req_buf.len(), frame_length);
            return Err(io::Error::new(io::ErrorKind::Other, err_msg));
        }

        let (resp_tx, resp_rx) = mpsc::sync_channel(1);
        chan.send(RequestWrapper {
            response_queue: resp_tx,
            req_type: req_type,
            req_buf: req_buf,
        }).unwrap();

        let response = resp_rx.recv().unwrap();
        try!(stream.write_u32::<BigEndian>(response.len() as u32));
        try!(stream.write_all(&response));
    }
}

fn client_acceptor(server: TcpListener, chan: mpsc::SyncSender<RequestWrapper>) {
    for stream in server.incoming() {
        match stream {
            Ok(stream) => {
                let client_chan = chan.clone();

                thread::spawn(move || {
                    client_worker(stream, client_chan);
                });
            },
            Err(err) => {
                info!("error accepting new client: {:?}", err);
            }
        }
    }
}

struct CoreBinder<'a> {
    core: &'a mut Core,
}

impl<'a> CoreBinder<'a> {
    fn handle_command(&mut self, req_wr: RequestWrapper) {
        let RequestWrapper {
            response_queue: response_queue,
            req_type: req_type,
            req_buf: req_buf,
        } = req_wr;
        let response = match req_type {
            RequestType::EnqueueTrack => {
                self.enqueue_track(&req_buf)
            },
            RequestType::TrackSkipToEnd => {
                self.track_skip_to_end(&req_buf)
            },
        };
        response_queue.send(response).unwrap();
    }

    fn enqueue_track(&mut self, req: &[u8]) -> Vec<u8> {
        let res = bincode::serde::deserialize(req)
            .map_err(|_| BinderError::RemoteSerdeError)
            .and_then(|req| {
                self.core.enqueue_track(req)
                    .map_err(BinderError::CallError)
            });

        bincode::serde::serialize(&res, SIZE_LIMIT).unwrap()
    }

    fn track_skip_to_end(&mut self, req: &[u8]) -> Vec<u8> {
        warn!("unimplemented: client request TrackSkipToEndRequest");
         let res: Result<(), BinderError<TrackSkipToEndError>> =
            bincode::serde::deserialize::<TrackSkipToEndRequest>(req)
                .map_err(|_| BinderError::RemoteSerdeError)
                .and_then(|req| {
                    Err(BinderError::StubImplementation)
                });

        bincode::serde::serialize(&res, SIZE_LIMIT).unwrap()
    }
}

/// Connects to IceCast and holds references to streamable content.
struct OutputManager {
    // TODO: this needs a helper to fix OggPage positions, so that the stream
    //       starts with position of zero and strictly increases with time,
    //       by the number of samples played.
    //
    // TODO: this needs a helper to fix OggPage sequences, so that the stream
    //       starts with a sequence of zero and increases by one each time a
    //       page is emitted.
    //
    connector: IceCastWriter,
    cur_serial: u32,
    clock: OggClock,

    // the position at the end of the currently playing track
    position: u64,

    playing_offline: bool,
    buffer: VecDeque<OggPageBuf>,
    play_queue: VecDeque<OggTrackBuf>,
    offline_track: OggTrackBuf,
}

impl OutputManager {
    fn fill_buffer(&mut self) {
        let mut track = match self.play_queue.pop_front() {
            Some(track) => track,
            None => self.offline_track.clone(),
        };

        // not sure why we as_mut instead of just using &mut track
        update_serial(self.cur_serial, track.as_mut());
        self.cur_serial = self.cur_serial.wrapping_add(1);
        update_positions(self.position, track.as_mut());
        self.position = final_position(&track).unwrap();

        self.buffer.extend(track.pages().map(|x| x.to_owned()));
    }

    fn get_next_page(&mut self) -> OggPageBuf {
        if self.buffer.is_empty() {
            self.fill_buffer();
        }
        self.buffer.pop_front().unwrap()
    }

    fn copy_page(&mut self) {
        let page = self.get_next_page();
        self.clock.wait(&page).unwrap();
        self.connector.send_ogg_page(&page).unwrap();
    }
}

// impl OutputManager {
//     pub fn new(backup_track: OggTrack) -> OutputManager {
//         OutputManager {
//             connector: IceCastConnector,
//             clock: OggClock::new(48000),
//             play_queue: VecDeque::new(),
//             offline_track: backup_track,
//         }
//     }
// }

<|endoftext|>


<commit_before>extern crate fuse;
extern crate time;
extern crate libc;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};

struct JsonFilesystem;

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        reply.error(ENOSYS);
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(JsonFilesystem, &mountpoint, &[]);
}
<commit_msg>First working readdir implementation.<commit_after>extern crate fuse;
extern crate time;
extern crate libc;

use std::io::{FileType, USER_FILE, USER_DIR};
use std::mem;
use std::os;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, Filesystem, Request, ReplyAttr, ReplyEntry, ReplyDirectory};

struct JsonFilesystem;

impl Filesystem for JsonFilesystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        println!("getattr(): ino {}", ino);
        let mut attr: FileAttr = unsafe { mem::zeroed() };
        attr.ino = 1;
        attr.kind = FileType::Directory;
        attr.perm = USER_DIR;
        let ttl = Timespec::new(1, 0);
        if ino == 1 {
            reply.attr(&ttl, &attr);
        } else {
            reply.error(ENOSYS);
        }
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        println!("readdir(): ino {}, fh {}, ofset {}", ino, fh, offset);
        if ino == 1 {
            if offset == 0 {
                reply.add(1, 0, FileType::Directory, &PosixPath::new("."));
                reply.add(1, 1, FileType::Directory, &PosixPath::new(".."));
            }
            reply.ok();
        } else {
            reply.error(ENOENT);
        }
    }
}

fn main() {
    println!("24 days of Rust - fuse (day N)");
    let mountpoint = Path::new(os::args()[1].as_slice());
    fuse::mount(JsonFilesystem, &mountpoint, &[]);
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde-serialize")]

use na::{
    DMatrix, Isometry3, IsometryMatrix3, Matrix3x4, Point3, Quaternion, Rotation3, Similarity3,
    SimilarityMatrix3, Translation3, Unit, Point2, Translation2, Rotation2, Isometry2, IsometryMatrix2,
    Similarity2, SimilarityMatrix2,
};
use rand;
use serde_json;

macro_rules! test_serde(
    ($($test: ident, $ty: ident);* $(;)*) => {$(
        #[test]
        fn $test() {
            let v: $ty<f32> = rand::random();
            let serialized = serde_json::to_string(&v).unwrap();
            assert_eq!(v, serde_json::from_str(&serialized).unwrap());
        }
    )*}
);

#[test]
fn serde_dmatrix() {
    let v: DMatrix<f32> = DMatrix::new_random(3, 4);
    let serialized = serde_json::to_string(&v).unwrap();
    assert_eq!(v, serde_json::from_str(&serialized).unwrap());
}

test_serde!(
    serde_matrix3x4,          Matrix3x4;
    serde_point3,             Point3;
    serde_translation3,       Translation3;
    serde_rotation3,          Rotation3;
    serde_isometry3,          Isometry3;
    serde_isometry_matrix3,   IsometryMatrix3;
    serde_similarity3,        Similarity3;
    serde_similarity_matrix3, SimilarityMatrix3;
    serde_quaternion,         Quaternion;
    serde_point2,             Point2;
    serde_translation2,       Translation2;
    serde_rotation2,          Rotation2;
    serde_isometry2,          Isometry2;
    serde_isometry_matrix2,   IsometryMatrix2;
    serde_similarity2,        Similarity2;
    serde_similarity_matrix2, SimilarityMatrix2;
);

#[test]
fn serde_flat() {
    // The actual storage is hidden behind three layers of wrapper types that shouldn't appear in serialized form.
    let v = Unit::new_normalize(Quaternion::new(0., 0., 0., 1.));
    let serialized = serde_json::to_string(&v).unwrap();
    assert_eq!(serialized, "[0.0,0.0,1.0,0.0]");
}
<commit_msg>Add type annotations in serde tests<commit_after>#![cfg(feature = "serde-serialize")]

use na::{
    DMatrix, Isometry3, IsometryMatrix3, Matrix3x4, Point3, Quaternion, Rotation3, Similarity3,
    SimilarityMatrix3, Translation3, Unit, Point2, Translation2, Rotation2, Isometry2, IsometryMatrix2,
    Similarity2, SimilarityMatrix2,
};
use rand;
use serde_json;

macro_rules! test_serde(
    ($($test: ident, $ty: ident);* $(;)*) => {$(
        #[test]
        fn $test() {
            let v: $ty<f32> = rand::random();
            let serialized = serde_json::to_string(&v).unwrap();
            let deserialized: $ty<f32> = serde_json::from_str(&serialized).unwrap();
            assert_eq!(v, deserialized);
        }
    )*}
);

#[test]
fn serde_dmatrix() {
    let v: DMatrix<f32> = DMatrix::new_random(3, 4);
    let serialized = serde_json::to_string(&v).unwrap();
    let deserialized: DMatrix<f32> = serde_json::from_str(&serialized).unwrap();
    assert_eq!(v, deserialized);
}

test_serde!(
    serde_matrix3x4,          Matrix3x4;
    serde_point3,             Point3;
    serde_translation3,       Translation3;
    serde_rotation3,          Rotation3;
    serde_isometry3,          Isometry3;
    serde_isometry_matrix3,   IsometryMatrix3;
    serde_similarity3,        Similarity3;
    serde_similarity_matrix3, SimilarityMatrix3;
    serde_quaternion,         Quaternion;
    serde_point2,             Point2;
    serde_translation2,       Translation2;
    serde_rotation2,          Rotation2;
    serde_isometry2,          Isometry2;
    serde_isometry_matrix2,   IsometryMatrix2;
    serde_similarity2,        Similarity2;
    serde_similarity_matrix2, SimilarityMatrix2;
);

#[test]
fn serde_flat() {
    // The actual storage is hidden behind three layers of wrapper types that shouldn't appear in serialized form.
    let v = Unit::new_normalize(Quaternion::new(0., 0., 0., 1.));
    let serialized = serde_json::to_string(&v).unwrap();
    assert_eq!(serialized, "[0.0,0.0,1.0,0.0]");
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate "gfx" as gfx_;
pub use self::gfx_ as gfx;

#[derive(Clone, Debug, PartialEq)]
pub struct Res;

impl gfx::Resources for Res {
    type Buffer = ();
    type ArrayBuffer = ();
    type Shader = ();
    type Program = ();
    type FrameBuffer = ();
    type Surface = ();
    type Texture = ();
    type Sampler = ();
}
<commit_msg>Use non-string crate name<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate gfx as gfx_;
pub use self::gfx_ as gfx;

#[derive(Clone, Debug, PartialEq)]
pub struct Res;

impl gfx::Resources for Res {
    type Buffer = ();
    type ArrayBuffer = ();
    type Shader = ();
    type Program = ();
    type FrameBuffer = ();
    type Surface = ();
    type Texture = ();
    type Sampler = ();
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::io::prelude::*;
use std::env;
use std::fs::File;
use std::path::Path;
use std::process::{Command, Stdio};

macro_rules! errln {
    ($($args:tt)*) => {
        let _ = writeln!(&mut ::std::io::stderr(), $($args)* );
    }
}

fn main() {
    let target = env::var("TARGET").expect("cannot get TARGET");
    let host = env::var("HOST").expect("cannot get HOST");
    let msvc = target.contains("msvc");

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

    if !target.starts_with("x86_64-") && !target.starts_with("i686") {
        let out_dir = env::var("OUT_DIR").unwrap();
        compute_place_holders(&out_dir, "capstone/include", msvc);
    }

    if !Path::new("capstone/libcapstone.a").exists() {
        build_capstone(&target, &host, msvc);
    }

    println!("cargo:rustc-link-search=native={}/capstone", env::var("CARGO_MANIFEST_DIR").unwrap());
    println!("cargo:rustc-link-lib=static=capstone")
}

fn compute_place_holders(out_dir: &str, inc_dir: &str, msvc: bool) {
    let out_rs = Path::new(out_dir).join("placeholders.rs");
    let out_exe = Path::new(out_dir).join("compute_placeholders.exe");

    let mut config = gcc::Config::new();
    config.include(inc_dir);

    let mut command = config.get_compiler().to_command();
    command.arg("compute_placeholders.c");
    if msvc {
        command.arg("/OUT");
    } else {
        command.arg("-o");
    }
    command.arg(&out_exe)
        .stdout(Stdio::null())
        .stderr(Stdio::null());

    errln!("{:?}", command);
    if command.status().is_ok() {
        let mut run_cmd = Command::new(&out_exe);
        errln!("{:?}", run_cmd);
        let output = run_cmd.output().expect("cannot run compute_placeholders.exe");
        let mut f = File::create(&out_rs).unwrap();
        f.write_all(output.stdout.as_slice()).unwrap();
    } else {
        panic!("cannot build compute_placeholders.exe");
    }
}

fn build_capstone(target: &str, host: &str, msvc: bool) {

    let host_windows = host.contains("windows");

    if msvc && !host_windows {
        panic!("cannot cross compile to msvc");
    }

    if msvc {
        panic!("msvc build not supported yet");
    }

    let mut cmd = Command::new("bash");
    cmd.current_dir("capstone")
        .arg("make.sh")
        // .env("CFLAGS", "-flto")
        .env("CAPSTONE_SHARED", "no")
        .env("CAPSTONE_STATIC", "yes");

    if host == target {
        // do nothing
    } else if target == "i686-pc-windows-gnu" {
        cmd.arg("cross-win32");
    } else if target == "x86_64-pc-windows-gnu" {
        cmd.arg("cross-win64");
    } else if host.starts_with("x86_64-") && target.starts_with("i686-") && host[7..] == target[5..] {
        // not perfect but hey
        cmd.arg("nix32");
    } else {
        cmd.env("CROSS", target.to_string() + "-");
    }

    errln!("build capstone: {:?}", cmd);

    let res = cmd.status();
    if let Ok(res) = res {
        if !res.success() {
            panic!("cannot compile capstone");
        }
    } else {
        panic!("cannot start capstone build");
    }

}
<commit_msg>Better custom build for capstone<commit_after>extern crate gcc;

use std::io::prelude::*;
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

macro_rules! errln {
    ($($args:tt)*) => {
        let _ = writeln!(&mut ::std::io::stderr(), $($args)* );
    }
}

fn main() {
    let target = env::var("TARGET").expect("cannot get TARGET");
    let host = env::var("HOST").expect("cannot get HOST");
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("cannot get OUT_DIR"));
    let msvc = target.contains("msvc");

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

    if !target.starts_with("x86_64-") && !target.starts_with("i686") {
        compute_place_holders(&out_dir, "capstone/include", msvc);
    }

    let libcapstone = out_dir.join("libcapstone.a");
    if !libcapstone.exists() {
        build_capstone(&out_dir, &target, &host, msvc);
    }
    if !libcapstone.exists() {
        panic!("cannot find libcapstone")
    }

    println!("cargo:rustc-link-search=native={}", out_dir.display());
    println!("cargo:rustc-link-lib=static=capstone")
}

fn compute_place_holders(out_dir: &Path, inc_dir: &str, msvc: bool) {
    let out_rs = out_dir.join("placeholders.rs");
    let out_exe = out_dir.join("compute_placeholders.exe");

    let mut config = gcc::Config::new();
    config.include(inc_dir);

    let mut command = config.get_compiler().to_command();
    command.arg("compute_placeholders.c");
    if msvc {
        command.arg("/OUT");
    } else {
        command.arg("-o");
    }
    command.arg(&out_exe)
        .stdout(Stdio::null())
        .stderr(Stdio::null());

    errln!("{:?}", command);
    if command.status().is_ok() {
        let mut run_cmd = Command::new(&out_exe);
        errln!("{:?}", run_cmd);
        let output = run_cmd.output().expect("cannot run compute_placeholders.exe");
        let mut f = File::create(&out_rs).unwrap();
        f.write_all(output.stdout.as_slice()).unwrap();
    } else {
        panic!("cannot build compute_placeholders.exe");
    }
}

fn build_capstone(out_dir: &Path, target: &str, host: &str, msvc: bool) {

    let host_windows = host.contains("windows");

    if msvc && !host_windows {
        panic!("cannot cross compile to msvc");
    }

    if msvc {
        panic!("msvc build not supported yet");
    }

    let mut cmd = Command::new("bash");
    cmd.current_dir("capstone")
        .arg("make.sh")
        // .env("CFLAGS", "-flto")
        .env("BUILDDIR", out_dir)
        .env("CAPSTONE_BUILD_CORE_ONLY", "yes")
        .env("CAPSTONE_SHARED", "no")
        .env("CAPSTONE_STATIC", "yes");

    if host == target {
        // do nothing
    } else if target == "i686-pc-windows-gnu" {
        cmd.arg("cross-win32");
    } else if target == "x86_64-pc-windows-gnu" {
        cmd.arg("cross-win64");
    } else if host.starts_with("x86_64-") && target.starts_with("i686-") && host[7..] == target[5..] {
        // not perfect but hey
        cmd.arg("nix32");
    } else {
        cmd.env("CROSS", target.to_string() + "-");
    }

    errln!("build capstone: {:?}", cmd);

    let res = cmd.status();
    if let Ok(res) = res {
        if !res.success() {
            panic!("cannot compile capstone");
        }
    } else {
        panic!("cannot start capstone build");
    }

}
<|endoftext|>


<commit_before>//! This build script detects target platforms that lack proper support for
//! atomics and sets `cfg` flags accordingly.

use std::env;
use std::str;

fn main() {
    let target = match rustc_target() {
        Some(target) => target,
        None => return,
    };

    if target_has_atomic_cas(&target) {
        println!("cargo:rustc-cfg=atomic_cas");
    }

    if target_has_atomics(&target) {
        println!("cargo:rustc-cfg=has_atomics");
    }

    println!("cargo:rerun-if-changed=build.rs");
}

fn target_has_atomic_cas(target: &str) -> bool {
    match &target[..] {
        "thumbv6m-none-eabi"
        | "msp430-none-elf"
        | "riscv32i-unknown-none-elf"
        | "riscv32imc-unknown-none-elf" => false,
        _ => true,
    }
}

fn target_has_atomics(target: &str) -> bool {
    match &target[..] {
        "thumbv4t-none-eabi" | "msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => false,
        _ => true,
    }
}

fn rustc_target() -> Option<String> {
    env::var("TARGET").ok()
}
<commit_msg>#487 Fix formatting.<commit_after>//! This build script detects target platforms that lack proper support for
//! atomics and sets `cfg` flags accordingly.

use std::env;
use std::str;

fn main() {
    let target = match rustc_target() {
        Some(target) => target,
        None => return,
    };

    if target_has_atomic_cas(&target) {
        println!("cargo:rustc-cfg=atomic_cas");
    }

    if target_has_atomics(&target) {
        println!("cargo:rustc-cfg=has_atomics");
    }

    println!("cargo:rerun-if-changed=build.rs");
}

fn target_has_atomic_cas(target: &str) -> bool {
    match &target[..] {
        "thumbv6m-none-eabi"
        | "msp430-none-elf"
        | "riscv32i-unknown-none-elf"
        | "riscv32imc-unknown-none-elf" => false,
        _ => true,
    }
}

fn target_has_atomics(target: &str) -> bool {
    match &target[..] {
        "thumbv4t-none-eabi"
        | "msp430-none-elf"
        | "riscv32i-unknown-none-elf"
        | "riscv32imc-unknown-none-elf" => false,
        _ => true,
    }
}

fn rustc_target() -> Option<String> {
    env::var("TARGET").ok()
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::os;

fn main() {
    let curr_dir = os::getenv("CARGO_MANIFEST_DIR").unwrap();
    let nvim_dir = Path::new(curr_dir).join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "src", "nvim"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static -l nvim -l uv -l msgpack -l curses",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<commit_msg>Make sure the submodule is brought in<commit_after>use std::io::Command;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    Command::new("git").arg("submodule").arg("update").arg("--init").cwd(&curr_dir).status().unwrap();

    let nvim_dir = Path::new(curr_dir).join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "src", "nvim"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static -l nvim -l uv -l msgpack -l curses",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path::Path;

const LINUX_CLANG_DIRS: &'static [&'static str] = &["/usr/lib", "/usr/lib/llvm", "/usr/lib64/llvm", "/usr/lib/x86_64-linux-gnu"];
const MAC_CLANG_DIR: &'static str = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib";

fn path_exists(path: &Path) -> bool {
    match fs::metadata(path) {
        Ok(_) => true,
        Err(_) => false
    }
}

fn main() {
    let use_static_lib = env::var_os("LIBCLANG_STATIC").is_some() || cfg!(feature = "static");

    let possible_clang_dirs = if let Ok(dir) = env::var("LIBCLANG_PATH") {
        vec![dir]
    } else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
        LINUX_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else if cfg!(target_os = "macos") {
        vec![MAC_CLANG_DIR.to_string()]
    } else {
        panic!("Platform not supported");
    };

    let clang_lib = format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX);

    let maybe_clang_dir = possible_clang_dirs.iter().filter_map(|candidate_dir| {
        let clang_dir = Path::new(candidate_dir);
        let clang_path = clang_dir.join(clang_lib.clone());

        if path_exists(&*clang_path) {
            Some(clang_dir)
        } else {
            None
        }
    }).next();

    macro_rules! qw {
        ($($i:ident)*) => (vec!($(stringify!($i)),*));
    }

    if let Some(clang_dir) = maybe_clang_dir {
        if use_static_lib {
            let libs = qw![
                LLVMAnalysis
                LLVMBitReader
                LLVMCore
                LLVMLTO
                LLVMLinker
                LLVMMC
                LLVMMCParser
                LLVMObjCARCOpts
                LLVMObject
                LLVMOption
                LLVMScalarOpts
                LLVMSupport
                LLVMTarget
                LLVMTransformUtils
                LLVMVectorize
                LLVMipa
                LLVMipo
                clang
                clangARCMigrate
                clangAST
                clangASTMatchers
                clangAnalysis
                clangBasic
                clangDriver
                clangEdit
                clangFormat
                clangFrontend
                clangIndex
                clangLex
                clangParse
                clangRewrite
                clangRewriteFrontend
                clangSema
                clangSerialization
                clangStaticAnalyzerCheckers
                clangStaticAnalyzerCore
                clangStaticAnalyzerFrontend
                clangTooling
            ];

            print!("cargo:rustc-flags=");
            for lib in libs {
                print!("-l static={} ", lib);
            }
            println!("-L {} -l ncursesw -l z -l stdc++", clang_dir.to_str().unwrap());
        } else{
            println!("cargo:rustc-flags=-l clang -L {}", clang_dir.to_str().unwrap());
        }
    } else {
        panic!("Unable to find {}", clang_lib);
    }
}
<commit_msg>Windows platform fixes<commit_after>use std::env;
use std::fs;
use std::path::Path;

const LINUX_CLANG_DIRS: &'static [&'static str] = &["/usr/lib", "/usr/lib/llvm", "/usr/lib64/llvm", "/usr/lib/x86_64-linux-gnu"];
const MAC_CLANG_DIR: &'static str = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib";
const WIN_CLANG_DIRS: &'static [&'static str] = &["C:\\Program Files\\LLVM\\bin", "C:\\Program Files\\LLVM\\lib"];

fn path_exists(path: &Path) -> bool {
    match fs::metadata(path) {
        Ok(_) => true,
        Err(_) => false
    }
}

fn main() {
    let use_static_lib = env::var_os("LIBCLANG_STATIC").is_some() || cfg!(feature = "static");

    let possible_clang_dirs = if let Ok(dir) = env::var("LIBCLANG_PATH") {
        vec![dir]
    } else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
        LINUX_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else if cfg!(target_os = "macos") {
        vec![MAC_CLANG_DIR.to_string()]
    } else if cfg!(target_os = "windows") {
		WIN_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else {
        panic!("Platform not supported");
    };

    let clang_lib = if cfg!(target_os = "windows") {
			format!("libclang{}", env::consts::DLL_SUFFIX)
		} else {
			format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)
		};

    let maybe_clang_dir = possible_clang_dirs.iter().filter_map(|candidate_dir| {
        let clang_dir = Path::new(candidate_dir);
        let clang_path = clang_dir.join(clang_lib.clone());
        if path_exists(&*clang_path) {
            Some(clang_dir)
        } else {
            None
        }
    }).next();

    macro_rules! qw {
        ($($i:ident)*) => (vec!($(stringify!($i)),*));
    }

    if let Some(clang_dir) = maybe_clang_dir {
        if use_static_lib {
            let libs = qw![
                LLVMAnalysis
                LLVMBitReader
                LLVMCore
                LLVMLTO
                LLVMLinker
                LLVMMC
                LLVMMCParser
                LLVMObjCARCOpts
                LLVMObject
                LLVMOption
                LLVMScalarOpts
                LLVMSupport
                LLVMTarget
                LLVMTransformUtils
                LLVMVectorize
                LLVMipa
                LLVMipo
                clang
                clangARCMigrate
                clangAST
                clangASTMatchers
                clangAnalysis
                clangBasic
                clangDriver
                clangEdit
                clangFormat
                clangFrontend
                clangIndex
                clangLex
                clangParse
                clangRewrite
                clangRewriteFrontend
                clangSema
                clangSerialization
                clangStaticAnalyzerCheckers
                clangStaticAnalyzerCore
                clangStaticAnalyzerFrontend
                clangTooling
            ];

            print!("cargo:rustc-flags=");
            for lib in libs {
                print!("-l static={} ", lib);
            }
            println!("-L {} -l ncursesw -l z -l stdc++", clang_dir.to_str().unwrap());
        } else{
            println!("cargo:rustc-link-search=native={}", clang_dir.to_str().unwrap());
            println!("cargo:rustc-link-lib=dylib=clang");
        }
    } else {
        panic!("Unable to find {}", clang_lib);
    }
}
<|endoftext|>


<commit_before>// 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.

extern crate gcc;

use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("msvc") {
        let mut config = gcc::Config::new();
        config.file("src/util_helpers.asm");
        config.file("src/aesni_helpers.asm");
        if target.contains("x86_64") {
            config.define("X64", None);
        }
        config.compile("lib_rust_crypto_helpers.a");
    } else {
        gcc::compile_library(
            "lib_rust_crypto_helpers.a",
            &["src/util_helpers.c", "src/aesni_helpers.c"]);
    }
}

<commit_msg>Use Inline assembly for msvc target from non-windows host<commit_after>// 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.

extern crate gcc;

use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if target.contains("msvc") && host.contains("windows") {
        let mut config = gcc::Config::new();
        config.file("src/util_helpers.asm");
        config.file("src/aesni_helpers.asm");
        if target.contains("x86_64") {
            config.define("X64", None);
        }
        config.compile("lib_rust_crypto_helpers.a");
    } else {
        gcc::compile_library(
            "lib_rust_crypto_helpers.a",
            &["src/util_helpers.c", "src/aesni_helpers.c"]);
    }
}

<|endoftext|>


<commit_before>// Bitcoin secp256k1 bindings
// Written in 2015 by
//   Andrew Poelstra
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Build script

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]

extern crate cc;

use std::io::{self, Write};

fn main() {
    // Check whether we can use 64-bit compilation
    #[cfg(target_pointer_width = "64")]
    let use_64bit_compilation = {
        let check = cc::Build::new().file("depend/check_uint128_t.c")
                                    .cargo_metadata(false)
                                    .try_compile("check_uint128_t")
                                    .is_ok();
        if !check {
            writeln!(
                &mut io::stderr(),
                "Warning: Compiling in 32-bit mode on a 64-bit architecture due to lack of uint128_t support."
            ).expect("print to stderr")
        }
        check
    };
    #[cfg(not(target_pointer_width = "64"))]
    let use_64bit_compilation = false;

    // Actual build
    let mut base_config = cc::Build::new();
    base_config.include("depend/secp256k1/")
               .include("depend/secp256k1/include")
               .include("depend/secp256k1/src")
               .flag("-g")
               .flag("-Wno-unused-function") // some ecmult stuff is defined but not used upstream
               .define("SECP256K1_BUILD", Some("1"))
               // TODO these three should be changed to use libgmp, at least until secp PR 290 is merged
               .define("USE_NUM_NONE", Some("1"))
               .define("USE_FIELD_INV_BUILTIN", Some("1"))
               .define("USE_SCALAR_INV_BUILTIN", Some("1"))
               .define("USE_ENDOMORPHISM", Some("1"))
               .define("ENABLE_MODULE_ECDH", Some("1"))
               .define("ENABLE_MODULE_RECOVERY", Some("1"));

    if use_64bit_compilation {
        base_config.define("USE_FIELD_5X52", Some("1"))
                   .define("USE_SCALAR_4X64", Some("1"))
                   .define("HAVE___INT128", Some("1"));
    } else {
        base_config.define("USE_FIELD_10X26", Some("1"))
                   .define("USE_SCALAR_8X32", Some("1"));
    }

    // secp256k1
    base_config.file("depend/secp256k1/contrib/lax_der_parsing.c")
               .file("depend/secp256k1/src/secp256k1.c")
               .compile("libsecp256k1.a");
}

<commit_msg>Use correct flag on big endian machines.<commit_after>// Bitcoin secp256k1 bindings
// Written in 2015 by
//   Andrew Poelstra
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Build script

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]

extern crate cc;

use std::io::{self, Write};

fn main() {
    // Check whether we can use 64-bit compilation
    #[cfg(target_pointer_width = "64")]
    let use_64bit_compilation = {
        let check = cc::Build::new().file("depend/check_uint128_t.c")
                                    .cargo_metadata(false)
                                    .try_compile("check_uint128_t")
                                    .is_ok();
        if !check {
            writeln!(
                &mut io::stderr(),
                "Warning: Compiling in 32-bit mode on a 64-bit architecture due to lack of uint128_t support."
            ).expect("print to stderr")
        }
        check
    };
    #[cfg(not(target_pointer_width = "64"))]
    let use_64bit_compilation = false;

    // Actual build
    let mut base_config = cc::Build::new();
    base_config.include("depend/secp256k1/")
               .include("depend/secp256k1/include")
               .include("depend/secp256k1/src")
               .flag("-g")
               .flag("-Wno-unused-function") // some ecmult stuff is defined but not used upstream
               .define("SECP256K1_BUILD", Some("1"))
               // TODO these three should be changed to use libgmp, at least until secp PR 290 is merged
               .define("USE_NUM_NONE", Some("1"))
               .define("USE_FIELD_INV_BUILTIN", Some("1"))
               .define("USE_SCALAR_INV_BUILTIN", Some("1"))
               .define("USE_ENDOMORPHISM", Some("1"))
               .define("ENABLE_MODULE_ECDH", Some("1"))
               .define("ENABLE_MODULE_RECOVERY", Some("1"));

    if let Ok(target_endian) = std::env::var("CARGO_CFG_TARGET_ENDIAN") {
        if target_endian == "big" {
            base_config.define("WORDS_BIGENDIAN", Some("1"));
        }
    }

    if use_64bit_compilation {
        base_config.define("USE_FIELD_5X52", Some("1"))
                   .define("USE_SCALAR_4X64", Some("1"))
                   .define("HAVE___INT128", Some("1"));
    } else {
        base_config.define("USE_FIELD_10X26", Some("1"))
                   .define("USE_SCALAR_8X32", Some("1"));
    }

    // secp256k1
    base_config.file("depend/secp256k1/contrib/lax_der_parsing.c")
               .file("depend/secp256k1/src/secp256k1.c")
               .compile("libsecp256k1.a");
}

<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Saurav Sachidanand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

extern crate gcc;
use std::env;
use std::process::Command;

macro_rules! nfd {
    ($suf:expr) => {
        concat!("nativefiledialog/src/", $suf);
    };
}

fn main() {
    let mut cfg = gcc::Config::new();
    let env = env::var("TARGET").unwrap();

    cfg.include(nfd!("include"));
    cfg.file(nfd!("nfd_common.c"));

    if env.contains("darwin") {
        cfg.file(nfd!("nfd_cocoa.m"));
        cfg.compile("libnfd.a");
        println!("cargo:rustc-link-lib=framework=AppKit");
    } else if env.contains("windows") {
        cfg.file(nfd!("nfd_win.cpp"));
        cfg.compile("libnfd.a");
        println!("cargo:rustc-link-lib=ole32");
        // MinGW doesn't link it by default
        println!("cargo:rustc-link-lib=uuid");
    } else {
        let pkg_output = Command::new("pkg-config")
            .arg("--cflags")
            .arg("gtk+-3.0")
            .arg("glib-2.0")
            .arg("--libs")
            .arg("glib-2.0")
            .output();
        match pkg_output {
            Ok(output) => {
                let t = String::from_utf8(output.stdout).unwrap();
                let flags = t.split(" ");
                for flag in flags {
                    if flag != "\n" && flag != "" {
                        cfg.flag(flag);
                    }
                }
            }
            _ => (),
        }
        cfg.file(nfd!("nfd_gtk.c"));
        cfg.compile("libnfd.a");
        println!("cargo:rustc-link-lib=gdk-3");
        println!("cargo:rustc-link-lib=gtk-3");
        println!("cargo:rustc-link-lib=glib-2.0");
        println!("cargo:rustc-link-lib=gobject-2.0");
    }
}
<commit_msg>Use Cpp explicitly for Windows<commit_after>/*
Copyright (c) 2016 Saurav Sachidanand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

extern crate gcc;
use std::env;
use std::process::Command;

macro_rules! nfd {
    ($suf:expr) => {
        concat!("nativefiledialog/src/", $suf);
    };
}

fn main() {
    let mut cfg = gcc::Config::new();
    let env = env::var("TARGET").unwrap();

    cfg.include(nfd!("include"));
    cfg.file(nfd!("nfd_common.c"));

    if env.contains("darwin") {
        cfg.file(nfd!("nfd_cocoa.m"));
        cfg.compile("libnfd.a");
        println!("cargo:rustc-link-lib=framework=AppKit");
    } else if env.contains("windows") {
        cfg.cpp(true);
        cfg.file(nfd!("nfd_win.cpp"));
        cfg.compile("libnfd.a");
        println!("cargo:rustc-link-lib=ole32");
        // MinGW doesn't link it by default
        println!("cargo:rustc-link-lib=uuid");
    } else {
        let pkg_output = Command::new("pkg-config")
            .arg("--cflags")
            .arg("gtk+-3.0")
            .arg("glib-2.0")
            .arg("--libs")
            .arg("glib-2.0")
            .output();
        match pkg_output {
            Ok(output) => {
                let t = String::from_utf8(output.stdout).unwrap();
                let flags = t.split(" ");
                for flag in flags {
                    if flag != "\n" && flag != "" {
                        cfg.flag(flag);
                    }
                }
            }
            _ => (),
        }
        cfg.file(nfd!("nfd_gtk.c"));
        cfg.compile("libnfd.a");
        println!("cargo:rustc-link-lib=gdk-3");
        println!("cargo:rustc-link-lib=gtk-3");
        println!("cargo:rustc-link-lib=glib-2.0");
        println!("cargo:rustc-link-lib=gobject-2.0");
    }
}
<|endoftext|>