<commit_before>//! An IRC transport that wraps an IRC-framed stream to provide a number of features including
//! automatic PING replies, automatic sending of PINGs, and message rate-limiting. This can be used
//! as the basis for implementing a more full IRC client.
use std::{
    pin::Pin,
    sync::{Arc, RwLock, RwLockReadGuard},
    task::{Context, Poll},
    time::Duration,
};

use chrono::prelude::*;
use futures_channel::mpsc::UnboundedSender;
use futures_util::{future::Future, ready, sink::Sink, stream::Stream};
use tokio::{
    io::{AsyncRead, AsyncWrite},
    time::{self, Delay, Interval},
};
use tokio_util::codec::Framed;

use crate::{
    client::data::Config,
    error,
    proto::{Command, IrcCodec, Message},
};

/// Pinger-based futures helper.
struct Pinger {
    tx: UnboundedSender<Message>,
    /// The amount of time to wait before timing out from no ping response.
    ping_timeout: Duration,
    /// The instant that the last ping was sent to the server.
    ping_deadline: Option<Delay>,
    /// The interval at which to send pings.
    ping_interval: Interval,
}

impl Pinger {
    /// Construct a new pinger helper.
    pub fn new(tx: UnboundedSender<Message>, config: &Config) -> Pinger {
        let ping_timeout = Duration::from_secs(u64::from(config.ping_timeout()));

        Self {
            tx,
            ping_timeout,
            ping_deadline: None,
            ping_interval: time::interval(ping_timeout / 2),
        }
    }

    /// Handle an incoming message.
    fn handle_message(&mut self, message: &Message) -> error::Result<()> {
        match message.command {
            // On receiving a `PING` message from the server, we automatically respond with
            // the appropriate `PONG` message to keep the connection alive for transport.
            Command::PING(ref data, _) => {
                self.send_pong(data)?;
            }
            // Check `PONG` responses from the server. If it matches, we will update the
            // last instant that the pong was received. This will prevent timeout.
            Command::PONG(_, None) | Command::PONG(_, Some(_)) => {
                log::trace!("Received PONG");
                self.ping_deadline.take();
            }
            _ => (),
        }

        Ok(())
    }

    /// Send a pong.
    fn send_pong(&mut self, data: &str) -> error::Result<()> {
        self.tx
            .unbounded_send(Command::PONG(data.to_owned(), None).into())?;
        Ok(())
    }

    /// Sends a ping via the transport.
    fn send_ping(&mut self) -> error::Result<()> {
        log::trace!("Sending PING");

        // Creates new ping data using the local timestamp.
        let data = format!("{}", Local::now().timestamp());

        self.tx
            .unbounded_send(Command::PING(data.clone(), None).into())?;

        Ok(())
    }

    /// Set the ping deadline.
    fn set_deadline(&mut self) {
        if self.ping_deadline.is_none() {
            let ping_deadline = time::delay_for(self.ping_timeout);
            self.ping_deadline = Some(ping_deadline);
        }
    }
}

impl Future for Pinger {
    type Output = Result<(), error::Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if let Some(ping_deadline) = self.as_mut().ping_deadline.as_mut() {
            match Pin::new(ping_deadline).poll(cx) {
                Poll::Ready(()) => return Poll::Ready(Err(error::Error::PingTimeout)),
                Poll::Pending => (),
            }
        }

        if let Poll::Ready(_) = Pin::new(&mut self.as_mut().ping_interval).poll_next(cx) {
            self.as_mut().send_ping()?;
            self.as_mut().set_deadline();
        }

        Poll::Pending
    }
}

/// An IRC transport that handles core functionality for the IRC protocol. This is used in the
/// implementation of `Connection` and ultimately `IrcServer`, and plays an important role in
/// handling connection timeouts, message throttling, and ping response.
pub struct Transport<T> {
    /// The inner connection framed with an `IrcCodec`.
    inner: Framed<T, IrcCodec>,
    /// Helper for handle pinging.
    pinger: Option<Pinger>,
}

impl<T> Unpin for Transport<T> where T: Unpin {}

impl<T> Transport<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    /// Creates a new `Transport` from the given IRC stream.
    pub fn new(
        config: &Config,
        inner: Framed<T, IrcCodec>,
        tx: UnboundedSender<Message>,
    ) -> Transport<T> {
        let pinger = Some(Pinger::new(tx, config));

        Transport { inner, pinger }
    }

    /// Gets the inner stream underlying the `Transport`.
    pub fn into_inner(self) -> Framed<T, IrcCodec> {
        self.inner
    }
}

impl<T> Stream for Transport<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Item = Result<Message, error::Error>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        if let Some(pinger) = self.as_mut().pinger.as_mut() {
            match Pin::new(pinger).poll(cx) {
                Poll::Ready(result) => result?,
                Poll::Pending => (),
            }
        }

        let result = ready!(Pin::new(&mut self.as_mut().inner).poll_next(cx));

        let message = match result {
            None => return Poll::Ready(None),
            Some(message) => message?,
        };

        if let Some(pinger) = self.as_mut().pinger.as_mut() {
            pinger.handle_message(&message)?;
        }

        Poll::Ready(Some(Ok(message)))
    }
}

impl<T> Sink<Message> for Transport<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Error = error::Error;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(Pin::new(&mut self.as_mut().inner).poll_ready(cx))?;
        Poll::Ready(Ok(()))
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        log::trace!("[SEND] {}", item);
        Pin::new(&mut self.as_mut().inner).start_send(item)?;
        Ok(())
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(Pin::new(&mut self.as_mut().inner).poll_flush(cx))?;
        Poll::Ready(Ok(()))
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(Pin::new(&mut self.as_mut().inner).poll_close(cx))?;
        Poll::Ready(Ok(()))
    }
}

/// A view of the logs from a particular `Logged` transport.
#[derive(Clone, Debug)]
pub struct LogView {
    sent: Arc<RwLock<Vec<Message>>>,
    received: Arc<RwLock<Vec<Message>>>,
}

impl LogView {
    /// Gets a read guard for all the messages sent on the transport.
    pub fn sent(&self) -> error::Result<RwLockReadGuard<Vec<Message>>> {
        self.sent.read().map_err(|_| error::Error::PoisonedLog)
    }

    /// Gets a read guard for all the messages received on the transport.
    pub fn received(&self) -> error::Result<RwLockReadGuard<Vec<Message>>> {
        self.received.read().map_err(|_| error::Error::PoisonedLog)
    }
}

/// A logged version of the `Transport` that records all sent and received messages.
/// Note: this will introduce some performance overhead by cloning all messages.
pub struct Logged<T> {
    inner: Transport<T>,
    view: LogView,
}

impl<T> Unpin for Logged<T> where T: Unpin {}

impl<T> Logged<T>
where
    T: AsyncRead + AsyncWrite,
{
    /// Wraps the given `Transport` in logging.
    pub fn wrap(inner: Transport<T>) -> Logged<T> {
        Logged {
            inner,
            view: LogView {
                sent: Arc::new(RwLock::new(vec![])),
                received: Arc::new(RwLock::new(vec![])),
            },
        }
    }

    /// Gets a view of the logging for this transport.
    pub fn view(&self) -> LogView {
        self.view.clone()
    }
}

impl<T> Stream for Logged<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Item = Result<Message, error::Error>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match ready!(Pin::new(&mut self.as_mut().inner).poll_next(cx)) {
            Some(msg) => {
                let msg = msg?;

                self.view
                    .received
                    .write()
                    .map_err(|_| error::Error::PoisonedLog)?
                    .push(msg.clone());

                Poll::Ready(Some(Ok(msg)))
            }
            None => Poll::Ready(None),
        }
    }
}

impl<T> Sink<Message> for Logged<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Error = error::Error;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Pin::new(&mut self.as_mut().inner).poll_ready(cx)
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Pin::new(&mut self.as_mut().inner).poll_close(cx)
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        Pin::new(&mut self.as_mut().inner).start_send(item.clone())?;

        self.view
            .sent
            .write()
            .map_err(|_| error::Error::PoisonedLog)?
            .push(item);

        Ok(())
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Pin::new(&mut self.as_mut().inner).poll_flush(cx)
    }
}
<commit_msg>ping_time is once again used to define the ping intervals<commit_after>//! An IRC transport that wraps an IRC-framed stream to provide a number of features including
//! automatic PING replies, automatic sending of PINGs, and message rate-limiting. This can be used
//! as the basis for implementing a more full IRC client.
use std::{
    pin::Pin,
    sync::{Arc, RwLock, RwLockReadGuard},
    task::{Context, Poll},
    time::Duration,
};

use chrono::prelude::*;
use futures_channel::mpsc::UnboundedSender;
use futures_util::{future::Future, ready, sink::Sink, stream::Stream};
use tokio::{
    io::{AsyncRead, AsyncWrite},
    time::{self, Delay, Interval},
};
use tokio_util::codec::Framed;

use crate::{
    client::data::Config,
    error,
    proto::{Command, IrcCodec, Message},
};

/// Pinger-based futures helper.
struct Pinger {
    tx: UnboundedSender<Message>,
    /// The amount of time to wait before timing out from no ping response.
    ping_timeout: Duration,
    /// The instant that the last ping was sent to the server.
    ping_deadline: Option<Delay>,
    /// The interval at which to send pings.
    ping_interval: Interval,
}

impl Pinger {
    /// Construct a new pinger helper.
    pub fn new(tx: UnboundedSender<Message>, config: &Config) -> Pinger {
        let ping_time = Duration::from_secs(u64::from(config.ping_time()));
        let ping_timeout = Duration::from_secs(u64::from(config.ping_timeout()));

        Self {
            tx,
            ping_timeout,
            ping_deadline: None,
            ping_interval: time::interval(ping_time),
        }
    }

    /// Handle an incoming message.
    fn handle_message(&mut self, message: &Message) -> error::Result<()> {
        match message.command {
            // On receiving a `PING` message from the server, we automatically respond with
            // the appropriate `PONG` message to keep the connection alive for transport.
            Command::PING(ref data, _) => {
                self.send_pong(data)?;
            }
            // Check `PONG` responses from the server. If it matches, we will update the
            // last instant that the pong was received. This will prevent timeout.
            Command::PONG(_, None) | Command::PONG(_, Some(_)) => {
                log::trace!("Received PONG");
                self.ping_deadline.take();
            }
            _ => (),
        }

        Ok(())
    }

    /// Send a pong.
    fn send_pong(&mut self, data: &str) -> error::Result<()> {
        self.tx
            .unbounded_send(Command::PONG(data.to_owned(), None).into())?;
        Ok(())
    }

    /// Sends a ping via the transport.
    fn send_ping(&mut self) -> error::Result<()> {
        log::trace!("Sending PING");

        // Creates new ping data using the local timestamp.
        let data = format!("{}", Local::now().timestamp());

        self.tx
            .unbounded_send(Command::PING(data.clone(), None).into())?;

        Ok(())
    }

    /// Set the ping deadline.
    fn set_deadline(&mut self) {
        if self.ping_deadline.is_none() {
            let ping_deadline = time::delay_for(self.ping_timeout);
            self.ping_deadline = Some(ping_deadline);
        }
    }
}

impl Future for Pinger {
    type Output = Result<(), error::Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if let Some(ping_deadline) = self.as_mut().ping_deadline.as_mut() {
            match Pin::new(ping_deadline).poll(cx) {
                Poll::Ready(()) => return Poll::Ready(Err(error::Error::PingTimeout)),
                Poll::Pending => (),
            }
        }

        if let Poll::Ready(_) = Pin::new(&mut self.as_mut().ping_interval).poll_next(cx) {
            self.as_mut().send_ping()?;
            self.as_mut().set_deadline();
        }

        Poll::Pending
    }
}

/// An IRC transport that handles core functionality for the IRC protocol. This is used in the
/// implementation of `Connection` and ultimately `IrcServer`, and plays an important role in
/// handling connection timeouts, message throttling, and ping response.
pub struct Transport<T> {
    /// The inner connection framed with an `IrcCodec`.
    inner: Framed<T, IrcCodec>,
    /// Helper for handle pinging.
    pinger: Option<Pinger>,
}

impl<T> Unpin for Transport<T> where T: Unpin {}

impl<T> Transport<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    /// Creates a new `Transport` from the given IRC stream.
    pub fn new(
        config: &Config,
        inner: Framed<T, IrcCodec>,
        tx: UnboundedSender<Message>,
    ) -> Transport<T> {
        let pinger = Some(Pinger::new(tx, config));

        Transport { inner, pinger }
    }

    /// Gets the inner stream underlying the `Transport`.
    pub fn into_inner(self) -> Framed<T, IrcCodec> {
        self.inner
    }
}

impl<T> Stream for Transport<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Item = Result<Message, error::Error>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        if let Some(pinger) = self.as_mut().pinger.as_mut() {
            match Pin::new(pinger).poll(cx) {
                Poll::Ready(result) => result?,
                Poll::Pending => (),
            }
        }

        let result = ready!(Pin::new(&mut self.as_mut().inner).poll_next(cx));

        let message = match result {
            None => return Poll::Ready(None),
            Some(message) => message?,
        };

        if let Some(pinger) = self.as_mut().pinger.as_mut() {
            pinger.handle_message(&message)?;
        }

        Poll::Ready(Some(Ok(message)))
    }
}

impl<T> Sink<Message> for Transport<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Error = error::Error;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(Pin::new(&mut self.as_mut().inner).poll_ready(cx))?;
        Poll::Ready(Ok(()))
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        log::trace!("[SEND] {}", item);
        Pin::new(&mut self.as_mut().inner).start_send(item)?;
        Ok(())
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(Pin::new(&mut self.as_mut().inner).poll_flush(cx))?;
        Poll::Ready(Ok(()))
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        ready!(Pin::new(&mut self.as_mut().inner).poll_close(cx))?;
        Poll::Ready(Ok(()))
    }
}

/// A view of the logs from a particular `Logged` transport.
#[derive(Clone, Debug)]
pub struct LogView {
    sent: Arc<RwLock<Vec<Message>>>,
    received: Arc<RwLock<Vec<Message>>>,
}

impl LogView {
    /// Gets a read guard for all the messages sent on the transport.
    pub fn sent(&self) -> error::Result<RwLockReadGuard<Vec<Message>>> {
        self.sent.read().map_err(|_| error::Error::PoisonedLog)
    }

    /// Gets a read guard for all the messages received on the transport.
    pub fn received(&self) -> error::Result<RwLockReadGuard<Vec<Message>>> {
        self.received.read().map_err(|_| error::Error::PoisonedLog)
    }
}

/// A logged version of the `Transport` that records all sent and received messages.
/// Note: this will introduce some performance overhead by cloning all messages.
pub struct Logged<T> {
    inner: Transport<T>,
    view: LogView,
}

impl<T> Unpin for Logged<T> where T: Unpin {}

impl<T> Logged<T>
where
    T: AsyncRead + AsyncWrite,
{
    /// Wraps the given `Transport` in logging.
    pub fn wrap(inner: Transport<T>) -> Logged<T> {
        Logged {
            inner,
            view: LogView {
                sent: Arc::new(RwLock::new(vec![])),
                received: Arc::new(RwLock::new(vec![])),
            },
        }
    }

    /// Gets a view of the logging for this transport.
    pub fn view(&self) -> LogView {
        self.view.clone()
    }
}

impl<T> Stream for Logged<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Item = Result<Message, error::Error>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        match ready!(Pin::new(&mut self.as_mut().inner).poll_next(cx)) {
            Some(msg) => {
                let msg = msg?;

                self.view
                    .received
                    .write()
                    .map_err(|_| error::Error::PoisonedLog)?
                    .push(msg.clone());

                Poll::Ready(Some(Ok(msg)))
            }
            None => Poll::Ready(None),
        }
    }
}

impl<T> Sink<Message> for Logged<T>
where
    T: Unpin + AsyncRead + AsyncWrite,
{
    type Error = error::Error;

    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Pin::new(&mut self.as_mut().inner).poll_ready(cx)
    }

    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Pin::new(&mut self.as_mut().inner).poll_close(cx)
    }

    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
        Pin::new(&mut self.as_mut().inner).start_send(item.clone())?;

        self.view
            .sent
            .write()
            .map_err(|_| error::Error::PoisonedLog)?
            .push(item);

        Ok(())
    }

    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Pin::new(&mut self.as_mut().inner).poll_flush(cx)
    }
}
<|endoftext|>


<commit_before>use ::anyhow::{anyhow, Result};
use ::log::info;
use ::rand::Rng;
use ::serde_derive::{Deserialize, Serialize};
use ::std::fs::File;
use ::std::io::prelude::*;
use ::std::path::{Path, PathBuf};

use ::config::Config;

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Client {
    //    pub daemon_address: String,
    pub daemon_port: String,
    pub secret: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Daemon {
    pub pueue_directory: String,
    pub default_parallel_tasks: usize,
    //    pub address: String,
    pub port: String,
    pub secret: String,
}

/// The struct representation of a full configuration.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Settings {
    pub client: Client,
    pub daemon: Daemon,
}

impl Settings {
    /// This function creates a new configuration instance and
    /// populates it with default values for every option.
    /// If a local config file already exists it is parsed and
    /// overwrites the default option values.
    /// The local config is located at "~/.config/pueue.yml".
    pub fn new() -> Result<Settings> {
        let mut config = Config::new();

        let random_secret = gen_random_secret();
        // Set pueue config defaults
        config.set_default("daemon.pueue_directory", default_pueue_path()?)?;
        //        config.set_default("daemon.address", "127.0.0.1")?;
        config.set_default("daemon.port", "6924")?;
        config.set_default("daemon.default_parallel_tasks", 1)?;
        config.set_default("daemon.secret", random_secret.clone())?;

        //        config.set_default("client.daemon_address", "127.0.0.1")?;
        config.set_default("client.daemon_port", "6924")?;
        config.set_default("client.secret", random_secret)?;

        // Add in the home config file
        parse_config(&mut config)?;

        // You can deserialize (and thus freeze) the entire configuration
        Ok(config.try_into()?)
    }

    /// Save the current configuration as a file to the configuration path.
    /// The file is written to "~/.config/pueue.yml".
    pub fn save(&self) -> Result<()> {
        let content = serde_yaml::to_string(self)?;
        let mut file = File::create(default_config_path()?)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

fn parse_config(settings: &mut Config) -> Result<()> {
    info!("Parsing config files");
    let config_paths = get_config_paths()?;

    for path in config_paths.into_iter() {
        info!("Checking path: {:?}", &path);
        if path.exists() {
            info!("Parsing config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            settings.merge(config_file)?;
        }
    }

    Ok(())
}

fn get_home_dir() -> Result<PathBuf> {
    dirs::home_dir().ok_or(anyhow!("Couldn't resolve home dir"))
}

fn gen_random_secret() -> String {
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~";
    const PASSWORD_LEN: usize = 20;
    let mut rng = rand::thread_rng();

    let secret: String = (0..PASSWORD_LEN)
        .map(|_| {
            let idx = rng.gen_range(0, CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();

    secret
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn default_config_path() -> Result<PathBuf> {
    Ok(get_home_dir()?.join(".config/pueue.yml"))
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn get_config_paths() -> Result<Vec<PathBuf>> {
    let mut paths = Vec::new();
    paths.push(Path::new("/etc/pueue.yml").to_path_buf());
    paths.push(default_config_path()?);
    paths.push(Path::new("./pueue.yml").to_path_buf());

    Ok(paths)
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn default_pueue_path() -> Result<String> {
    let path = get_home_dir()?.join(".local/share/pueue");
    path.to_str().map_or_else(
        || Err(anyhow!("Failed to parse log path (Weird characters?)")),
        |v| Ok(v.to_string()),
    )
}

#[cfg(target_os = "macos")]
fn default_config_path() -> Result<PathBuf> {
    Ok(get_home_dir()?.join("Library/Preferences/pueue.yml"))
}

#[cfg(target_os = "macos")]
fn get_config_paths() -> Result<Vec<PathBuf>> {
    let mut paths = Vec::new();
    paths.push(default_config_path()?);
    paths.push(Path::new("./pueue.yml").to_path_buf());

    Ok(paths)
}

#[cfg(target_os = "macos")]
fn default_pueue_path() -> Result<String> {
    let path = get_home_dir()?.join(".local/share/pueue");
    path.to_str().map_or_else(
        || Err(anyhow!("Failed to parse log path (Weird characters?)")),
        |v| Ok(v.to_string()),
    )
}

#[cfg(target_os = "windows")]
fn default_config_path() -> Result<PathBuf> {
    Ok(get_home_dir()?.join("pueue.yml"))
}

#[cfg(target_os = "windows")]
fn get_config_paths() -> Result<Vec<PathBuf>> {
    Ok(vec![
        // Windows Terminal stores its config file in the "AppData/Local" directory.
        dirs::data_local_dir()
            .ok_or(anyhow!("Couldn't resolve app data directory"))?
            .join("pueue/pueue.yml"),
        default_config_path()?,
        Path::new("./pueue.yml").to_path_buf(),
    ])
}

#[cfg(target_os = "windows")]
fn default_pueue_path() -> Result<String> {
    // Use local data directory since this data doesn't need to be synced.
    let path = dirs::data_local_dir()
        .ok_or(anyhow!("Couldn't resolve app data directory"))?
        .join("pueue");
    path.to_str().map_or_else(
        || Err(anyhow!("Failed to parse log path (Weird characters?)")),
        |v| Ok(v.to_string()),
    )
}
<commit_msg>Auto-create config dir. Fixes #67<commit_after>use ::anyhow::{anyhow, Result};
use ::log::info;
use ::rand::Rng;
use ::serde_derive::{Deserialize, Serialize};
use ::std::fs::{File, create_dir_all};
use ::std::io::prelude::*;
use ::std::path::{Path, PathBuf};

use ::config::Config;

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Client {
    //    pub daemon_address: String,
    pub daemon_port: String,
    pub secret: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Daemon {
    pub pueue_directory: String,
    pub default_parallel_tasks: usize,
    //    pub address: String,
    pub port: String,
    pub secret: String,
}

/// The struct representation of a full configuration.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Settings {
    pub client: Client,
    pub daemon: Daemon,
}

impl Settings {
    /// This function creates a new configuration instance and
    /// populates it with default values for every option.
    /// If a local config file already exists it is parsed and
    /// overwrites the default option values.
    /// The local config is located at "~/.config/pueue.yml".
    pub fn new() -> Result<Settings> {
        let mut config = Config::new();

        let random_secret = gen_random_secret();
        // Set pueue config defaults
        config.set_default("daemon.pueue_directory", default_pueue_path()?)?;
        //        config.set_default("daemon.address", "127.0.0.1")?;
        config.set_default("daemon.port", "6924")?;
        config.set_default("daemon.default_parallel_tasks", 1)?;
        config.set_default("daemon.secret", random_secret.clone())?;

        //        config.set_default("client.daemon_address", "127.0.0.1")?;
        config.set_default("client.daemon_port", "6924")?;
        config.set_default("client.secret", random_secret)?;

        // Add in the home config file
        parse_config(&mut config)?;

        // You can deserialize (and thus freeze) the entire configuration
        Ok(config.try_into()?)
    }

    /// Save the current configuration as a file to the configuration path.
    /// The file is written to the main configuration directory of the respective OS
    pub fn save(&self) -> Result<()> {
        let config_path = default_config_path()?;
        let config_dir = config_path.parent().ok_or(anyhow!("Couldn't resolve config dir"))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = serde_yaml::to_string(self)?;
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

fn parse_config(settings: &mut Config) -> Result<()> {
    info!("Parsing config files");
    let config_paths = get_config_paths()?;

    for path in config_paths.into_iter() {
        info!("Checking path: {:?}", &path);
        if path.exists() {
            info!("Parsing config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            settings.merge(config_file)?;
        }
    }

    Ok(())
}

fn get_home_dir() -> Result<PathBuf> {
    dirs::home_dir().ok_or(anyhow!("Couldn't resolve home dir"))
}

fn gen_random_secret() -> String {
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~";
    const PASSWORD_LEN: usize = 20;
    let mut rng = rand::thread_rng();

    let secret: String = (0..PASSWORD_LEN)
        .map(|_| {
            let idx = rng.gen_range(0, CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();

    secret
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn default_config_path() -> Result<PathBuf> {
    Ok(get_home_dir()?.join(".config/pueue.yml"))
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn get_config_paths() -> Result<Vec<PathBuf>> {
    let mut paths = Vec::new();
    paths.push(Path::new("/etc/pueue.yml").to_path_buf());
    paths.push(default_config_path()?);
    paths.push(Path::new("./pueue.yml").to_path_buf());

    Ok(paths)
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn default_pueue_path() -> Result<String> {
    let path = get_home_dir()?.join(".local/share/pueue");
    path.to_str().map_or_else(
        || Err(anyhow!("Failed to parse log path (Weird characters?)")),
        |v| Ok(v.to_string()),
    )
}

#[cfg(target_os = "macos")]
fn default_config_path() -> Result<PathBuf> {
    Ok(get_home_dir()?.join("Library/Preferences/pueue.yml"))
}

#[cfg(target_os = "macos")]
fn get_config_paths() -> Result<Vec<PathBuf>> {
    let mut paths = Vec::new();
    paths.push(default_config_path()?);
    paths.push(Path::new("./pueue.yml").to_path_buf());

    Ok(paths)
}

#[cfg(target_os = "macos")]
fn default_pueue_path() -> Result<String> {
    let path = get_home_dir()?.join(".local/share/pueue");
    path.to_str().map_or_else(
        || Err(anyhow!("Failed to parse log path (Weird characters?)")),
        |v| Ok(v.to_string()),
    )
}

#[cfg(target_os = "windows")]
fn default_config_path() -> Result<PathBuf> {
    Ok(get_home_dir()?.join("pueue.yml"))
}

#[cfg(target_os = "windows")]
fn get_config_paths() -> Result<Vec<PathBuf>> {
    Ok(vec![
        // Windows Terminal stores its config file in the "AppData/Local" directory.
        dirs::data_local_dir()
            .ok_or(anyhow!("Couldn't resolve app data directory"))?
            .join("pueue/pueue.yml"),
        default_config_path()?,
        Path::new("./pueue.yml").to_path_buf(),
    ])
}

#[cfg(target_os = "windows")]
fn default_pueue_path() -> Result<String> {
    // Use local data directory since this data doesn't need to be synced.
    let path = dirs::data_local_dir()
        .ok_or(anyhow!("Couldn't resolve app data directory"))?
        .join("pueue");
    path.to_str().map_or_else(
        || Err(anyhow!("Failed to parse log path (Weird characters?)")),
        |v| Ok(v.to_string()),
    )
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{Result, Write};
use case::CaseExt;

use analysis::rust_type::parameter_rust_type;
use env::Env;
use file_saver::*;
use library::*;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use super::super::general;
use traits::*;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  env.config.target_path.join(file_name_sys("lib"));

    println!("Generating file {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_lib(w, env));
}

fn generate_lib(w: &mut Write, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    try!(generate_extern_crates(w, env));
    try!(statics::after_extern_crates(w));

    if env.config.library_name != "GLib" {
        try!(statics::use_glib(w));
    }
    match &*env.config.library_name {
        "GLib" => try!(statics::only_for_glib(w)),
        "GObject" => try!(statics::only_for_gobject(w)),
        "Gtk" => try!(statics::only_for_gtk(w)),
        _ => (),
    }

    let ns = env.library.namespace(MAIN_NAMESPACE);
    let records = prepare(ns);
    let classes = prepare(ns);
    let interfaces = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &prepare(ns)));
    try!(generate_constants(w, env, &ns.constants));
    try!(generate_bitfields(w, &prepare(ns)));
    try!(generate_unions(w, &prepare(ns)));
    try!(functions::generate_callbacks(w, env, &prepare(ns)));
    try!(generate_records(w, env, &records));
    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &interfaces));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_records_funcs(w, env, &records));
    try!(functions::generate_classes_funcs(w, env, &classes));
    try!(functions::generate_interfaces_funcs(w, env, &interfaces));
    try!(functions::generate_other_funcs(w, env, &ns.functions));

    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()>{
    for library_name in &env.config.external_libraries {
        try!(writeln!(w, "extern crate {0}_sys as {0};", crate_name(library_name)));
    }

    Ok(())
}

fn prepare<T: Ord>(ns: &Namespace) -> Vec<&T>
where Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_aliases(w: &mut Write, env: &Env, items: &[&Alias])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let (comment, c_type) = match ffi_type(env, item.typ, &item.target_c_type) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields(w: &mut Write, items: &[&Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "bitflags! {{\n\t#[repr(C)]\n\tflags {}: c_uint {{", item.c_type));
        for member in &item.members {
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "\t\tconst {} = {},", member.c_identifier, val as u32));
        }
        try!(writeln!(w, "\t}}\n}}"));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_constants(w: &mut Write, env: &Env, constants: &[Constant]) -> Result<()> {
    try!(writeln!(w, ""));
    for constant in constants {
        let (mut comment, mut type_) =
            match parameter_rust_type(env, constant.typ, ParameterDirection::In, Nullable(false)) {
                Ok(x) => ("", x),
                Err(x) => ("//", x),
            };
        if env.type_status_sys(&format!("{}.{}", env.config.library_name,
            constant.name)).ignored() {
            comment = "//";
        }
        let mut value = constant.value.clone();
        if type_ == "&str" {
            type_ = "&'static str".into();
            value = format!("r##\"{}\"##", value);
        }
        try!(writeln!(w, "{}pub const {}: {} = {};", comment,
            constant.c_identifier, type_, value));
    }

    Ok(())
}

fn generate_enums(w: &mut Write, items: &[&Enumeration])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if item.members.len() == 1 {
            try!(writeln!(w, "pub type {} = c_int;", item.name));
            try!(writeln!(w, "pub const {}: {} = {};",
                          item.members[0].c_identifier, item.name, item.members[0].value));
            try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
            try!(writeln!(w, ""));
            continue;
        }

        let mut vals = HashMap::new();
        try!(writeln!(w, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]\n#[repr(C)]"));
        try!(writeln!(w, "pub enum {} {{", item.c_type));
        for member in &item.members {
            if vals.get(&member.value).is_some() {
                continue;
            }
            try!(writeln!(w, "\t{} = {},",
                          &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), member.name.clone());
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            try!(writeln!(w, "pub const {}: {} = {1}::{};", member.c_identifier, item.c_type,
                          &prepare_enum_member_name(vals.get(&member.value).unwrap())));
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions(w: &mut Write, items: &[&Union])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if let Some(ref c_type) = item.c_type {
            try!(writeln!(w, "pub type {} = c_void; // union", c_type));
        }
    }
    try!(writeln!(w, ""));

    Ok(())
}

fn prepare_enum_member_name(name: &str) -> String {
    let cameled = name.to_camel();
    if name.chars().next().unwrap().is_digit(10) {
        format!("_{}", cameled)
    } else {
        cameled
    }
}

fn generate_classes_structs(w: &mut Write, classes: &[&Class]) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {}(c_void);", klass.c_type));
    }

    Ok(())
}

fn generate_interfaces_structs(w: &mut Write, interfaces: &[&Interface]) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {}(c_void);", interface.c_type));
    }

    Ok(())
}

fn generate_records(w: &mut Write, env: &Env, records: &[&Record]) -> Result<()> {
    try!(writeln!(w, ""));
    for record in records {
        let mut lines = Vec::new();
        let mut commented = false;
        let mut truncated = false;
        for field in &record.fields {
            let is_union = env.library.type_(field.typ).maybe_ref_as::<Union>().is_some();
            let is_bits = field.bits.is_some();
            if !truncated && (is_union || is_bits) {
                warn!("Record `{}` field `{}` not expressible in Rust, truncated",
                      record.name, field.name);
                lines.push(format!("\t_truncated_record_marker: c_void,"));
                truncated = true;
            }
            if truncated {
                if is_union {
                    lines.push(format!("\t//union,"));
                }
                else {
                    let bits = field.bits.map(|n| format!(": {}", n)).unwrap_or("".into());
                    lines.push(
                        format!("\t//{}: {}{},", field.name,
                                field.c_type.as_ref().map(|s| &s[..]).unwrap_or("fn"), bits));
                };
                continue;
            }

            let vis = if field.private { "" } else { "pub " };

            if let Some(ref c_type) = field.c_type {
                let name = mangle_keywords(&*field.name);
                let c_type = ffi_type(env, field.typ, c_type);
                lines.push(format!("\t{}{}: {},", vis, name, c_type.as_str()));
                if c_type.is_err() {
                    commented = true;
                }
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("\t{}{}: Option<unsafe extern \"C\" fn{}>,", vis, name, sig));
                    commented |= com;
                }
                else if let Some(c_type) = env.library.type_(field.typ).get_glib_name() {
                    warn!("Record `{}`, field `{}` missing c:type assumed `{}`",
                          record.name, field.name, c_type);
                    let c_type = ffi_type(env, field.typ, c_type);
                    lines.push(format!("\t{}{}: {},", vis, name, c_type.as_str()));
                    if c_type.is_err() {
                        commented = true;
                    }
                }
                else {
                    lines.push(format!("\t{}{}: [{:?} {}],",
                        vis, name, field.typ, field.typ.full_name(&env.library)));
                    commented = true;
                }
            }
        }
        let comment = if commented { "//" } else { "" };
        if lines.is_empty() {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {}(c_void);\n", comment, record.c_type));
        }
        else {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {} {{", comment, record.c_type));
            for line in lines {
                try!(writeln!(w, "{}{}", comment, line));
            }
            try!(writeln!(w, "{}}}\n", comment));
        }
    }
    Ok(())
}
<commit_msg>Fix wrong name for PangoGlyph constants<commit_after>use std::collections::HashMap;
use std::io::{Result, Write};
use case::CaseExt;

use analysis::rust_type::parameter_rust_type;
use env::Env;
use file_saver::*;
use library::*;
use nameutil::*;
use super::ffi_type::ffi_type;
use super::functions;
use super::statics;
use super::super::general;
use traits::*;

pub fn generate(env: &Env) {
    println!("generating sys for {}", env.config.library_name);

    let path =  env.config.target_path.join(file_name_sys("lib"));

    println!("Generating file {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_lib(w, env));
}

fn generate_lib(w: &mut Write, env: &Env) -> Result<()>{
    try!(general::start_comments(w, &env.config));
    try!(statics::begin(w));

    try!(generate_extern_crates(w, env));
    try!(statics::after_extern_crates(w));

    if env.config.library_name != "GLib" {
        try!(statics::use_glib(w));
    }
    match &*env.config.library_name {
        "GLib" => try!(statics::only_for_glib(w)),
        "GObject" => try!(statics::only_for_gobject(w)),
        "Gtk" => try!(statics::only_for_gtk(w)),
        _ => (),
    }

    let ns = env.library.namespace(MAIN_NAMESPACE);
    let records = prepare(ns);
    let classes = prepare(ns);
    let interfaces = prepare(ns);

    try!(generate_aliases(w, env, &prepare(ns)));
    try!(generate_enums(w, &prepare(ns)));
    try!(generate_constants(w, env, &ns.constants));
    try!(generate_bitfields(w, &prepare(ns)));
    try!(generate_unions(w, &prepare(ns)));
    try!(functions::generate_callbacks(w, env, &prepare(ns)));
    try!(generate_records(w, env, &records));
    try!(generate_classes_structs(w, &classes));
    try!(generate_interfaces_structs(w, &interfaces));

    try!(writeln!(w, ""));
    try!(writeln!(w, "extern \"C\" {{"));
    try!(functions::generate_records_funcs(w, env, &records));
    try!(functions::generate_classes_funcs(w, env, &classes));
    try!(functions::generate_interfaces_funcs(w, env, &interfaces));
    try!(functions::generate_other_funcs(w, env, &ns.functions));

    try!(writeln!(w, "\n}}"));

    Ok(())
}

fn generate_extern_crates(w: &mut Write, env: &Env) -> Result<()>{
    for library_name in &env.config.external_libraries {
        try!(writeln!(w, "extern crate {0}_sys as {0};", crate_name(library_name)));
    }

    Ok(())
}

fn prepare<T: Ord>(ns: &Namespace) -> Vec<&T>
where Type: MaybeRef<T> {
    let mut vec: Vec<&T> = Vec::with_capacity(ns.types.len());
    for typ in ns.types.iter().filter_map(|t| t.as_ref()) {
        if let Some(ref x) = typ.maybe_ref() {
            vec.push(x);
        }
    }
    vec.sort();
    vec
}

fn generate_aliases(w: &mut Write, env: &Env, items: &[&Alias])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        let (comment, c_type) = match ffi_type(env, item.typ, &item.target_c_type) {
            Ok(x) => ("", x),
            Err(x) => ("//", x),
        };
        try!(writeln!(w, "{}pub type {} = {};", comment, item.c_identifier, c_type));
    }

    Ok(())
}

fn generate_bitfields(w: &mut Write, items: &[&Bitfield])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        try!(writeln!(w, "bitflags! {{\n\t#[repr(C)]\n\tflags {}: c_uint {{", item.c_type));
        for member in &item.members {
            let val: i64 = member.value.parse().unwrap();
            try!(writeln!(w, "\t\tconst {} = {},", member.c_identifier, val as u32));
        }
        try!(writeln!(w, "\t}}\n}}"));
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_constants(w: &mut Write, env: &Env, constants: &[Constant]) -> Result<()> {
    try!(writeln!(w, ""));
    for constant in constants {
        let (mut comment, mut type_) =
            match parameter_rust_type(env, constant.typ, ParameterDirection::In, Nullable(false)) {
                Ok(x) => ("", x),
                Err(x) => ("//", x),
            };
        if env.type_status_sys(&format!("{}.{}", env.config.library_name,
            constant.name)).ignored() {
            comment = "//";
        }
        let mut value = constant.value.clone();
        if type_ == "&str" {
            type_ = "&'static str".into();
            value = format!("r##\"{}\"##", value);
        } else if type_ == "Glyph" && env.config.library_name == "Pango"  {
            //Fix single constant alias
            type_ = "PangoGlyph".into();
        }
        try!(writeln!(w, "{}pub const {}: {} = {};", comment,
            constant.c_identifier, type_, value));
    }

    Ok(())
}

fn generate_enums(w: &mut Write, items: &[&Enumeration])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if item.members.len() == 1 {
            try!(writeln!(w, "pub type {} = c_int;", item.name));
            try!(writeln!(w, "pub const {}: {} = {};",
                          item.members[0].c_identifier, item.name, item.members[0].value));
            try!(writeln!(w, "pub type {} = {};", item.c_type, item.name));
            try!(writeln!(w, ""));
            continue;
        }

        let mut vals = HashMap::new();
        try!(writeln!(w, "#[derive(Clone, Copy, Debug, Eq, PartialEq)]\n#[repr(C)]"));
        try!(writeln!(w, "pub enum {} {{", item.c_type));
        for member in &item.members {
            if vals.get(&member.value).is_some() {
                continue;
            }
            try!(writeln!(w, "\t{} = {},",
                          &prepare_enum_member_name(&member.name), member.value));
            vals.insert(member.value.clone(), member.name.clone());
        }
        try!(writeln!(w, "}}"));
        for member in &item.members {
            try!(writeln!(w, "pub const {}: {} = {1}::{};", member.c_identifier, item.c_type,
                          &prepare_enum_member_name(vals.get(&member.value).unwrap())));
        }
        try!(writeln!(w, ""));
    }

    Ok(())
}

fn generate_unions(w: &mut Write, items: &[&Union])
        -> Result<()> {
    try!(writeln!(w, ""));
    for item in items {
        if let Some(ref c_type) = item.c_type {
            try!(writeln!(w, "pub type {} = c_void; // union", c_type));
        }
    }
    try!(writeln!(w, ""));

    Ok(())
}

fn prepare_enum_member_name(name: &str) -> String {
    let cameled = name.to_camel();
    if name.chars().next().unwrap().is_digit(10) {
        format!("_{}", cameled)
    } else {
        cameled
    }
}

fn generate_classes_structs(w: &mut Write, classes: &[&Class]) -> Result<()> {
    try!(writeln!(w, ""));
    for klass in classes {
        try!(writeln!(w, "#[repr(C)]\npub struct {}(c_void);", klass.c_type));
    }

    Ok(())
}

fn generate_interfaces_structs(w: &mut Write, interfaces: &[&Interface]) -> Result<()> {
    try!(writeln!(w, ""));
    for interface in interfaces {
        try!(writeln!(w, "#[repr(C)]\npub struct {}(c_void);", interface.c_type));
    }

    Ok(())
}

fn generate_records(w: &mut Write, env: &Env, records: &[&Record]) -> Result<()> {
    try!(writeln!(w, ""));
    for record in records {
        let mut lines = Vec::new();
        let mut commented = false;
        let mut truncated = false;
        for field in &record.fields {
            let is_union = env.library.type_(field.typ).maybe_ref_as::<Union>().is_some();
            let is_bits = field.bits.is_some();
            if !truncated && (is_union || is_bits) {
                warn!("Record `{}` field `{}` not expressible in Rust, truncated",
                      record.name, field.name);
                lines.push(format!("\t_truncated_record_marker: c_void,"));
                truncated = true;
            }
            if truncated {
                if is_union {
                    lines.push(format!("\t//union,"));
                }
                else {
                    let bits = field.bits.map(|n| format!(": {}", n)).unwrap_or("".into());
                    lines.push(
                        format!("\t//{}: {}{},", field.name,
                                field.c_type.as_ref().map(|s| &s[..]).unwrap_or("fn"), bits));
                };
                continue;
            }

            let vis = if field.private { "" } else { "pub " };

            if let Some(ref c_type) = field.c_type {
                let name = mangle_keywords(&*field.name);
                let c_type = ffi_type(env, field.typ, c_type);
                lines.push(format!("\t{}{}: {},", vis, name, c_type.as_str()));
                if c_type.is_err() {
                    commented = true;
                }
            }
            else {
                let name = mangle_keywords(&*field.name);
                if let Some(ref func) =
                        env.library.type_(field.typ).maybe_ref_as::<Function>() {
                    let (com, sig) = functions::function_signature(env, func, true);
                    lines.push(format!("\t{}{}: Option<unsafe extern \"C\" fn{}>,", vis, name, sig));
                    commented |= com;
                }
                else if let Some(c_type) = env.library.type_(field.typ).get_glib_name() {
                    warn!("Record `{}`, field `{}` missing c:type assumed `{}`",
                          record.name, field.name, c_type);
                    let c_type = ffi_type(env, field.typ, c_type);
                    lines.push(format!("\t{}{}: {},", vis, name, c_type.as_str()));
                    if c_type.is_err() {
                        commented = true;
                    }
                }
                else {
                    lines.push(format!("\t{}{}: [{:?} {}],",
                        vis, name, field.typ, field.typ.full_name(&env.library)));
                    commented = true;
                }
            }
        }
        let comment = if commented { "//" } else { "" };
        if lines.is_empty() {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {}(c_void);\n", comment, record.c_type));
        }
        else {
            try!(writeln!(w, "{}#[repr(C)]\n{0}pub struct {} {{", comment, record.c_type));
            for line in lines {
                try!(writeln!(w, "{}{}", comment, line));
            }
            try!(writeln!(w, "{}}}\n", comment));
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor};
use types::{Cursor, XCursor};
use std::ptr;
use utils::safe_as_cstring;
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManager<'manager> {
    manager: *mut wlr_xcursor_manager,
    phantom: PhantomData<XCursor<'manager>>
}

impl<'manager> XCursorManager<'manager> {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager, phantom: PhantomData })
            }
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<T: Into<Option<String>>>(&self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::new(xcursor))
            }
        }
    }

    /// returns 0 if the scaled theme was successfully loaded and 1 otherwise
    pub fn load(&self, scale: f32) -> i32 {
        unsafe {
            wlr_xcursor_manager_load(self.manager, scale)
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_ptr = safe_as_cstring(name).as_ptr();
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_ptr, cursor.as_ptr());
        }
    }
}

impl<'manager> Drop for XCursorManager<'manager> {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<commit_msg>add lifetime manager to self in get_xcurosr<commit_after>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load,
                  wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy,
                  wlr_xcursor_manager_get_xcursor};
use types::{Cursor, XCursor};
use std::ptr;
use utils::safe_as_cstring;
use std::marker::PhantomData;

#[derive(Debug)]
pub struct XCursorManager<'manager> {
    manager: *mut wlr_xcursor_manager,
    phantom: PhantomData<XCursor<'manager>>
}

impl<'manager> XCursorManager<'manager> {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager: manager, phantom: PhantomData })
            }
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    pub fn get_xcursor<T: Into<Option<String>>>(&'manager self, name: T, scale: f32) -> Option<XCursor<'manager>> {
        let name_str = name.into().map(safe_as_cstring);
        let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
        unsafe {
            let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale);
            if xcursor.is_null() {
                None
            } else {
                Some(XCursor::new(xcursor))
            }
        }
    }

    /// returns 0 if the scaled theme was successfully loaded and 1 otherwise
    pub fn load(&self, scale: f32) -> i32 {
        unsafe {
            wlr_xcursor_manager_load(self.manager, scale)
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_ptr = safe_as_cstring(name).as_ptr();
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_ptr, cursor.as_ptr());
        }
    }
}

impl<'manager> Drop for XCursorManager<'manager> {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<|endoftext|>


<commit_before>use bitboard::Board;
use bitboard::Move;

use transposition::TranspositionTable;

use heuristic::Heuristic;

use std::time::Instant;
use rand::Rng;
use rand::ThreadRng;
use rand;

pub trait Search<H : Heuristic> {
    fn search(&mut self, board : Board, ms_left : u64, start : Instant) -> Move;

    fn set_heuristic(&mut self, hr : Box<H>);
}

pub struct SearchInfo {
    pub tt  : TranspositionTable,
    pub to  : bool,
    pub st  : Instant,
    pub sr  : u64,
    pub rn  : ThreadRng,
}

impl SearchInfo {
    pub fn new() -> SearchInfo {
        SearchInfo {
            tt: TranspositionTable::new(20_000_000),
            to: false,
            st: Instant::now(),
            sr: 0,
            rn: rand::thread_rng(),
        }
    }

    pub fn set_start(&mut self) {
        self.st = Instant::now();
    }

    #[inline]
    pub fn check_timeout(&mut self, msleft : u64) {
        use std::time::Duration;
        self.to = self.st.elapsed() >= Duration::from_millis(msleft);
    }
}<commit_msg>history information added to SearchInfo<commit_after>use bitboard::Board;
use bitboard::Move;

use transposition::TranspositionTable;

use heuristic::Heuristic;

use std::time::Instant;
use rand::Rng;
use rand::ThreadRng;
use rand;

pub trait Search<H : Heuristic> {
    fn search(&mut self, board : Board, ms_left : u64, start : Instant) -> Move;

    fn set_heuristic(&mut self, hr : Box<H>);
}

pub struct SearchInfo {
    pub tt  : TranspositionTable,
    pub to  : bool,
    pub st  : Instant,
    pub sr  : u64,
    pub rn  : ThreadRng,
    pub hs  : [[i32; 64];2],
}

impl SearchInfo {
    pub fn new() -> SearchInfo {
        SearchInfo {
            tt: TranspositionTable::new(20_000_000),
            to: false,
            st: Instant::now(),
            sr: 0,
            rn: rand::thread_rng(),
            hs: [[
                32,  -16, 8,  4,  4, 8, -16, 32,
                -16, -16, 2, -2, -2, 2, -16, -16,
                8,     2, 0,  0,  0, 0,   2, 8,
                4,    -2, 0,  0,  0, 0,  -2, 4,
                4,    -2, 0,  0,  0, 0,  -2, 4,
                8,     2, 0,  0,  0, 0,   2, 8,
                -16, -16, 2, -2, -2, 2, -16, -16,
                32,  -16, 8,  4,  4, 8, -16, 32,
            ];2],
        }
    }

    pub fn set_start(&mut self) {
        self.st = Instant::now();
    }

    #[inline]
    pub fn check_timeout(&mut self, msleft : u64) {
        use std::time::Duration;
        self.to = self.st.elapsed() >= Duration::from_millis(msleft);
    }

    pub fn reset_history(&mut self) {
        self.hs = [[
            32,  -16, 8,  4,  4, 8, -16, 32,
            -16, -16, 2, -2, -2, 2, -16, -16,
            8,     2, 0,  0,  0, 0,   2, 8,
            4,    -2, 0,  0,  0, 0,  -2, 4,
            4,    -2, 0,  0,  0, 0,  -2, 4,
            8,     2, 0,  0,  0, 0,   2, 8,
            -16, -16, 2, -2, -2, 2, -16, -16,
            32,  -16, 8,  4,  4, 8, -16, 32,
        ];2];
    }
}<|endoftext|>


<commit_before>// Copyright (C) 2018, Cloudflare, Inc.
// Copyright (C) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use ring::rand::*;

const LOCAL_CONN_ID_LEN: usize = 16;

const HTTP_REQ_STREAM_ID: u64 = 4;

const USAGE: &str = "Usage: client [options] URL

Options:
  -h --help               Show this screen.
  --wire-version VERSION  The version number to send to the server [default: babababa].
  --no-verify             Don't verify server's certificate.
";

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; 1400];

    env_logger::init();

    let args = docopt::Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let url = url::Url::parse(args.get_str("URL")).unwrap();

    let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap();
    socket.connect(&url).unwrap();

    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(&socket, mio::Token(0),
                  mio::Ready::readable(),
                  mio::PollOpt::edge()).unwrap();

    let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
    SystemRandom::new().fill(&mut scid[..]).unwrap();

    let version = args.get_str("--wire-version");
    let version = u32::from_str_radix(version, 16).unwrap();

    let mut config = quiche::Config::new(version).unwrap();

    config.verify_peer(true);

    config.set_idle_timeout(30);
    config.set_max_packet_size(1460);
    config.set_initial_max_data(10_000_000);
    config.set_initial_max_stream_data_bidi_local(1_000_000);
    config.set_initial_max_stream_data_bidi_remote(1_000_000);
    config.set_initial_max_streams_bidi(100);
    config.set_disable_migration(true);

    if args.get_bool("--no-verify") {
        config.verify_peer(false);
    }

    if std::env::var_os("SSLKEYLOGFILE").is_some() {
        config.log_keys();
    }

    let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();

    let write = match conn.send(&mut out) {
        Ok(v) => v,

        Err(e) => panic!("{} initial send failed: {:?}", conn.trace_id(), e),
    };

    socket.send(&out[..write]).unwrap();

    debug!("{} written {}", conn.trace_id(), write);

    let mut req_sent = false;

    loop {
        poll.poll(&mut events, conn.timeout()).unwrap();

        'read: loop {
            if events.is_empty() {
                debug!("timed out");

                conn.on_timeout();

                break 'read;
            }

            let len = match socket.recv(&mut buf) {
                Ok(v) => v,

                Err(e) => {
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            debug!("{} got {} bytes", conn.trace_id(), len);

            // Process potentially coalesced packets.
            let read = match conn.recv(&mut buf[..len]) {
                Ok(v)  => v,

                Err(quiche::Error::Done) => {
                    debug!("{} done reading", conn.trace_id());
                    break;
                },

                Err(e) => {
                    error!("{} recv failed: {:?}", conn.trace_id(), e);
                    conn.close(false, e.to_wire(), b"fail").unwrap();
                    break 'read;
                },
            };

            debug!("{} processed {} bytes", conn.trace_id(), read);
        }

        if conn.is_closed() {
            debug!("{} connection closed", conn.trace_id());
            break;
        }

        if conn.is_established() && !req_sent {
            info!("{} sending HTTP request for {}", conn.trace_id(), url.path());

            let req = format!("GET {}\r\n", url.path());
            conn.stream_send(HTTP_REQ_STREAM_ID, req.as_bytes(), true).unwrap();

            req_sent = true;
        }

        let streams: Vec<u64> = conn.readable().collect();
        for s in streams {
            let data = conn.stream_recv(s, std::usize::MAX).unwrap();

            info!("{} stream {} has {} bytes (fin? {})",
                  conn.trace_id(), s, data.len(), data.fin());

            print!("{}", unsafe { std::str::from_utf8_unchecked(&data) });

            if s == HTTP_REQ_STREAM_ID && data.fin() {
                conn.close(true, 0x00, b"kthxbye").unwrap();
            }
        }

        loop {
            let write = match conn.send(&mut out) {
                Ok(v) => v,

                Err(quiche::Error::Done) => {
                    debug!("{} done writing", conn.trace_id());
                    break;
                },

                Err(e) => {
                    error!("{} send failed: {:?}", conn.trace_id(), e);
                    conn.close(false, e.to_wire(), b"fail").unwrap();
                    break;
                },
            };

            // TODO: coalesce packets.
            socket.send(&out[..write]).unwrap();

            debug!("{} written {}", conn.trace_id(), write);
        }

        if conn.is_closed() {
            debug!("{} connection closed", conn.trace_id());
            break;
        }
    }
}
<commit_msg>client: add option to make an HTTP/1.1 request instead of HTTP/0.9<commit_after>// Copyright (C) 2018, Cloudflare, Inc.
// Copyright (C) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use ring::rand::*;

const LOCAL_CONN_ID_LEN: usize = 16;

const HTTP_REQ_STREAM_ID: u64 = 4;

const USAGE: &str = "Usage: client [options] URL

Options:
  -h --help               Show this screen.
  --http1                 Send HTTP/1.1 request instead of HTTP/0.9.
  --wire-version VERSION  The version number to send to the server [default: babababa].
  --no-verify             Don't verify server's certificate.
";

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; 1400];

    env_logger::init();

    let args = docopt::Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let url = url::Url::parse(args.get_str("URL")).unwrap();

    let socket = std::net::UdpSocket::bind("0.0.0.0:0").unwrap();
    socket.connect(&url).unwrap();

    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(&socket, mio::Token(0),
                  mio::Ready::readable(),
                  mio::PollOpt::edge()).unwrap();

    let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
    SystemRandom::new().fill(&mut scid[..]).unwrap();

    let version = args.get_str("--wire-version");
    let version = u32::from_str_radix(version, 16).unwrap();

    let mut config = quiche::Config::new(version).unwrap();

    config.verify_peer(true);

    config.set_idle_timeout(30);
    config.set_max_packet_size(1460);
    config.set_initial_max_data(10_000_000);
    config.set_initial_max_stream_data_bidi_local(1_000_000);
    config.set_initial_max_stream_data_bidi_remote(1_000_000);
    config.set_initial_max_streams_bidi(100);
    config.set_disable_migration(true);

    if args.get_bool("--no-verify") {
        config.verify_peer(false);
    }

    if std::env::var_os("SSLKEYLOGFILE").is_some() {
        config.log_keys();
    }

    let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();

    let write = match conn.send(&mut out) {
        Ok(v) => v,

        Err(e) => panic!("{} initial send failed: {:?}", conn.trace_id(), e),
    };

    socket.send(&out[..write]).unwrap();

    debug!("{} written {}", conn.trace_id(), write);

    let mut req_sent = false;

    loop {
        poll.poll(&mut events, conn.timeout()).unwrap();

        'read: loop {
            if events.is_empty() {
                debug!("timed out");

                conn.on_timeout();

                break 'read;
            }

            let len = match socket.recv(&mut buf) {
                Ok(v) => v,

                Err(e) => {
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            debug!("{} got {} bytes", conn.trace_id(), len);

            // Process potentially coalesced packets.
            let read = match conn.recv(&mut buf[..len]) {
                Ok(v)  => v,

                Err(quiche::Error::Done) => {
                    debug!("{} done reading", conn.trace_id());
                    break;
                },

                Err(e) => {
                    error!("{} recv failed: {:?}", conn.trace_id(), e);
                    conn.close(false, e.to_wire(), b"fail").unwrap();
                    break 'read;
                },
            };

            debug!("{} processed {} bytes", conn.trace_id(), read);
        }

        if conn.is_closed() {
            debug!("{} connection closed", conn.trace_id());
            break;
        }

        if conn.is_established() && !req_sent {
            info!("{} sending HTTP request for {}", conn.trace_id(), url.path());

            let req = if args.get_bool("--http1") {
                format!("GET {} HTTP/1.1\r\nHost: {}\r\nUser-Agent: quiche\r\n\r\n",
                    url.path(), url.host().unwrap())
            } else {
                format!("GET {}\r\n", url.path())
            };

            conn.stream_send(HTTP_REQ_STREAM_ID, req.as_bytes(), true).unwrap();

            req_sent = true;
        }

        let streams: Vec<u64> = conn.readable().collect();
        for s in streams {
            let data = conn.stream_recv(s, std::usize::MAX).unwrap();

            info!("{} stream {} has {} bytes (fin? {})",
                  conn.trace_id(), s, data.len(), data.fin());

            print!("{}", unsafe { std::str::from_utf8_unchecked(&data) });

            if s == HTTP_REQ_STREAM_ID && data.fin() {
                conn.close(true, 0x00, b"kthxbye").unwrap();
            }
        }

        loop {
            let write = match conn.send(&mut out) {
                Ok(v) => v,

                Err(quiche::Error::Done) => {
                    debug!("{} done writing", conn.trace_id());
                    break;
                },

                Err(e) => {
                    error!("{} send failed: {:?}", conn.trace_id(), e);
                    conn.close(false, e.to_wire(), b"fail").unwrap();
                    break;
                },
            };

            // TODO: coalesce packets.
            socket.send(&out[..write]).unwrap();

            debug!("{} written {}", conn.trace_id(), write);
        }

        if conn.is_closed() {
            debug!("{} connection closed", conn.trace_id());
            break;
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "client"]

extern crate debug;
extern crate http;
use http::client::RequestWriter;
use http::method::Get;
use http::headers::HeaderEnum;
use std::os;
use std::str;
use std::io::println;

fn main() {
    format!("{}", Get);
    let args = os::args();
    match args.len() {
        0 => unreachable!(),
        2 => make_and_print_request(args[1].as_slice()),
        _ => {
            println!("Usage: {} URL", args[0]);
            return;
        },
    };
}

fn make_and_print_request(url: &str) {
    let request: RequestWriter = RequestWriter::new(Get, from_str(url).expect("Invalid URL :-("))
                                              .unwrap();

    println!("Request");
    println!("=======");
    println!("");
    println!("URL: {}", request.url);
    println!("Remote address: {}", request.remote_addr);
    println!("Method: {}", request.method);
    println!("Headers:");
    for header in request.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }

    println!("");
    println!("Response");
    println!("========");
    println!("");
    let mut response = match request.read_response() {
        Ok(response) => response,
        Err(_request) => fail!("This example can progress no further with no response :-("),
    };
    println!("Status: {}", response.status);
    println!("Headers:");
    for header in response.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }
    println!("Body:");
    let body = match response.read_to_end() {
        Ok(body) => body,
        Err(err) => fail!("Reading response failed: {}", err),
    };
    println(str::from_utf8(body.as_slice()).expect("Uh oh, response wasn't UTF-8"));
}
<commit_msg>Upgrade examples/client.rs to rust-url<commit_after>#![crate_name = "client"]

extern crate debug;
extern crate http;
extern crate url;
use http::client::RequestWriter;
use http::method::Get;
use http::headers::HeaderEnum;
use std::os;
use std::str;
use std::io::println;
use url::Url;

fn main() {
    format!("{}", Get);
    let args = os::args();
    match args.len() {
        0 => unreachable!(),
        2 => make_and_print_request(args[1].as_slice()),
        _ => {
            println!("Usage: {} URL", args[0]);
            return;
        },
    };
}

fn make_and_print_request(url: &str) {
    let url = Url::parse(url).ok().expect("Invalid URL :-(");
    let request: RequestWriter = RequestWriter::new(Get, url).unwrap();

    println!("Request");
    println!("=======");
    println!("");
    println!("URL: {}", request.url);
    println!("Remote address: {}", request.remote_addr);
    println!("Method: {}", request.method);
    println!("Headers:");
    for header in request.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }

    println!("");
    println!("Response");
    println!("========");
    println!("");
    let mut response = match request.read_response() {
        Ok(response) => response,
        Err(_request) => fail!("This example can progress no further with no response :-("),
    };
    println!("Status: {}", response.status);
    println!("Headers:");
    for header in response.headers.iter() {
        println!(" - {}: {}", header.header_name(), header.header_value());
    }
    println!("Body:");
    let body = match response.read_to_end() {
        Ok(body) => body,
        Err(err) => fail!("Reading response failed: {}", err),
    };
    println(str::from_utf8(body.as_slice()).expect("Uh oh, response wasn't UTF-8"));
}
<|endoftext|>


<commit_before>//
/*

*/
#![feature(inclusive_range_syntax)]
#![feature(type_ascription)]
#![feature(more_struct_aliases)]

extern crate modbus_server;
extern crate futures;
extern crate tokio_proto;
extern crate tokio_service;
extern crate tokio_core;

extern crate docopt;
extern crate rustc_serialize;

use std::str;
use futures::{future, Stream,Sink};
use std::thread;
use futures::sync::mpsc::unbounded;
use futures::sync::mpsc::{UnboundedSender};
use std::sync::mpsc::channel;
use docopt::Docopt;
use std::io::{self};
use tokio_proto::TcpServer;
use tokio_service::Service;
use tokio_core::reactor::Core;

use modbus_server::{ModbusTCPProto,ModbusTCPResponse,ModbusTCPRequest};
use modbus_server::{ModbusRequestPDU,ModbusResponsePDU};

const USAGE: &'static str = "
Usage: slave [options] <resources> ...

Options:
    --addr=<addr>  # Base URL  [default: 127.0.0.1:502].
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_resource: Vec<String>,
    flag_addr: String
}

// TODO: add ModbusRTUCodec

use modbus_server::BlankRegisters;

pub struct ModbusService {
    in_: UnboundedSender<(ModbusRequestPDU,
                          std::sync::mpsc::Sender<ModbusResponsePDU>)>
}

impl ModbusService {
    fn new (
        in_:UnboundedSender<(ModbusRequestPDU,
                             std::sync::mpsc::Sender<ModbusResponsePDU>)>
        )->ModbusService {
        ModbusService{ in_:in_}
    }

}

impl Service for ModbusService {

    type Request = ModbusTCPRequest;
    type Response = ModbusTCPResponse;
    type Error = io::Error;
    type Future = future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        let (resp_in,out)=channel ::<ModbusResponsePDU>();
        let tmp = self.in_.clone();
        tmp.send((req.pdu.clone(), resp_in));
        let pdu = out.recv().unwrap();
        future::finished(ModbusTCPResponse {
            header:req.header,
            pdu:pdu
        })
    }
}

fn main() {

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| {println!("DAMN {:?}",e); e.exit()});
    println!("{:?}", args);
    let (in_,req_out)= unbounded::<(ModbusRequestPDU,std::sync::mpsc::Sender<ModbusResponsePDU>)>();
    thread::spawn(move ||{

        let mut block = BlankRegisters::new();
        let mut core = Core::new().unwrap();
        core.run(req_out.map(
            |(req, tx)|{
                tx.send(block.call(req))
            }).for_each(|e| Ok(()))).unwrap();
    });

    TcpServer::new(ModbusTCPProto, args.flag_addr.parse().unwrap())
        .serve(move || Ok(ModbusService::new(in_.clone())));
}

<commit_msg>Fully working version. Sender is polled() to poke into working.<commit_after>//
/*

*/
#![feature(inclusive_range_syntax)]
#![feature(type_ascription)]
#![feature(more_struct_aliases)]

extern crate modbus_server;
extern crate futures;
extern crate tokio_proto;
extern crate tokio_service;
extern crate tokio_core;

extern crate docopt;
extern crate rustc_serialize;
use futures::Future;
use std::str;
use futures::{future, Stream,Sink};
use std::thread;
use futures::sync::mpsc;
use futures::sync::oneshot;

use docopt::Docopt;
use std::io::{self};
use tokio_proto::TcpServer;
use tokio_service::Service;
use tokio_core::reactor::Core;

use modbus_server::{ModbusTCPProto,ModbusTCPResponse,ModbusTCPRequest};
use modbus_server::{ModbusRequestPDU,ModbusResponsePDU};

const USAGE: &'static str = "
Usage: slave [options] <resources> ...

Options:
    --addr=<addr>  # Base URL  [default: 127.0.0.1:502].
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_resource: Vec<String>,
    flag_addr: String
}

// TODO: add ModbusRTUCodec

use modbus_server::BlankRegisters;

pub struct ModbusService {
    in_: mpsc::Sender<(ModbusRequestPDU,
                       oneshot::Sender<ModbusResponsePDU>)>
}

impl ModbusService {
    fn new (
        in_:mpsc::Sender<(ModbusRequestPDU,
                          oneshot::Sender<ModbusResponsePDU>)>
        )->ModbusService {
        ModbusService{ in_:in_}
    }

}

impl Service for ModbusService {

    type Request = ModbusTCPRequest;
    type Response = ModbusTCPResponse;
    type Error = io::Error;
    type Future = future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {

        let (resp_in,out)=oneshot ::channel::<ModbusResponsePDU>();
        let tmp = self.in_.clone();
        tmp.send((req.pdu.clone(), resp_in)).poll();

        let rx = out.map(|pdu|{

            ModbusTCPResponse {
                header:req.header.clone(),
                pdu:pdu
            }
        });

        let w = rx.wait().unwrap();
        future::finished(w)
    }
}

fn main() {

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| {println!("DAMN {:?}",e); e.exit()});
    println!("{:?}", args);
    let (in_,req_out)= mpsc::channel::<(ModbusRequestPDU,oneshot::Sender<ModbusResponsePDU>)>(1);
    thread::spawn(move ||{

        let mut block = BlankRegisters::new();
        let mut core = Core::new().unwrap();
        core.run(req_out.map(
            |(req, tx)|{
                println!("Sending {:?}",req);
                tx.complete(block.call(req))
            }).for_each(|e| Ok(()))).unwrap();
    });

    TcpServer::new(ModbusTCPProto, args.flag_addr.parse().unwrap())
        .serve(move || Ok(ModbusService::new(in_.clone())));
}

<|endoftext|>


<commit_before>extern crate deeplearn;
extern crate gpuarray as ga;

use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{
    self,
    BufReader,
    Read,
};
use std::path::Path;
use std::rc::Rc;

use deeplearn::{init, layers, util, Graph, Trainer};
use deeplearn::op::Relu;
use ga::Array;

fn main() {
    let batch_size = 1;

    let (char_map, lines) = load_char_rnn_data("data/bible.txt").unwrap();
    println!("Loaded char rnn data");

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Build the graph

    let ctx = Rc::new(ga::Context::new());
    let ref mut graph = Graph::new(ctx.clone());

    // Input. 1 batch of rows*columns inputs
    let input = graph.add_variable(vec![batch_size, 26], false, 0.0);

    // Layer 1
    // Biased fully connected layer with 300 neurons and ReLU activation
    let (l1_fcb, _, _) = layers::dense_biased(graph, input, 300,
                                              init::Normal(0.001, 0.005),  // Weights initializer
                                              init::Normal(0.001, 0.005)); // Bias initializer
    let l1_out = layers::activation(graph, Relu(l1_fcb));

    // Layer 2
    // LSTM layer with 100 cells
    let (l2_out, _) = layers::lstm(graph, l1_out, 100, init::Normal(0.001, 0.005));

    // Layer 3
    // Biased fully connected layer with 26 neurons and ReLU activation
    let (l3_fcb, _, _) = layers::dense_biased(graph, l2_out, 26,
                                              init::Normal(0.001, 0.005),  // Weights initializer
                                              init::Normal(0.001, 0.005)); // Bias initializer
    let l3_out = layers::activation(graph, Relu(l3_fcb));

    // Loss
    let (loss_out, train_out) = layers::mse(graph, l2_out);
    let loss_d = graph.add_gradient(loss_out); // Create a gradient to apply to the loss function

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Train and validate the network

    // TODO
}

pub fn load_char_rnn_data<P: AsRef<Path>>(path: P)
    -> io::Result<(HashMap<u8, Array<f32>>, Vec<Vec<u8>>)>
{
    use std::io::BufRead;

    let ref mut file = BufReader::new(File::open(path).unwrap());

    let mut unique_chars = HashSet::new();
    let mut lines = vec![];

    for line in file.lines() {
        let line: String = try!(line);
        for c in line.as_bytes() {
            unique_chars.insert(*c);
        }
        lines.push(line.as_bytes().to_owned());
    }

    let char_classes = unique_chars.len();
    let mut char_map = HashMap::new();
    for (i, c) in unique_chars.into_iter().enumerate() {
        char_map.insert(c, util::one_hot_row(i, char_classes));
    }

    Ok((char_map, lines))
}
<commit_msg>Training and validating in char_rnn example<commit_after>extern crate deeplearn;
extern crate gpuarray as ga;

use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{
    self,
    BufReader,
    Write,
};
use std::path::Path;
use std::rc::Rc;

use deeplearn::{init, layers, util, Graph};
use deeplearn::op::Relu;
use ga::Array;

fn main() {
    let batch_size = 1;

    let (char_map, rev_char_map, lines) = load_char_rnn_data("data/bible.txt").unwrap();
    let char_classes = char_map.len();
    println!("Loaded char rnn data");
    println!("Character types: {}", char_classes);

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Build the graph

    let ctx = Rc::new(ga::Context::new());
    let ref mut graph = Graph::new(ctx.clone());

    // Input. 1 batch of rows*columns inputs
    let input = graph.add_variable(vec![batch_size, char_classes], false, 0.0);

    // Layer 1
    // LSTM layer with 200 cells
    let (l1_out, _) = layers::lstm(graph, input, 200, init::Normal(0.001, 0.005));

    // Layer 2
    // LSTM layer with 200 cells
    let (l2_out, _) = layers::lstm(graph, l1_out, 200, init::Normal(0.001, 0.005));

    // Layer 3
    // Biased fully connected layer with 26 neurons and ReLU activation
    let (l3_fcb, _, _) = layers::dense_biased(graph, l2_out, char_classes,
                                              init::Normal(0.001, 0.005),  // Weights initializer
                                              init::Normal(0.001, 0.005)); // Bias initializer
    let l3_out = layers::activation(graph, Relu(l3_fcb));

    // Loss
    let (loss_out, train_out) = layers::mse(graph, l3_out);
    let loss_d = graph.add_gradient(loss_out); // Create a gradient to apply to the loss function

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Train and validate the network

    // We apply a gradient of -0.001 to the loss function
    let loss_d_cpu = Array::new(vec![batch_size, char_classes], -0.001);
    loss_d.write(graph, &loss_d_cpu);

    for line in &lines {
        for t in 1..line.len() {
            input.write(graph, &char_map[&line[t-1]]);
            train_out.write(graph, &char_map[&line[t]]);
            graph.forward();
        }
        for t in (1..line.len()).rev() {
            graph.backward();
        }
    }

    let mut l3_out_cpu = Array::new(vec![batch_size, char_classes], 0.0);
    let mut argmax_out = Array::new(vec![batch_size], 0usize);

    loop {
        // Print prompt
        print!(">");
        io::stdout().flush().unwrap();

        // Get seed string
        let mut seed = String::new();
        io::stdin().read_line(&mut seed).unwrap();

        // Input the seed string
        let mut last_char = 0u8;
        for c in seed.trim_right().as_bytes() {
            print!("{}", *c as char);
            input.write(graph, &char_map[c]);
            graph.forward();
            l3_out.read(graph, &mut l3_out_cpu);
            util::argmax_rows(&l3_out_cpu, &mut argmax_out);
            last_char = rev_char_map[&argmax_out[&[0]]];
        }

        // Generate the rest of the output
        for _ in 0..150 {
            print!("{}", last_char as char);
            io::stdout().flush().unwrap();

            input.write(graph, &char_map[&last_char]);
            graph.forward();
            l3_out.read(graph, &mut l3_out_cpu);
            //println!("{:?}", l3_out_cpu);
            util::argmax_rows(&l3_out_cpu, &mut argmax_out);
            last_char = rev_char_map[&argmax_out[&[0]]];

            if last_char == b'\n' {
                break;
            }
        }
        println!("");
    }
}

pub fn load_char_rnn_data<P: AsRef<Path>>(path: P)
    -> io::Result<(HashMap<u8, Array<f32>>, HashMap<usize, u8>, Vec<Vec<u8>>)>
{
    use std::io::BufRead;

    let ref mut file = BufReader::new(File::open(path).unwrap());

    let mut unique_chars = HashSet::new();
    let mut lines = vec![];

    for line in file.lines() {
        let line: String = try!(line) + "\n";
        for c in line.as_bytes() {
            unique_chars.insert(*c);
        }
        lines.push(line.as_bytes().to_owned());
    }

    let char_classes = unique_chars.len();
    let mut char_map = HashMap::new();
    let mut rev_char_map = HashMap::new();
    for (i, c) in unique_chars.into_iter().enumerate() {
        char_map.insert(c, util::one_hot_row(i, char_classes));
        rev_char_map.insert(i, c);
    }

    Ok((char_map, rev_char_map, lines))
}
<|endoftext|>


<commit_before>extern crate pancurses;
extern crate rand;

use pancurses::*;
use rand::Rng;

const DELAYSIZE: i32 = 200;

const COLOR_TABLE: [i16; 8] = [COLOR_RED,
                               COLOR_BLUE,
                               COLOR_GREEN,
                               COLOR_CYAN,
                               COLOR_RED,
                               COLOR_MAGENTA,
                               COLOR_YELLOW,
                               COLOR_WHITE];

fn main() {
    let window = init();
    window.set_nodelay(true);
    noecho();

    if has_colors() {
        start_color();
    }

    for (i, color) in COLOR_TABLE.into_iter().enumerate() {
        init_pair(i as i16, *color, COLOR_BLACK);
    }

    let mut rng = rand::thread_rng();

    let mut flag = 0;

    let lines = window.get_max_y();
    let cols = window.get_max_x();

    while window.getch() == ERR {
        let mut start = 0;
        let mut direction = 0;
        let mut diff = 0;

        while diff < 2 || diff >= lines - 2 {
            start = rng.gen::<i32>() % (cols - 3);
            let mut end = rng.gen::<i32>() % (cols - 3);
            start = if start < 2 { 2 } else { start };
            end = if end < 2 { 2 } else { end };
            direction = if start > end { -1 } else { 1 };
            diff = (start - end).abs();
        }

        attrset(A_NORMAL);

        for row in 0..diff {
            mvaddstr(lines -row, row * direction + start, if direction < 0 { "\\" } else { "/" });

            if flag != 0 {
                myrefresh(&window);
                erase();
                flag = 0;
            } else {
                flag += 1;
            }
        }
        let row = diff;

        if flag != 0 {
            myrefresh(&window);
            flag = 0;
        } else {
            flag += 1;
        }

        explode(lines - row, diff * direction + start, &window);
        erase();
        myrefresh(&window);
    }

    endwin();
}

fn explode(row: i32, mut col: i32, window: &Window) {
    erase();
    mvaddstr(row, col, "-");
    myrefresh(window);

    col -= 1;

    get_color();
    mvaddstr(row - 1, col, " - ");
    mvaddstr(row,     col, "-+-");
    mvaddstr(row + 1, col, " - ");
    myrefresh(window);

    col -= 1;

    get_color();
    mvaddstr(row - 2, col, " --- ");
    mvaddstr(row - 1, col, "-+++-");
    mvaddstr(row,     col, "-+#+-");
    mvaddstr(row + 1, col, "-+++-");
    mvaddstr(row + 2, col, " --- ");
    myrefresh(window);

    get_color();
    mvaddstr(row - 2, col, " +++ ");
    mvaddstr(row - 1, col, "++#++");
    mvaddstr(row,     col, "+# #+");
    mvaddstr(row + 1, col, "++#++");
    mvaddstr(row + 2, col, " +++ ");
    myrefresh(window);

    get_color();
    mvaddstr(row - 2, col, "  #  ");
    mvaddstr(row - 1, col, "## ##");
    mvaddstr(row,     col, "#   #");
    mvaddstr(row + 1, col, "## ##");
    mvaddstr(row + 2, col, "  #  ");
    myrefresh(window);

    get_color();
    mvaddstr(row - 2, col, " # # ");
    mvaddstr(row - 1, col, "#   #");
    mvaddstr(row,     col, "     ");
    mvaddstr(row + 1, col, "#   #");
    mvaddstr(row + 2, col, " # # ");
    myrefresh(window);
}

fn myrefresh(window: &Window) {
    napms(DELAYSIZE);
    mv(window.get_max_y() - 1, window.get_max_x() - 1);
    refresh();
}

fn get_color() {
    let mut rng = rand::thread_rng();
    let bold = if rng.gen::<bool>() { A_BOLD } else { A_NORMAL } as chtype;
    attrset(COLOR_PAIR(rng.gen::<chtype>() % 8) | bold);
}
<commit_msg>Pass the Rng to the get_color method instead of always using the thread local one<commit_after>extern crate pancurses;
extern crate rand;

use pancurses::*;
use rand::Rng;

const DELAYSIZE: i32 = 200;

const COLOR_TABLE: [i16; 8] = [COLOR_RED,
                               COLOR_BLUE,
                               COLOR_GREEN,
                               COLOR_CYAN,
                               COLOR_RED,
                               COLOR_MAGENTA,
                               COLOR_YELLOW,
                               COLOR_WHITE];

fn main() {
    let window = init();
    window.set_nodelay(true);
    noecho();

    if has_colors() {
        start_color();
    }

    for (i, color) in COLOR_TABLE.into_iter().enumerate() {
        init_pair(i as i16, *color, COLOR_BLACK);
    }

    let mut rng = rand::thread_rng();

    let mut flag = 0;

    let lines = window.get_max_y();
    let cols = window.get_max_x();

    while window.getch() == ERR {
        let mut start = 0;
        let mut direction = 0;
        let mut diff = 0;

        while diff < 2 || diff >= lines - 2 {
            start = rng.gen::<i32>() % (cols - 3);
            let mut end = rng.gen::<i32>() % (cols - 3);
            start = if start < 2 { 2 } else { start };
            end = if end < 2 { 2 } else { end };
            direction = if start > end { -1 } else { 1 };
            diff = (start - end).abs();
        }

        attrset(A_NORMAL);

        for row in 0..diff {
            mvaddstr(lines -row, row * direction + start, if direction < 0 { "\\" } else { "/" });

            if flag != 0 {
                myrefresh(&window);
                erase();
                flag = 0;
            } else {
                flag += 1;
            }
        }
        let row = diff;

        if flag != 0 {
            myrefresh(&window);
            flag = 0;
        } else {
            flag += 1;
        }

        explode(lines - row, diff * direction + start, &window, &mut rng);
        erase();
        myrefresh(&window);
    }

    endwin();
}

fn explode<T: Rng>(row: i32, mut col: i32, window: &Window, rng: &mut T) {
    erase();
    mvaddstr(row, col, "-");
    myrefresh(window);

    col -= 1;

    get_color(rng);
    mvaddstr(row - 1, col, " - ");
    mvaddstr(row,     col, "-+-");
    mvaddstr(row + 1, col, " - ");
    myrefresh(window);

    col -= 1;

    get_color(rng);
    mvaddstr(row - 2, col, " --- ");
    mvaddstr(row - 1, col, "-+++-");
    mvaddstr(row,     col, "-+#+-");
    mvaddstr(row + 1, col, "-+++-");
    mvaddstr(row + 2, col, " --- ");
    myrefresh(window);

    get_color(rng);
    mvaddstr(row - 2, col, " +++ ");
    mvaddstr(row - 1, col, "++#++");
    mvaddstr(row,     col, "+# #+");
    mvaddstr(row + 1, col, "++#++");
    mvaddstr(row + 2, col, " +++ ");
    myrefresh(window);

    get_color(rng);
    mvaddstr(row - 2, col, "  #  ");
    mvaddstr(row - 1, col, "## ##");
    mvaddstr(row,     col, "#   #");
    mvaddstr(row + 1, col, "## ##");
    mvaddstr(row + 2, col, "  #  ");
    myrefresh(window);

    get_color(rng);
    mvaddstr(row - 2, col, " # # ");
    mvaddstr(row - 1, col, "#   #");
    mvaddstr(row,     col, "     ");
    mvaddstr(row + 1, col, "#   #");
    mvaddstr(row + 2, col, " # # ");
    myrefresh(window);
}

fn myrefresh(window: &Window) {
    napms(DELAYSIZE);
    mv(window.get_max_y() - 1, window.get_max_x() - 1);
    refresh();
}

fn get_color<T: Rng>(rng: &mut T) {
    let bold = if rng.gen::<bool>() { A_BOLD } else { A_NORMAL } as chtype;
    attrset(COLOR_PAIR(rng.gen::<chtype>() % 8) | bold);
}
<|endoftext|>


<commit_before>
extern crate airspy;
use airspy::AirspySamplerate;

#[macro_use]
extern crate log;
extern crate fern;
extern crate time;

fn main() {
    // setup fern logger
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            format!("{}.{:3} [{}] {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }

    match airspy::Airspy::new() {
        Ok(mut device) => {
            info!("device opened sucessfully");
            device.set_samplerate(AirspySamplerate::Sps10000000).unwrap();
        }
        Err(e) => {
            error!("error {:?}", e);
        }
    }
}
<commit_msg>example airspyrx.rs now outputs IQ data to stdout<commit_after>
extern crate airspy;
use airspy::Airspy;
use airspy::AirspySamplerate;
use airspy::{IQ};

#[macro_use]
extern crate log;
extern crate fern;
extern crate time;

use std::io;
use std::io::Write;
use std::env;

fn main() {
    // setup fern logger
    let logger_config = fern::DispatchConfig {
        format: Box::new(|msg: &str, level: &log::LogLevel, _location: &log::LogLocation| {
            let t = time::now();
            let ms = t.tm_nsec/1000_000;
            format!("{}.{:3} [{}] {}", t.strftime("%Y-%m-%dT%H:%M:%S").unwrap(), ms, level, msg)
        }),
        output: vec![fern::OutputConfig::stderr()],
        level: log::LogLevelFilter::Trace,
    };

    if let Err(e) = fern::init_global_logger(logger_config, log::LogLevelFilter::Trace) {
        panic!("Failed to initialize global logger: {}", e);
    }

    // check args
    let mut args = env::args();
    let mut frequency_hz = 103_400_000;
    if args.len() == 1 {
        info!("use default frequency: {:.3} MHz", frequency_hz as f64/1000_000f64);
    }
    else {
        frequency_hz = (args.nth(1).unwrap().parse::<f32>().unwrap() as f64 * 1000_000f64) as u32;
        info!("frequency: {:.3} MHz", frequency_hz as f64/1000_000f64);
    }

    match Airspy::<IQ<i16>>::new() {
        Ok(mut device) => {
            info!("device opened sucessfully");
            device.set_samplerate(AirspySamplerate::Sps2500000).unwrap();

            device.set_vga_gain(6).unwrap();
            device.set_mixer_gain(5).unwrap();
            device.set_lna_gain(7).unwrap();

            device.set_frequency(frequency_hz).unwrap();
            device.start_rx().unwrap();

            let mut stdout = io::stdout();

            loop {
                // actually iterator blocks here
                for s in device.samples() {
                    let sliceu8 = Airspy::convert_samples_to_bytes(&s);

                    stdout.write(sliceu8).unwrap();
                    stdout.flush().unwrap();
                }

                info!("sleep");
            }
        }
        Err(e) => {
            error!("error {:?}", e);
        }
    }
}
<|endoftext|>