<commit_before>use std::collections::HashMap;

use hyper::client::Client;
use hyper::client::IntoUrl;

use url::Url;

use super::errors::*;
use super::msg;
use super::resp;
use super::net::Open189Client;

const URL_SMS_TOKEN: &'static str = "http://api.189.cn/v2/dm/randcode/token";
const URL_SMS_SEND_WITH_CODE: &'static str = "http://api.189.cn/v2/dm/randcode/sendSms";
const URL_SMS_SEND_WITH_CALLBACK: &'static str = "http://api.189.cn/v2/dm/randcode/send";

/// Client for the `open.189.cn` API.
pub struct Open189App {
    app_id: String,
    secret: String,
    client: Open189Client,
}

impl Open189App {
    /// Construct a client instance given the `open.189.cn` app ID and secret.
    ///
    /// A Hyper client is created with default parameters for the underlying
    /// HTTP transport. You can provide your own Hyper client instance instead
    /// with the [`with_client`] method.
    ///
    /// [`with_client`]: #method.with_client
    ///
    /// # Examples
    ///
    /// ```
    /// use open189::Open189App;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let client = Open189App::new(app_id, secret);
    /// ```
    pub fn new<S: AsRef<str>>(app_id: S, secret: S) -> Open189App {
        Open189App::with_client(app_id, secret, Client::new())
    }

    /// Construct a client instance with the provided Hyper client instance.
    ///
    /// Consumes the `Client` passed in; useful if you want to configure your
    /// HTTP client before using, for example setting up proxy or connection
    /// pooling.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    /// use hyper;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let http_client = hyper::client::Client::new();
    /// // configure your HTTP client
    /// let client = Open189App::with_client(app_id, secret, http_client);
    /// ```
    pub fn with_client<S: AsRef<str>>(app_id: S, secret: S, client: Client) -> Open189App {
        Open189App {
            app_id: app_id.as_ref().to_string(),
            secret: secret.as_ref().to_string(),
            client: Open189Client::new(client),
        }
    }

    /// Get the app ID the client is created with.
    ///
    /// # Examples
    ///
    /// ```
    /// use open189::Open189App;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let client = Open189App::new(app_id, secret);
    ///
    /// assert_eq!(client.app_id(), app_id);
    /// ```
    pub fn app_id(&self) -> &str {
        &self.app_id
    }

    /// Get the app secret the client is created with.
    ///
    /// # Examples
    ///
    /// ```
    /// use open189::Open189App;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let client = Open189App::new(app_id, secret);
    ///
    /// assert_eq!(client.secret(), secret);
    /// ```
    pub fn secret(&self) -> &str {
        &self.secret
    }

    /// Request a user-independent access token with the Client Credentials flow.
    ///
    /// As a best practice, you should utilize the API considerately and avoid
    /// repeatedly hammering it with access token requests. It's recommended to
    /// cache the access token yourself, in any way you'd like to, and periodically
    /// refresh it before expiry.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    ///
    /// let client = Open189App::new(app_id, secret);
    /// let access_token = client.get_access_token_cc()?;
    /// # store the access token somewhere!
    /// ```
    pub fn get_access_token_cc(&self) -> Result<msg::AccessToken> {
        let mut params = HashMap::new();
        params.insert("grant_type", "client_credentials".to_string());
        self.client
            .perform_access_token_req::<_, resp::AccessTokenResponse>(self.app_id(),
                                                                      self.secret(),
                                                                      params)
    }

    /// Request a token for use in the SMS sending API.
    ///
    /// An access token is required; you can get one with the [`get_access_token_cc`]
    /// method.
    ///
    /// [`get_access_token_cc`]: #method.get_access_token_cc
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    ///
    /// let client = Open189App::new(app_id, secret);
    /// let access_token = fetch_cached_access_token();
    /// let sms_token = client.sms_get_token(access_token)?;
    /// ```
    pub fn sms_get_token<S: AsRef<str>>(&self, access_token: S) -> Result<String> {
        let params = HashMap::new();
        self.client.get_sync::<_, _, resp::SmsTokenResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             URL_SMS_TOKEN,
                                                             params)
    }
}

/// Configuration for sending of locally generated SMS verification code.
///
/// This struct is not meant to be used directly; see [`SmsCodeConfig::prepared`]
/// instead.
///
/// [`SmsCodeConfig::prepared`]: ../enum.SmsCodeConfig.html#method.prepared
pub struct PreparedSmsCode<'a> {
    phone: &'a str,
    code: &'a str,
    expire_time: Option<usize>,
}

/// Configuration for sending of API-generated SMS verification code.
///
/// This struct is not meant to be used directly; see [`SmsCodeConfig::callback`]
/// instead.
///
/// [`SmsCodeConfig::callback`]: ../enum.SmsCodeConfig.html#method.callback
pub struct CallbackSmsCode<'a> {
    phone: &'a str,
    url: Url,
    expire_time: Option<usize>,
}

/// Configuration for SMS verification code.
pub enum SmsCodeConfig<'a> {
    /// Code is generated locally, ready to be sent.
    Prepared(PreparedSmsCode<'a>),
    /// Code is to be generated remotely by the API server, and sent back to the
    /// callback URL provided.
    Callback(CallbackSmsCode<'a>),
}

impl<'a> SmsCodeConfig<'a> {
    /// Construct the parameters for sending pre-generated verification code.
    ///
    /// The code should consist of 6 digits only. Everything else would be rejected
    /// by the API anyway, so the validation is done locally before firing the
    /// actual request.
    ///
    /// Expiry time is optional and seems purely informative, given it's just
    /// another integer formatted into the fixed SMS template. The value is
    /// expected to be in minutes, as suggested by the wording of the template.
    /// Defaults to 2 minutes if not specified.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::SmsCodeConfig;
    ///
    /// # use default expiry time
    /// let config = SmsCodeConfig::prepared("12345678901", "234567", None);
    ///
    /// # manually specify an expiry time of 5 min
    /// let config = SmsCodeConfig::prepared("12345678901", "234567", Some(5));
    /// ```
    pub fn prepared(phone: &'a str,
                    code: &'a str,
                    expire_time: Option<usize>)
                    -> SmsCodeConfig<'a> {
        SmsCodeConfig::Prepared(PreparedSmsCode {
            phone: phone,
            code: code,
            expire_time: expire_time,
        })
    }

    /// Construct the parameters for sending remotely-generated verification code.
    ///
    /// Instead of providing the code yourself, the API would choose one for you,
    /// and notify you by `POST`-ing to the callback URL you provided. The URL is
    /// validated on construction and may fail, in which case an `Err` would be
    /// returned.
    ///
    /// Expiry time is interpreted the same way as [above].
    ///
    /// [above]: #method.prepared
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::SmsCodeConfig;
    ///
    /// let url = "https://api.example.com/v1/callback/sms";
    /// let config = SmsCodeConfig::callback("12345678901", url, None).unwrap();
    /// ```
    pub fn callback<U: IntoUrl>(phone: &'a str,
                                callback_url: U,
                                expire_time: Option<usize>)
                                -> Result<SmsCodeConfig<'a>> {
        Ok(SmsCodeConfig::Callback(CallbackSmsCode {
            phone: phone,
            url: callback_url.into_url()?,
            expire_time: expire_time,
        }))
    }
}

impl Open189App {
    /// Send a verification code with SMS.
    ///
    /// An access token is required; you can get one with the [`get_access_token_cc`]
    /// method. This token is reusable; just remember to refresh it periodically.
    /// You also need to request a separate token for every SMS you're going
    /// to send, with the [`sms_get_token`] method.
    ///
    /// There are two supported ways to send a SMS verification code. One is to
    /// generate the verification code yourself; the other is to have the API
    /// pick one for you, then notifying you with a POST to a callback URL provided
    /// alongside the request. You're expected to manage the expiry time yourself
    /// anyway, so probably you're also generating your own codes, but the choice
    /// is there; use one of [the `SmsCodeConfig` constructors][ctors] to pass the
    /// parameters.
    ///
    /// [`get_access_token_cc`]: #method.get_access_token_cc
    /// [`sms_get_token`]: #method.sms_get_token
    /// [ctors]: ../enum.SmsCodeConfig.html#methods
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    /// use open189::SmsCodeConfig;
    ///
    /// let client = Open189App::new(app_id, secret);
    /// let access_token = fetch_cached_access_token();
    /// let sms_token = client.sms_get_token(access_token)?;
    ///
    /// let config = SmsCodeConfig::prepared("12345678901", "234567", Some(5));
    /// let result = client.sms_send_verification_code(access_token, sms_token, config)?;
    /// ```
    pub fn sms_send_verification_code<S: AsRef<str>>(&self,
                                                     access_token: S,
                                                     sms_token: S,
                                                     config: SmsCodeConfig)
                                                     -> Result<msg::SentSmsCode> {
        let mut params = HashMap::new();
        params.insert("token", sms_token.as_ref().to_string());

        let url;
        match config {
            SmsCodeConfig::Prepared(config) => {
                url = URL_SMS_SEND_WITH_CODE;

                let code = config.code;
                if code.len() != 6 {
                    return Err(ErrorKind::WrongSmsCodeLength(code.len(), 6).into());
                }
                if !code.chars().all(|ch| ch.is_digit(10)) {
                    return Err(ErrorKind::NonDigitInSmsCode(code.to_string()).into());
                }
                params.insert("randcode", code.to_string());

                params.insert("phone", config.phone.to_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
            SmsCodeConfig::Callback(config) => {
                url = URL_SMS_SEND_WITH_CALLBACK;

                params.insert("phone", config.phone.to_string());
                params.insert("url", config.url.into_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
        }

        self.client.post_sync::<_, _, resp::SmsCodeResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             url,
                                                             params)
    }
}
<commit_msg>docs: fix intra links<commit_after>use std::collections::HashMap;

use hyper::client::Client;
use hyper::client::IntoUrl;

use url::Url;

use super::errors::*;
use super::msg;
use super::resp;
use super::net::Open189Client;

const URL_SMS_TOKEN: &'static str = "http://api.189.cn/v2/dm/randcode/token";
const URL_SMS_SEND_WITH_CODE: &'static str = "http://api.189.cn/v2/dm/randcode/sendSms";
const URL_SMS_SEND_WITH_CALLBACK: &'static str = "http://api.189.cn/v2/dm/randcode/send";

/// Client for the `open.189.cn` API.
pub struct Open189App {
    app_id: String,
    secret: String,
    client: Open189Client,
}

impl Open189App {
    /// Construct a client instance given the `open.189.cn` app ID and secret.
    ///
    /// A Hyper client is created with default parameters for the underlying
    /// HTTP transport. You can provide your own Hyper client instance instead
    /// with the [`with_client`] method.
    ///
    /// [`with_client`]: #method.with_client
    ///
    /// # Examples
    ///
    /// ```
    /// use open189::Open189App;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let client = Open189App::new(app_id, secret);
    /// ```
    pub fn new<S: AsRef<str>>(app_id: S, secret: S) -> Open189App {
        Open189App::with_client(app_id, secret, Client::new())
    }

    /// Construct a client instance with the provided Hyper client instance.
    ///
    /// Consumes the `Client` passed in; useful if you want to configure your
    /// HTTP client before using, for example setting up proxy or connection
    /// pooling.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    /// use hyper;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let http_client = hyper::client::Client::new();
    /// // configure your HTTP client
    /// let client = Open189App::with_client(app_id, secret, http_client);
    /// ```
    pub fn with_client<S: AsRef<str>>(app_id: S, secret: S, client: Client) -> Open189App {
        Open189App {
            app_id: app_id.as_ref().to_string(),
            secret: secret.as_ref().to_string(),
            client: Open189Client::new(client),
        }
    }

    /// Get the app ID the client is created with.
    ///
    /// # Examples
    ///
    /// ```
    /// use open189::Open189App;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let client = Open189App::new(app_id, secret);
    ///
    /// assert_eq!(client.app_id(), app_id);
    /// ```
    pub fn app_id(&self) -> &str {
        &self.app_id
    }

    /// Get the app secret the client is created with.
    ///
    /// # Examples
    ///
    /// ```
    /// use open189::Open189App;
    ///
    /// let app_id = "your app id here";
    /// let secret = "your app secret here";
    /// let client = Open189App::new(app_id, secret);
    ///
    /// assert_eq!(client.secret(), secret);
    /// ```
    pub fn secret(&self) -> &str {
        &self.secret
    }

    /// Request a user-independent access token with the Client Credentials flow.
    ///
    /// As a best practice, you should utilize the API considerately and avoid
    /// repeatedly hammering it with access token requests. It's recommended to
    /// cache the access token yourself, in any way you'd like to, and periodically
    /// refresh it before expiry.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    ///
    /// let client = Open189App::new(app_id, secret);
    /// let access_token = client.get_access_token_cc()?;
    /// # store the access token somewhere!
    /// ```
    pub fn get_access_token_cc(&self) -> Result<msg::AccessToken> {
        let mut params = HashMap::new();
        params.insert("grant_type", "client_credentials".to_string());
        self.client
            .perform_access_token_req::<_, resp::AccessTokenResponse>(self.app_id(),
                                                                      self.secret(),
                                                                      params)
    }

    /// Request a token for use in the SMS sending API.
    ///
    /// An access token is required; you can get one with the [`get_access_token_cc`]
    /// method.
    ///
    /// [`get_access_token_cc`]: #method.get_access_token_cc
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    ///
    /// let client = Open189App::new(app_id, secret);
    /// let access_token = fetch_cached_access_token();
    /// let sms_token = client.sms_get_token(access_token)?;
    /// ```
    pub fn sms_get_token<S: AsRef<str>>(&self, access_token: S) -> Result<String> {
        let params = HashMap::new();
        self.client.get_sync::<_, _, resp::SmsTokenResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             URL_SMS_TOKEN,
                                                             params)
    }
}

/// Configuration for sending of locally generated SMS verification code.
///
/// This struct is not meant to be used directly; see [`SmsCodeConfig::prepared`]
/// instead.
///
/// [`SmsCodeConfig::prepared`]: enum.SmsCodeConfig.html#method.prepared
pub struct PreparedSmsCode<'a> {
    phone: &'a str,
    code: &'a str,
    expire_time: Option<usize>,
}

/// Configuration for sending of API-generated SMS verification code.
///
/// This struct is not meant to be used directly; see [`SmsCodeConfig::callback`]
/// instead.
///
/// [`SmsCodeConfig::callback`]: enum.SmsCodeConfig.html#method.callback
pub struct CallbackSmsCode<'a> {
    phone: &'a str,
    url: Url,
    expire_time: Option<usize>,
}

/// Configuration for SMS verification code.
pub enum SmsCodeConfig<'a> {
    /// Code is generated locally, ready to be sent.
    Prepared(PreparedSmsCode<'a>),
    /// Code is to be generated remotely by the API server, and sent back to the
    /// callback URL provided.
    Callback(CallbackSmsCode<'a>),
}

impl<'a> SmsCodeConfig<'a> {
    /// Construct the parameters for sending pre-generated verification code.
    ///
    /// The code should consist of 6 digits only. Everything else would be rejected
    /// by the API anyway, so the validation is done locally before firing the
    /// actual request.
    ///
    /// Expiry time is optional and seems purely informative, given it's just
    /// another integer formatted into the fixed SMS template. The value is
    /// expected to be in minutes, as suggested by the wording of the template.
    /// Defaults to 2 minutes if not specified.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::SmsCodeConfig;
    ///
    /// # use default expiry time
    /// let config = SmsCodeConfig::prepared("12345678901", "234567", None);
    ///
    /// # manually specify an expiry time of 5 min
    /// let config = SmsCodeConfig::prepared("12345678901", "234567", Some(5));
    /// ```
    pub fn prepared(phone: &'a str,
                    code: &'a str,
                    expire_time: Option<usize>)
                    -> SmsCodeConfig<'a> {
        SmsCodeConfig::Prepared(PreparedSmsCode {
            phone: phone,
            code: code,
            expire_time: expire_time,
        })
    }

    /// Construct the parameters for sending remotely-generated verification code.
    ///
    /// Instead of providing the code yourself, the API would choose one for you,
    /// and notify you by `POST`-ing to the callback URL you provided. The URL is
    /// validated on construction and may fail, in which case an `Err` would be
    /// returned.
    ///
    /// Expiry time is interpreted the same way as [above].
    ///
    /// [above]: #method.prepared
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::SmsCodeConfig;
    ///
    /// let url = "https://api.example.com/v1/callback/sms";
    /// let config = SmsCodeConfig::callback("12345678901", url, None).unwrap();
    /// ```
    pub fn callback<U: IntoUrl>(phone: &'a str,
                                callback_url: U,
                                expire_time: Option<usize>)
                                -> Result<SmsCodeConfig<'a>> {
        Ok(SmsCodeConfig::Callback(CallbackSmsCode {
            phone: phone,
            url: callback_url.into_url()?,
            expire_time: expire_time,
        }))
    }
}

impl Open189App {
    /// Send a verification code with SMS.
    ///
    /// An access token is required; you can get one with the [`get_access_token_cc`]
    /// method. This token is reusable; just remember to refresh it periodically.
    /// You also need to request a separate token for every SMS you're going
    /// to send, with the [`sms_get_token`] method.
    ///
    /// There are two supported ways to send a SMS verification code. One is to
    /// generate the verification code yourself; the other is to have the API
    /// pick one for you, then notifying you with a POST to a callback URL provided
    /// alongside the request. You're expected to manage the expiry time yourself
    /// anyway, so probably you're also generating your own codes, but the choice
    /// is there; use one of [the `SmsCodeConfig` constructors][ctors] to pass the
    /// parameters.
    ///
    /// [`get_access_token_cc`]: #method.get_access_token_cc
    /// [`sms_get_token`]: #method.sms_get_token
    /// [ctors]: enum.SmsCodeConfig.html#methods
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use open189::Open189App;
    /// use open189::SmsCodeConfig;
    ///
    /// let client = Open189App::new(app_id, secret);
    /// let access_token = fetch_cached_access_token();
    /// let sms_token = client.sms_get_token(access_token)?;
    ///
    /// let config = SmsCodeConfig::prepared("12345678901", "234567", Some(5));
    /// let result = client.sms_send_verification_code(access_token, sms_token, config)?;
    /// ```
    pub fn sms_send_verification_code<S: AsRef<str>>(&self,
                                                     access_token: S,
                                                     sms_token: S,
                                                     config: SmsCodeConfig)
                                                     -> Result<msg::SentSmsCode> {
        let mut params = HashMap::new();
        params.insert("token", sms_token.as_ref().to_string());

        let url;
        match config {
            SmsCodeConfig::Prepared(config) => {
                url = URL_SMS_SEND_WITH_CODE;

                let code = config.code;
                if code.len() != 6 {
                    return Err(ErrorKind::WrongSmsCodeLength(code.len(), 6).into());
                }
                if !code.chars().all(|ch| ch.is_digit(10)) {
                    return Err(ErrorKind::NonDigitInSmsCode(code.to_string()).into());
                }
                params.insert("randcode", code.to_string());

                params.insert("phone", config.phone.to_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
            SmsCodeConfig::Callback(config) => {
                url = URL_SMS_SEND_WITH_CALLBACK;

                params.insert("phone", config.phone.to_string());
                params.insert("url", config.url.into_string());
                if let Some(expire_time) = config.expire_time {
                    params.insert("exp_time", format!("{}", expire_time));
                }
            }
        }

        self.client.post_sync::<_, _, resp::SmsCodeResponse>(self.app_id(),
                                                             self.secret(),
                                                             access_token.as_ref(),
                                                             url,
                                                             params)
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::os::unix::io::RawFd;
use std::rc::Rc;

use cairo_sys;
use cairo::{self, Context, XCBSurface};
use futures::{future, Async, Future, Poll, Stream};
use futures::stream::MergedItem;
use mio::{self, PollOpt, Ready, Token};
use mio::event::Evented;
use mio::unix::EventedFd;
use tokio_core::reactor::{Handle, PollEvented};
use xcb;

use text::{Color, Text};
use widgets::{WidgetList, Widget};

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

/// Creates a `cairo::Surface` for the XCB window with the given `id`.
fn cairo_surface_for_xcb_window(conn: &xcb::Connection,
                                screen: &xcb::Screen,
                                id: u32,
                                width: i32,
                                height: i32)
                                -> cairo::Surface {
    let cairo_conn = unsafe {
        cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as *mut cairo_sys::xcb_connection_t)
    };
    let visual = unsafe {
        cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(&conn, &screen).base as
                                            *mut xcb::ffi::xcb_visualtype_t as
                                            *mut cairo_sys::xcb_visualtype_t)
    };
    let drawable = cairo::XCBDrawable(id);
    cairo::Surface::create(&cairo_conn, &drawable, &visual, width, height)
}

pub struct Bar {
    conn: Rc<xcb::Connection>,
    window_id: u32,
    screen_idx: usize,
    surface: cairo::Surface,
    contents: Vec<Vec<Text>>,
}

impl Bar {
    pub fn new() -> Bar {
        let (conn, screen_idx) = xcb::Connection::connect_with_xlib_display().unwrap();
        let screen_idx = screen_idx as usize;
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            cairo_surface_for_xcb_window(&conn, &screen, id, width as i32, height as i32)
        };

        let bar = Bar {
            conn: Rc::new(conn),
            window_id: id,
            screen_idx,
            surface,
            contents: Vec::new(),
        };
        bar.map_window();
        bar.flush();
        bar
    }

    fn flush(&self) {
        self.conn.flush();
    }

    fn map_window(&self) {
        xcb::map_window(&self.conn, self.window_id);
    }

    fn screen(&self) -> xcb::Screen {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    fn update_contents(&mut self, new_contents: Vec<Option<Vec<Text>>>) {
        for (i, opt) in new_contents.into_iter().enumerate() {
            if let Some(new) = opt {
                self.contents[i] = new;
            }
        }
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in &mut layouts {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in &mut stretched {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }

    fn expose(&self) {
        // Clear to black before re-painting.
        let context = Context::new(&self.surface);
        Color::black().apply_to_context(&context);
        context.paint();

        let flattened_contents = self.contents.clone().into_iter().flat_map(|v| v).collect();

        self.render_text_blocks(flattened_contents);
        self.conn.flush();
    }

    pub fn run_event_loop(mut self,
                          handle: &Handle,
                          widgets: Vec<Box<Widget>>)
                          -> Box<Future<Item = (), Error = ()>> {
        self.contents = vec![Vec::new(); widgets.len()];

        let events_stream = XcbEventStream::new(self.conn.clone(), handle);
        let widget_updates_stream = WidgetList::new(widgets);

        let event_loop = events_stream.merge(widget_updates_stream);
        let fut = event_loop.for_each(move |item| {
            let (xcb_event, widget_update) = match item {
                MergedItem::First(e) => (Some(e), None),
                MergedItem::Second(u) => (None, Some(u)),
                MergedItem::Both(e, u) => (Some(e), Some(u)),
            };

            if let Some(update) = widget_update {
                self.update_contents(update);
                self.expose();
            }
            if let Some(event) = xcb_event {
                match event.response_type() & !0x80 {
                    xcb::EXPOSE => self.expose(),
                    _ => {}
                }
            }

            future::ok(())
        });

        Box::new(fut)
    }
}

struct XcbEvented(Rc<xcb::Connection>);

impl XcbEvented {
    fn fd(&self) -> RawFd {
        unsafe { xcb::ffi::base::xcb_get_file_descriptor(self.0.get_raw_conn()) }
    }
}

impl Evented for XcbEvented {
    fn register(&self,
                poll: &mio::Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt)
                -> io::Result<()> {
        EventedFd(&self.fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self,
                  poll: &mio::Poll,
                  token: Token,
                  interest: Ready,
                  opts: PollOpt)
                  -> io::Result<()> {
        EventedFd(&self.fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        EventedFd(&self.fd()).deregister(poll)
    }
}

struct XcbEventStream {
    conn: Rc<xcb::Connection>,
    poll: PollEvented<XcbEvented>,
    would_block: bool,
}

impl XcbEventStream {
    fn new(conn: Rc<xcb::Connection>, handle: &Handle) -> XcbEventStream {
        let evented = XcbEvented(conn.clone());
        XcbEventStream {
            conn,
            poll: PollEvented::new(evented, handle).unwrap(),
            would_block: true,
        }
    }
}

impl Stream for XcbEventStream {
    type Item = xcb::GenericEvent;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if self.would_block {
            match self.poll.poll_read() {
                Async::Ready(()) => self.would_block = false,
                Async::NotReady => return Ok(Async::NotReady),
            }
        }

        match self.conn.poll_for_event() {
            Some(event) => Ok(Async::Ready(Some(event))),
            None => {
                self.would_block = true;
                self.poll.need_read();
                Ok(Async::NotReady)
            }
        }
    }
}
<commit_msg>Extra borrow unnecessary.<commit_after>use std::io;
use std::os::unix::io::RawFd;
use std::rc::Rc;

use cairo_sys;
use cairo::{self, Context, XCBSurface};
use futures::{future, Async, Future, Poll, Stream};
use futures::stream::MergedItem;
use mio::{self, PollOpt, Ready, Token};
use mio::event::Evented;
use mio::unix::EventedFd;
use tokio_core::reactor::{Handle, PollEvented};
use xcb;

use text::{Color, Text};
use widgets::{WidgetList, Widget};

fn get_root_visual_type(conn: &xcb::Connection, screen: &xcb::Screen) -> xcb::Visualtype {
    for root in conn.get_setup().roots() {
        for allowed_depth in root.allowed_depths() {
            for visual in allowed_depth.visuals() {
                if visual.visual_id() == screen.root_visual() {
                    return visual;
                }
            }
        }
    }
    panic!("No visual type found");
}

/// Creates a `cairo::Surface` for the XCB window with the given `id`.
fn cairo_surface_for_xcb_window(conn: &xcb::Connection,
                                screen: &xcb::Screen,
                                id: u32,
                                width: i32,
                                height: i32)
                                -> cairo::Surface {
    let cairo_conn = unsafe {
        cairo::XCBConnection::from_raw_none(conn.get_raw_conn() as *mut cairo_sys::xcb_connection_t)
    };
    let visual = unsafe {
        cairo::XCBVisualType::from_raw_none(&mut get_root_visual_type(conn, screen).base as
                                            *mut xcb::ffi::xcb_visualtype_t as
                                            *mut cairo_sys::xcb_visualtype_t)
    };
    let drawable = cairo::XCBDrawable(id);
    cairo::Surface::create(&cairo_conn, &drawable, &visual, width, height)
}

pub struct Bar {
    conn: Rc<xcb::Connection>,
    window_id: u32,
    screen_idx: usize,
    surface: cairo::Surface,
    contents: Vec<Vec<Text>>,
}

impl Bar {
    pub fn new() -> Bar {
        let (conn, screen_idx) = xcb::Connection::connect_with_xlib_display().unwrap();
        let screen_idx = screen_idx as usize;
        let id = conn.generate_id();

        let surface = {
            let screen = conn.get_setup()
                .roots()
                .nth(screen_idx)
                .expect("invalid screen");
            let values = [(xcb::CW_BACK_PIXEL, screen.black_pixel()),
                          (xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE)];

            let (width, height) = (screen.width_in_pixels(), 100);

            xcb::create_window(&conn,
                               xcb::COPY_FROM_PARENT as u8,
                               id,
                               screen.root(),
                               0,
                               0,
                               width,
                               height,
                               10,
                               xcb::WINDOW_CLASS_INPUT_OUTPUT as u16,
                               screen.root_visual(),
                               &values);

            cairo_surface_for_xcb_window(&conn, &screen, id, width as i32, height as i32)
        };

        let bar = Bar {
            conn: Rc::new(conn),
            window_id: id,
            screen_idx,
            surface,
            contents: Vec::new(),
        };
        bar.map_window();
        bar.flush();
        bar
    }

    fn flush(&self) {
        self.conn.flush();
    }

    fn map_window(&self) {
        xcb::map_window(&self.conn, self.window_id);
    }

    fn screen(&self) -> xcb::Screen {
        self.conn
            .get_setup()
            .roots()
            .nth(self.screen_idx)
            .expect("Invalid screen")
    }

    fn update_contents(&mut self, new_contents: Vec<Option<Vec<Text>>>) {
        for (i, opt) in new_contents.into_iter().enumerate() {
            if let Some(new) = opt {
                self.contents[i] = new;
            }
        }
    }

    fn render_text_blocks(&self, texts: Vec<Text>) {
        // Layout each block of text. After this, we can query the width of each
        // block, which will allow us to do more complex layout below.
        let mut layouts: Vec<_> = texts.into_iter().map(|t| t.layout(&self.surface)).collect();

        // Calculate how much free space we have after laying out all the
        // non-stretch blocks. Split the remaining space (if any) between the
        // stretch blocks. If there isn't enough space for the non-stretch blocks
        // do nothing and allow it to overflow.
        {
            let mut width = 0.0;
            let mut stretched = Vec::new();
            for layout in &mut layouts {
                if !layout.stretch() {
                    width += layout.width();
                } else {
                    stretched.push(layout);
                }
            }

            let remaining_width = self.screen().width_in_pixels() as f64 - width;
            let remaining_width = if remaining_width < 0.0 {
                0.0
            } else {
                remaining_width
            };
            let width_per_stretched = remaining_width / (stretched.len() as f64);
            for layout in &mut stretched {
                layout.set_width(width_per_stretched);
            }
        }

        // TODO: Set the height of the window and the height of each text block(?)
        // to the height of the largest bit of text.

        // Finally, just render each block of text in turn.
        let mut x = 0.0;
        for layout in &layouts {
            layout.render(x, 0.0);
            x += layout.width();
        }
    }

    fn expose(&self) {
        // Clear to black before re-painting.
        let context = Context::new(&self.surface);
        Color::black().apply_to_context(&context);
        context.paint();

        let flattened_contents = self.contents.clone().into_iter().flat_map(|v| v).collect();

        self.render_text_blocks(flattened_contents);
        self.conn.flush();
    }

    pub fn run_event_loop(mut self,
                          handle: &Handle,
                          widgets: Vec<Box<Widget>>)
                          -> Box<Future<Item = (), Error = ()>> {
        self.contents = vec![Vec::new(); widgets.len()];

        let events_stream = XcbEventStream::new(self.conn.clone(), handle);
        let widget_updates_stream = WidgetList::new(widgets);

        let event_loop = events_stream.merge(widget_updates_stream);
        let fut = event_loop.for_each(move |item| {
            let (xcb_event, widget_update) = match item {
                MergedItem::First(e) => (Some(e), None),
                MergedItem::Second(u) => (None, Some(u)),
                MergedItem::Both(e, u) => (Some(e), Some(u)),
            };

            if let Some(update) = widget_update {
                self.update_contents(update);
                self.expose();
            }
            if let Some(event) = xcb_event {
                match event.response_type() & !0x80 {
                    xcb::EXPOSE => self.expose(),
                    _ => {}
                }
            }

            future::ok(())
        });

        Box::new(fut)
    }
}

struct XcbEvented(Rc<xcb::Connection>);

impl XcbEvented {
    fn fd(&self) -> RawFd {
        unsafe { xcb::ffi::base::xcb_get_file_descriptor(self.0.get_raw_conn()) }
    }
}

impl Evented for XcbEvented {
    fn register(&self,
                poll: &mio::Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt)
                -> io::Result<()> {
        EventedFd(&self.fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self,
                  poll: &mio::Poll,
                  token: Token,
                  interest: Ready,
                  opts: PollOpt)
                  -> io::Result<()> {
        EventedFd(&self.fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
        EventedFd(&self.fd()).deregister(poll)
    }
}

struct XcbEventStream {
    conn: Rc<xcb::Connection>,
    poll: PollEvented<XcbEvented>,
    would_block: bool,
}

impl XcbEventStream {
    fn new(conn: Rc<xcb::Connection>, handle: &Handle) -> XcbEventStream {
        let evented = XcbEvented(conn.clone());
        XcbEventStream {
            conn,
            poll: PollEvented::new(evented, handle).unwrap(),
            would_block: true,
        }
    }
}

impl Stream for XcbEventStream {
    type Item = xcb::GenericEvent;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if self.would_block {
            match self.poll.poll_read() {
                Async::Ready(()) => self.would_block = false,
                Async::NotReady => return Ok(Async::NotReady),
            }
        }

        match self.conn.poll_for_event() {
            Some(event) => Ok(Async::Ready(Some(event))),
            None => {
                self.would_block = true;
                self.poll.need_read();
                Ok(Async::NotReady)
            }
        }
    }
}
<|endoftext|>


<commit_before>use space::*;

pub struct Bots {
    instances: Vec<Position>
}
impl Bots {
    fn new() -> Bots {
        Bots {
            instances: Vec::new()
        }
    }
    fn make(&mut self, position: Position) {
        self.instances.push(position);
    }
    fn occupied(&self, position: Position) -> bool {
        for e in &self.instances {
            if e == &position {
                return true
            }
        }
        false
    }
}

#[test]
fn instantiation() {
    let a = Position::new(0, 0);
    let b = Position::new(2, 0);
    let c = Position::new(-1, 3);

    let mut bots = Bots::new();
    assert!(!bots.occupied(a));
    assert!(!bots.occupied(b));
    assert!(!bots.occupied(c));

    bots.make(Position::new(0, 0));
    assert!(bots.occupied(a));
    assert!(!bots.occupied(b));
    assert!(!bots.occupied(c));

    bots.make(Position::new(2, 0));
    assert!(bots.occupied(a));
    assert!(bots.occupied(b));
    assert!(!bots.occupied(c));
}
<commit_msg>Unconstrained bot movement<commit_after>use std::error::Error;
use std::fmt;

use space::*;

#[derive(Debug)]
pub struct NotFoundError;
impl Error for NotFoundError {
    fn description(&self) -> &str {
        "No bot found at the specified location."
    }
}
impl fmt::Display for NotFoundError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

pub struct Bots {
    instances: Vec<Position>
}
impl Bots {
    fn new() -> Bots {
        Bots {
            instances: Vec::new()
        }
    }

    fn make(&mut self, position: Position) {
        self.instances.push(position);
    }

    fn occupied(&self, position: Position) -> bool {
        self.instances.contains(&position)
    }

    fn shift(&mut self, from: Position, to: Position) -> Result<(), NotFoundError> {
        for e in self.instances.iter_mut() {
            if e == &from {
                *e = to;
                return Ok(())
            }
        }
        Err(NotFoundError)
    }
}

#[test]
fn instantiation() {
    let a = Position::new(0, 0);
    let b = Position::new(2, 0);
    let c = Position::new(-1, 3);

    let mut bots = Bots::new();
    assert!(!bots.occupied(a));
    assert!(!bots.occupied(b));
    assert!(!bots.occupied(c));

    bots.make(a);
    assert!(bots.occupied(a));
    assert!(!bots.occupied(b));
    assert!(!bots.occupied(c));

    bots.make(b);
    assert!(bots.occupied(a));
    assert!(bots.occupied(b));
    assert!(!bots.occupied(c));
}

#[test]
fn movement() {
    let a = Position::new(0, 0);
    let b = Position::new(2, 0);

    let mut bots = Bots::new();

    bots.make(a);
    assert!(bots.occupied(a));
    assert!(!bots.occupied(b));

    bots.shift(a, b).unwrap();
    assert!(!bots.occupied(a));
    assert!(bots.occupied(b));
}

#[test]
fn movement_nonexistent() {
    let mut bots = Bots::new();

    match bots.shift(Position::new(0, 1), Position::new(2, 5)) {
        Ok(_) => panic!(),
        Err(_) => ()
    }
}
<|endoftext|>


<commit_before>//! A simple parser for a tiny subset of CSS.
//!
//! To support more CSS syntax, it would probably be easiest to replace this
//! hand-rolled parser with one based on a library or parser generator.

use std::ascii::AsciiExt; // for `to_ascii_lowercase`

// Data structures:

#[derive(Debug)]
pub struct Stylesheet {
    pub rules: Vec<Rule>,
}

#[derive(Debug)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub declarations: Vec<Declaration>,
}

#[derive(Debug)]
pub enum Selector {
    Simple(SimpleSelector),
}

#[derive(Debug)]
pub struct SimpleSelector {
    pub tag_name: Option<String>,
    pub id: Option<String>,
    pub class: Vec<String>,
}

#[derive(Debug)]
pub struct Declaration {
    pub name: String,
    pub value: Value,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Keyword(String),
    Length(f32, Unit),
    ColorValue(Color),
}

#[derive(Debug, Clone, PartialEq)]
pub enum Unit {
    Px,
}

#[derive(Debug, Clone, PartialEq, Default)]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
    pub a: u8,
}

impl Copy for Color {}

pub type Specificity = (usize, usize, usize);

impl Selector {
    pub fn specificity(&self) -> Specificity {
        // http://www.w3.org/TR/selectors/#specificity
        let Selector::Simple(ref simple) = *self;
        let a = simple.id.iter().count();
        let b = simple.class.len();
        let c = simple.tag_name.iter().count();
        (a, b, c)
    }
}

impl Value {
    /// Return the size of a length in px, or zero for non-lengths.
    pub fn to_px(&self) -> f32 {
        match *self {
            Value::Length(f, Unit::Px) => f,
            _ => 0.0
        }
    }
}

/// Parse a whole CSS stylesheet.
pub fn parse(source: String) -> Stylesheet {
    let mut parser = Parser { pos: 0, input: source };
    Stylesheet { rules: parser.parse_rules() }
}

struct Parser {
    pos: usize,
    input: String,
}

impl Parser {
    /// Parse a list of rule sets, separated by optional whitespace.
    fn parse_rules(&mut self) -> Vec<Rule> {
        let mut rules = Vec::new();
        loop {
            self.consume_whitespace();
            if self.eof() { break }
            rules.push(self.parse_rule());
        }
        rules
    }

    /// Parse a rule set: `<selectors> { <declarations> }`.
    fn parse_rule(&mut self) -> Rule {
        Rule {
            selectors: self.parse_selectors(),
            declarations: self.parse_declarations(),
        }
    }

    /// Parse a comma-separated list of selectors.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();
        loop {
            selectors.push(Selector::Simple(self.parse_simple_selector()));
            self.consume_whitespace();
            match self.next_char() {
                ',' => { self.consume_char(); self.consume_whitespace(); }
                '{' => break,
                c   => panic!("Unexpected character {} in selector list", c)
            }
        }
        // Return selectors with highest specificity first, for use in matching.
        selectors.sort_by(|a,b| b.specificity().cmp(&a.specificity()));
        selectors
    }

    /// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
    fn parse_simple_selector(&mut self) -> SimpleSelector {
        let mut selector = SimpleSelector { tag_name: None, id: None, class: Vec::new() };
        while !self.eof() {
            match self.next_char() {
                '#' => {
                    self.consume_char();
                    selector.id = Some(self.parse_identifier());
                }
                '.' => {
                    self.consume_char();
                    selector.class.push(self.parse_identifier());
                }
                '*' => {
                    // universal selector
                    self.consume_char();
                }
                c if valid_identifier_char(c) => {
                    selector.tag_name = Some(self.parse_identifier());
                }
                _ => break
            }
        }
        selector
    }

    /// Parse a list of declarations enclosed in `{ ... }`.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        assert_eq!(self.consume_char(), '{');
        let mut declarations = Vec::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '}' {
                self.consume_char();
                break;
            }
            declarations.push(self.parse_declaration());
        }
        declarations
    }

    /// Parse one `<property>: <value>;` declaration.
    fn parse_declaration(&mut self) -> Declaration {
        let property_name = self.parse_identifier();
        self.consume_whitespace();
        assert_eq!(self.consume_char(), ':');
        self.consume_whitespace();
        let value = self.parse_value();
        self.consume_whitespace();
        assert_eq!(self.consume_char(), ';');

        Declaration {
            name: property_name,
            value: value,
        }
    }

    // Methods for parsing values:

    fn parse_value(&mut self) -> Value {
        match self.next_char() {
            '0'...'9' => self.parse_length(),
            '#' => self.parse_color(),
            _ => Value::Keyword(self.parse_identifier())
        }
    }

    fn parse_length(&mut self) -> Value {
        Value::Length(self.parse_float(), self.parse_unit())
    }

    fn parse_float(&mut self) -> f32 {
        let s = self.consume_while(|c| match c {
            '0'...'9' | '.' => true,
            _ => false
        });
        s.parse().unwrap()
    }

    fn parse_unit(&mut self) -> Unit {
        match &*self.parse_identifier().to_ascii_lowercase() {
            "px" => Unit::Px,
            _ => panic!("unrecognized unit")
        }
    }

    fn parse_color(&mut self) -> Value {
        assert_eq!(self.consume_char(), '#');
        Value::ColorValue(Color {
            r: self.parse_hex_pair(),
            g: self.parse_hex_pair(),
            b: self.parse_hex_pair(),
            a: 255 })
    }

    /// Parse two hexadecimal digits.
    fn parse_hex_pair(&mut self) -> u8 {
        let s = &self.input[self.pos .. self.pos + 2];
        self.pos += 2;
        u8::from_str_radix(s, 16).unwrap()
    }

    /// Parse a property name or keyword.
    fn parse_identifier(&mut self) -> String {
        self.consume_while(valid_identifier_char)
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(char::is_whitespace);
    }

    /// Consume characters until `test` returns false.
    fn consume_while<F>(&mut self, test: F) -> String
            where F: Fn(char) -> bool {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let mut iter = self.input[self.pos..].char_indices();
        let (_, cur_char) = iter.next().unwrap();
        let (next_pos, _) = iter.next().unwrap_or((1, ' '));
        self.pos += next_pos;
        cur_char
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input[self.pos..].chars().next().unwrap()
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => true, // TODO: Include U+00A0 and higher.
        _ => false,
    }
}
<commit_msg>Remove deprecated module<commit_after>//! A simple parser for a tiny subset of CSS.
//!
//! To support more CSS syntax, it would probably be easiest to replace this
//! hand-rolled parser with one based on a library or parser generator.

// Data structures:

#[derive(Debug)]
pub struct Stylesheet {
    pub rules: Vec<Rule>,
}

#[derive(Debug)]
pub struct Rule {
    pub selectors: Vec<Selector>,
    pub declarations: Vec<Declaration>,
}

#[derive(Debug)]
pub enum Selector {
    Simple(SimpleSelector),
}

#[derive(Debug)]
pub struct SimpleSelector {
    pub tag_name: Option<String>,
    pub id: Option<String>,
    pub class: Vec<String>,
}

#[derive(Debug)]
pub struct Declaration {
    pub name: String,
    pub value: Value,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Keyword(String),
    Length(f32, Unit),
    ColorValue(Color),
}

#[derive(Debug, Clone, PartialEq)]
pub enum Unit {
    Px,
}

#[derive(Debug, Clone, PartialEq, Default)]
pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
    pub a: u8,
}

impl Copy for Color {}

pub type Specificity = (usize, usize, usize);

impl Selector {
    pub fn specificity(&self) -> Specificity {
        // http://www.w3.org/TR/selectors/#specificity
        let Selector::Simple(ref simple) = *self;
        let a = simple.id.iter().count();
        let b = simple.class.len();
        let c = simple.tag_name.iter().count();
        (a, b, c)
    }
}

impl Value {
    /// Return the size of a length in px, or zero for non-lengths.
    pub fn to_px(&self) -> f32 {
        match *self {
            Value::Length(f, Unit::Px) => f,
            _ => 0.0
        }
    }
}

/// Parse a whole CSS stylesheet.
pub fn parse(source: String) -> Stylesheet {
    let mut parser = Parser { pos: 0, input: source };
    Stylesheet { rules: parser.parse_rules() }
}

struct Parser {
    pos: usize,
    input: String,
}

impl Parser {
    /// Parse a list of rule sets, separated by optional whitespace.
    fn parse_rules(&mut self) -> Vec<Rule> {
        let mut rules = Vec::new();
        loop {
            self.consume_whitespace();
            if self.eof() { break }
            rules.push(self.parse_rule());
        }
        rules
    }

    /// Parse a rule set: `<selectors> { <declarations> }`.
    fn parse_rule(&mut self) -> Rule {
        Rule {
            selectors: self.parse_selectors(),
            declarations: self.parse_declarations(),
        }
    }

    /// Parse a comma-separated list of selectors.
    fn parse_selectors(&mut self) -> Vec<Selector> {
        let mut selectors = Vec::new();
        loop {
            selectors.push(Selector::Simple(self.parse_simple_selector()));
            self.consume_whitespace();
            match self.next_char() {
                ',' => { self.consume_char(); self.consume_whitespace(); }
                '{' => break,
                c   => panic!("Unexpected character {} in selector list", c)
            }
        }
        // Return selectors with highest specificity first, for use in matching.
        selectors.sort_by(|a,b| b.specificity().cmp(&a.specificity()));
        selectors
    }

    /// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
    fn parse_simple_selector(&mut self) -> SimpleSelector {
        let mut selector = SimpleSelector { tag_name: None, id: None, class: Vec::new() };
        while !self.eof() {
            match self.next_char() {
                '#' => {
                    self.consume_char();
                    selector.id = Some(self.parse_identifier());
                }
                '.' => {
                    self.consume_char();
                    selector.class.push(self.parse_identifier());
                }
                '*' => {
                    // universal selector
                    self.consume_char();
                }
                c if valid_identifier_char(c) => {
                    selector.tag_name = Some(self.parse_identifier());
                }
                _ => break
            }
        }
        selector
    }

    /// Parse a list of declarations enclosed in `{ ... }`.
    fn parse_declarations(&mut self) -> Vec<Declaration> {
        assert_eq!(self.consume_char(), '{');
        let mut declarations = Vec::new();
        loop {
            self.consume_whitespace();
            if self.next_char() == '}' {
                self.consume_char();
                break;
            }
            declarations.push(self.parse_declaration());
        }
        declarations
    }

    /// Parse one `<property>: <value>;` declaration.
    fn parse_declaration(&mut self) -> Declaration {
        let property_name = self.parse_identifier();
        self.consume_whitespace();
        assert_eq!(self.consume_char(), ':');
        self.consume_whitespace();
        let value = self.parse_value();
        self.consume_whitespace();
        assert_eq!(self.consume_char(), ';');

        Declaration {
            name: property_name,
            value: value,
        }
    }

    // Methods for parsing values:

    fn parse_value(&mut self) -> Value {
        match self.next_char() {
            '0'...'9' => self.parse_length(),
            '#' => self.parse_color(),
            _ => Value::Keyword(self.parse_identifier())
        }
    }

    fn parse_length(&mut self) -> Value {
        Value::Length(self.parse_float(), self.parse_unit())
    }

    fn parse_float(&mut self) -> f32 {
        let s = self.consume_while(|c| match c {
            '0'...'9' | '.' => true,
            _ => false
        });
        s.parse().unwrap()
    }

    fn parse_unit(&mut self) -> Unit {
        match &*self.parse_identifier().to_ascii_lowercase() {
            "px" => Unit::Px,
            _ => panic!("unrecognized unit")
        }
    }

    fn parse_color(&mut self) -> Value {
        assert_eq!(self.consume_char(), '#');
        Value::ColorValue(Color {
            r: self.parse_hex_pair(),
            g: self.parse_hex_pair(),
            b: self.parse_hex_pair(),
            a: 255 })
    }

    /// Parse two hexadecimal digits.
    fn parse_hex_pair(&mut self) -> u8 {
        let s = &self.input[self.pos .. self.pos + 2];
        self.pos += 2;
        u8::from_str_radix(s, 16).unwrap()
    }

    /// Parse a property name or keyword.
    fn parse_identifier(&mut self) -> String {
        self.consume_while(valid_identifier_char)
    }

    /// Consume and discard zero or more whitespace characters.
    fn consume_whitespace(&mut self) {
        self.consume_while(char::is_whitespace);
    }

    /// Consume characters until `test` returns false.
    fn consume_while<F>(&mut self, test: F) -> String
            where F: Fn(char) -> bool {
        let mut result = String::new();
        while !self.eof() && test(self.next_char()) {
            result.push(self.consume_char());
        }
        result
    }

    /// Return the current character, and advance self.pos to the next character.
    fn consume_char(&mut self) -> char {
        let mut iter = self.input[self.pos..].char_indices();
        let (_, cur_char) = iter.next().unwrap();
        let (next_pos, _) = iter.next().unwrap_or((1, ' '));
        self.pos += next_pos;
        cur_char
    }

    /// Read the current character without consuming it.
    fn next_char(&self) -> char {
        self.input[self.pos..].chars().next().unwrap()
    }

    /// Return true if all input is consumed.
    fn eof(&self) -> bool {
        self.pos >= self.input.len()
    }
}

fn valid_identifier_char(c: char) -> bool {
    match c {
        'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' => true, // TODO: Include U+00A0 and higher.
        _ => false,
    }
}
<|endoftext|>


<commit_before>use pic::PIC_remap;
use stdio;
use utils::outb;

/* Defines an IDT entry */
#[packed]
struct IDTEntry {
    base_lo: u16,
    sel: u16,        /* Our kernel segment goes here! */
    zero: u8,        /* This will ALWAYS be set to 0! */
    flags: u8,       /* Set using the above table! */
    base_hi: u16
}

/* Defines an IDT pointer */
#[packed]
struct IDTPointer {
    limit: u16,
    base: u32
}

/* Declare an IDT of 256 entries. If any undefined IDT entry is hit,
 * it normally will cause an "Unhandled Interrupt" exception. Any
 * descriptor for which the 'presence' bit is cleared (0) will generate
 * an "Unhandled Interrupt" exception */

#[no_mangle]
pub static mut idt: [IDTEntry, ..256] = [IDTEntry {base_lo: 0, sel: 0, zero: 0, flags: 0, base_hi: 0}, ..256];

#[no_mangle]
pub static mut idtp: IDTPointer = IDTPointer {limit: 0, base: 0};

/* Use this function to set an entry in the IDT. A lot simpler
*  than twiddling with the GDT ;) */
#[no_mangle]
fn idt_set_gate(num: u8, f: extern "C" unsafe fn(), sel: u16, flags: u8)
{
    unsafe {
        let base = f as u32;
        idt[num].sel = sel;
        idt[num].flags = flags;
        idt[num].base_hi = (base >> 16) as u16;
        idt[num].base_lo = (base & ((1 << 16) - 1)) as u16;
    }
}

/* Installs the IDT */
extern {
    fn int_handler_kbd_wrapper ();
}

#[no_mangle]
pub unsafe fn idt_install() {
    /* Sets the special IDT pointer up  */
    idtp.limit = ((super::core::mem::size_of::<IDTEntry>() * 256) - 1) as u16;
    idtp.base = &idt as *[IDTEntry, ..256] as u32;

    /* Add any new ISRs to the IDT here using idt_set_gate */
    idt_set_gate(33, int_handler_kbd_wrapper, 0x08, 0x8E);

    /* Remap the PIC */
    PIC_remap();

    outb(0x21,0xfd); // Keyboard interrupts only
    outb(0xa1,0xff);

    /* Turn interrupts on */
    asm!("lidt ($0)" :: "r" (idtp));
    asm!("sti");
}

<commit_msg>Whitespace test for Travis<commit_after>use pic::PIC_remap;
use stdio;
use utils::outb;

/* Defines an IDT entry */
#[packed]
struct IDTEntry {
    base_lo: u16,
    sel: u16,        /* Our kernel segment goes here! */
    zero: u8,        /* This will ALWAYS be set to 0! */
    flags: u8,       /* Set using the above table! */
    base_hi: u16
}

/* Defines an IDT pointer */
#[packed]
struct IDTPointer {
    limit: u16,
    base: u32
}

/* Declare an IDT of 256 entries. If any undefined IDT entry is hit,
 * it normally will cause an "Unhandled Interrupt" exception. Any
 * descriptor for which the 'presence' bit is cleared (0) will generate
 * an "Unhandled Interrupt" exception */

#[no_mangle]
pub static mut idt: [IDTEntry, ..256] = [IDTEntry {base_lo: 0, sel: 0, zero: 0, flags: 0, base_hi: 0}, ..256];

#[no_mangle]
pub static mut idtp: IDTPointer = IDTPointer {limit: 0, base: 0};

/* Use this function to set an entry in the IDT. A lot simpler
*  than twiddling with the GDT ;) */
#[no_mangle]
fn idt_set_gate(num: u8, f: extern "C" unsafe fn(), sel: u16, flags: u8)
{
    unsafe {
        let base = f as u32;
        idt[num].sel = sel;
        idt[num].flags = flags;
        idt[num].base_hi = (base >> 16) as u16;
        idt[num].base_lo = (base & ((1 << 16) - 1)) as u16;
    }
}

/* Installs the IDT */
extern {
    fn int_handler_kbd_wrapper ();
}

#[no_mangle]
pub unsafe fn idt_install() {
    /* Sets the special IDT pointer up  */
    idtp.limit = ((super::core::mem::size_of::<IDTEntry>() * 256) - 1) as u16;
    idtp.base = &idt as *[IDTEntry, ..256] as u32;

    /* Add any new ISRs to the IDT here using idt_set_gate */
    idt_set_gate(33, int_handler_kbd_wrapper, 0x08, 0x8E);

    /* Remap the PIC */
    PIC_remap();

    outb(0x21,0xfd); // Keyboard interrupts only
    outb(0xa1,0xff);

    /* Turn interrupts on */
    asm!("lidt ($0)" :: "r" (idtp));
    asm!("sti");
}

<|endoftext|>


<commit_before>extern crate nalgebra;
use self::nalgebra::*;
use central_body::*;
use csv::*;
use std::rc::*;
use tick::*;

// Keplerian Orbital Elements
#[derive(Clone, Debug)]
pub struct KOE {
    pub a: f64,
    pub e: f64,
    pub inc: f64,
    pub lan: f64,
    pub ap: f64,
    pub m0: f64, // Mean anomaly
    pub cb: Rc<CentralBody>,
}

impl Tick for KOE {
    fn tick(&self, dt: f64) -> Self {
        let n = (self.cb.mu/self.a.powf(3.0)).sqrt();
        KOE::new(
            self.a,
            self.e,
            self.inc,
            self.lan,
            self.ap,
            self.m0 + n * dt,
            self.cb.clone()
        )
    }
}

impl KOE {
    pub fn new(a: f64, e: f64, inc: f64, lan: f64, ap: f64, m0: f64, cb: Rc<CentralBody>) -> KOE {
        KOE {
            a: a,
            e: e,
            inc: inc,
            lan: lan,
            ap: ap,
            m0: m0,
            cb: cb,
        }
    }

    pub fn approx_eq(&self, other: &KOE) -> bool {
        let eps = 1.0e-5;
        approx_eq_eps(&self.a, &other.a, &eps) &&
        approx_eq_eps(&self.e, &other.e, &eps) &&
        approx_eq_eps(&self.inc, &other.inc, &eps) &&
        approx_eq_eps(&self.lan, &other.lan, &eps) &&
        approx_eq_eps(&self.ap, &other.ap, &eps) &&
        approx_eq_eps(&self.m0, &other.m0, &eps) &&
        self.cb.approx_eq(&other.cb)
    }

    pub fn approx_eq_eps(&self, other: &KOE, eps: &f64) -> bool {
        approx_eq_eps(&self.a, &other.a, &eps) &&
        approx_eq_eps(&self.e, &other.e, &eps) &&
        approx_eq_eps(&self.inc, &other.inc, &eps) &&
        approx_eq_eps(&self.lan, &other.lan, &eps) &&
        approx_eq_eps(&self.ap, &other.ap, &eps) &&
        approx_eq_eps(&self.m0, &other.m0, &eps) &&
        self.cb.approx_eq(&other.cb)
    }

    pub fn to_csv(&self) -> CSV {
        let m0 = self.m0;
        let iterations = 10;
        let ea = KOE::newton_raphson(&m0, &self.e, &iterations);
        let ta = 2.0*((1.0+self.e).sqrt()*(ea/2.0).sin())
            .atan2((1.0-self.e).sqrt()*(ea/2.0).cos());
        let dist = self.a*(1.0-self.e*ea.cos());
        let mut r = (self.cb.reference*ta.cos() + self.cb.right*ta.sin()) * dist;
        let mut v = (self.cb.reference*(-ea.sin()) +
                    self.cb.right*((1.0-self.e.powf(2.0)).sqrt()*ea.cos())) * ((self.cb.mu*self.a).sqrt()/dist);
        let mut rot = Rot3::new_identity(3);
        if approx_eq(&self.inc, &0.0) {
            if !approx_eq(&self.e, &0.0) {
                rot = Rot3::new(self.cb.up * self.ap);
            }
        } else {
            let lan_axisangle = self.cb.up * self.lan;
            let inc_axisangle = self.cb.reference * self.inc;
            let ap_axisangle = self.cb.up * self.ap;
            rot = Rot3::new(lan_axisangle);
            rot = rot.prepend_rotation(&inc_axisangle);
            if !approx_eq(&self.e, &0.0) {
                rot = rot.prepend_rotation(&ap_axisangle);
            }
        }
        r = rot.transform(&r);
        v = rot.transform(&v);
        CSV::new(r, v, self.cb.clone())
    }

    fn newton_raphson(m0: &f64, e: &f64, iterations: &i32) -> f64 {
        let mut ea = m0.clone();
        for _ in 0..*iterations {
            ea  = ea - (ea - e*ea.sin() - m0)/(1.0 - e*ea.cos());
        }
        ea
    }
}
<commit_msg>Don't recompute the rotation matrix for every to_csv call<commit_after>extern crate nalgebra;
use self::nalgebra::*;
use central_body::*;
use csv::*;
use std::rc::*;
use tick::*;

// Keplerian Orbital Elements
#[derive(Clone, Debug)]
pub struct KOE {
    pub a: f64,
    pub e: f64,
    pub inc: f64,
    pub lan: f64,
    pub ap: f64,
    pub m0: f64, // Mean anomaly
    pub cb: Rc<CentralBody>,
    pub to_csv_rot: Rot3<f64>,
}

impl Tick for KOE {
    fn tick(&self, dt: f64) -> Self {
        let n = (self.cb.mu/self.a.powf(3.0)).sqrt();
        KOE {
            a: self.a,
            e: self.e,
            inc: self.inc,
            lan: self.lan,
            ap: self.ap,
            m0: self.m0 + n * dt,
            cb: self.cb.clone(),
            to_csv_rot: self.to_csv_rot,
        }
    }
}

impl KOE {
    pub fn new(a: f64, e: f64, inc: f64, lan: f64, ap: f64, m0: f64, cb: Rc<CentralBody>) -> KOE {
        let mut rot = Rot3::new_identity(3);
        if approx_eq(&inc, &0.0) {
            if !approx_eq(&e, &0.0) {
                rot = Rot3::new(cb.up * ap);
            }
        } else {
            let lan_axisangle = cb.up * lan;
            let inc_axisangle = cb.reference * inc;
            let ap_axisangle = cb.up * ap;
            rot = Rot3::new(lan_axisangle);
            rot = rot.prepend_rotation(&inc_axisangle);
            if !approx_eq(&e, &0.0) {
                rot = rot.prepend_rotation(&ap_axisangle);
            }
        }
        KOE {
            a: a,
            e: e,
            inc: inc,
            lan: lan,
            ap: ap,
            m0: m0,
            cb: cb,
            to_csv_rot: rot,
        }
    }

    pub fn approx_eq(&self, other: &KOE) -> bool {
        let eps = 1.0e-5;
        approx_eq_eps(&self.a, &other.a, &eps) &&
        approx_eq_eps(&self.e, &other.e, &eps) &&
        approx_eq_eps(&self.inc, &other.inc, &eps) &&
        approx_eq_eps(&self.lan, &other.lan, &eps) &&
        approx_eq_eps(&self.ap, &other.ap, &eps) &&
        approx_eq_eps(&self.m0, &other.m0, &eps) &&
        self.cb.approx_eq(&other.cb)
    }

    pub fn approx_eq_eps(&self, other: &KOE, eps: &f64) -> bool {
        approx_eq_eps(&self.a, &other.a, &eps) &&
        approx_eq_eps(&self.e, &other.e, &eps) &&
        approx_eq_eps(&self.inc, &other.inc, &eps) &&
        approx_eq_eps(&self.lan, &other.lan, &eps) &&
        approx_eq_eps(&self.ap, &other.ap, &eps) &&
        approx_eq_eps(&self.m0, &other.m0, &eps) &&
        self.cb.approx_eq(&other.cb)
    }

    pub fn to_csv(&self) -> CSV {
        let m0 = self.m0;
        let iterations = 10;
        let ea = KOE::newton_raphson(&m0, &self.e, &iterations);
        let ta = 2.0*((1.0+self.e).sqrt()*(ea/2.0).sin())
            .atan2((1.0-self.e).sqrt()*(ea/2.0).cos());
        let dist = self.a*(1.0-self.e*ea.cos());
        let mut r = (self.cb.reference*ta.cos() + self.cb.right*ta.sin()) * dist;
        let mut v = (self.cb.reference*(-ea.sin()) +
                    self.cb.right*((1.0-self.e.powf(2.0)).sqrt()*ea.cos())) * ((self.cb.mu*self.a).sqrt()/dist);
        r = self.to_csv_rot.transform(&r);
        v = self.to_csv_rot.transform(&v);
        CSV::new(r, v, self.cb.clone())
    }

    fn newton_raphson(m0: &f64, e: &f64, iterations: &i32) -> f64 {
        let mut ea = m0.clone();
        for _ in 0..*iterations {
            ea  = ea - (ea - e*ea.sin() - m0)/(1.0 - e*ea.cos());
        }
        ea
    }
}
<|endoftext|>


<commit_before>use std::iter;

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Position {
  pub offset: usize,
  pub line: usize,
  pub column: usize,
}

impl Position {
  pub fn new(offset: usize, line: usize, column: usize) -> Self {
    Position{
      offset: offset,
      line: line,
      column: column,
    }
  }

  pub fn zero() -> Self {
    Position::new(0, 1, 1)
  }

  pub fn advance(&mut self, char: char) {
    self.offset += 1;
    if char == '\n' {
      self.line += 1;
      self.column = 1;
    } else {
      self.column += 1;
    }
  }
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Lexeme<'a, T>(pub T, pub LexemeF<'a>);

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LexemeF<'a> {
  Identifier(&'a str),

  Arrow,
  LeftParenthesis,
  RightParenthesis,
  LeftBrace,
  RightBrace,
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Lexer<'a> {
  input: &'a str,
  position: Position,
  abort: bool,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Self {
    Lexer{input: input, position: Position::zero(), abort: false}
  }

  pub fn next_position(&self) -> Position {
    self.position
  }

  fn peek_char(&self) -> Option<char> {
    self.input.chars().next()
  }

  fn take_char(&mut self) -> Option<char> {
    let mut chars = self.input.chars();
    let result = chars.next();
    for c in result {
      self.position.advance(c);
    }
    self.input = chars.as_str();
    result
  }

  fn take_chars_while<F>(&mut self, pred: F) -> &'a str
    where F: Fn(char) -> bool {
    let terminator = (self.input.len(), '\n');
    let mut len = 0;
    for (i, c) in self.input.char_indices().chain(iter::once(terminator)) {
      len = i;
      if !pred(c) {
        break;
      }
      self.position.advance(c);
    }
    let result = unsafe { self.input.slice_unchecked(0, len) };
    self.input = unsafe { self.input.slice_unchecked(len, self.input.len()) };
    result
  }
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Lexeme<'a, Position>, Position>;

  fn next(&mut self) -> Option<Self::Item> {
    if self.abort {
      return None;
    }
    self.take_chars_while(is_whitespace);
    let position = self.position;
    match self.peek_char() {
      None =>
        None,
      Some('(') => {
        self.take_char();
        Some(Ok(Lexeme(position, LexemeF::LeftParenthesis)))
      },
      Some(')') => {
        self.take_char();
        Some(Ok(Lexeme(position, LexemeF::RightParenthesis)))
      },
      Some('{') => {
        self.take_char();
        Some(Ok(Lexeme(position, LexemeF::LeftBrace)))
      },
      Some('}') => {
        self.take_char();
        Some(Ok(Lexeme(position, LexemeF::RightBrace)))
      },
      Some('-') => {
        self.take_char();
        if self.peek_char() == Some('>') {
          self.take_char();
          Some(Ok(Lexeme(position, LexemeF::Arrow)))
        } else {
          self.abort = true;
          Some(Err(position))
        }
      },
      Some(c) if is_identifier_start(c) => {
        let name = self.take_chars_while(is_identifier_continue);
        Some(Ok(Lexeme(position, LexemeF::Identifier(name))))
      },
      Some(_) => {
        self.abort = true;
        Some(Err(position))
      },
    }
  }
}

fn is_whitespace(char: char) -> bool {
  char.is_whitespace()
}

// FIXME: Switch to is_xid_start once it is stable.
fn is_identifier_start(char: char) -> bool {
  char.is_alphabetic()
  || char == '_'
}

// FIXME: Switch to is_xid_continue once it is stable.
fn is_identifier_continue(char: char) -> bool {
  is_identifier_start(char)
  || char.is_numeric()
  || char == '\''
}

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

  #[test]
  fn test_empty() {
    assert_eq!(
      Lexer::new("").collect::<Vec<_>>(),
      vec![]
    );
  }

  #[test]
  fn test_whitespace() {
    assert_eq!(
      Lexer::new(" \t\r\n").collect::<Vec<_>>(),
      vec![]
    );
  }

  #[test]
  fn test_identifier() {
    assert_eq!(
      Lexer::new("a").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("a")))]
    );
    assert_eq!(
      Lexer::new("ab").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab")))]
    );
    assert_eq!(
      Lexer::new("ab_c").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab_c")))]
    );
    assert_eq!(
      Lexer::new("ab_cd'").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab_cd'")))]
    );
  }

  #[test]
  fn test_identifiers() {
    assert_eq!(
      Lexer::new("ab cd").collect::<Vec<_>>(),
      vec![
        Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab"))),
        Ok(Lexeme(Position::new(3, 1, 4), LexemeF::Identifier("cd"))),
      ]
    );
  }

  #[test]
  fn test_punctuation() {
    assert_eq!(
      Lexer::new("(){}->").collect::<Vec<_>>(),
      vec![
        Ok(Lexeme(Position::new(0, 1, 1), LexemeF::LeftParenthesis)),
        Ok(Lexeme(Position::new(1, 1, 2), LexemeF::RightParenthesis)),
        Ok(Lexeme(Position::new(2, 1, 3), LexemeF::LeftBrace)),
        Ok(Lexeme(Position::new(3, 1, 4), LexemeF::RightBrace)),
        Ok(Lexeme(Position::new(4, 1, 5), LexemeF::Arrow)),
      ]
    );
  }
}
<commit_msg>Add fun and end keywords instead of braces<commit_after>use std::iter;

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Position {
  pub offset: usize,
  pub line: usize,
  pub column: usize,
}

impl Position {
  pub fn new(offset: usize, line: usize, column: usize) -> Self {
    Position{
      offset: offset,
      line: line,
      column: column,
    }
  }

  pub fn zero() -> Self {
    Position::new(0, 1, 1)
  }

  pub fn advance(&mut self, char: char) {
    self.offset += 1;
    if char == '\n' {
      self.line += 1;
      self.column = 1;
    } else {
      self.column += 1;
    }
  }
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Lexeme<'a, T>(pub T, pub LexemeF<'a>);

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LexemeF<'a> {
  Identifier(&'a str),

  Fun,
  End,

  Arrow,
  LeftParenthesis,
  RightParenthesis,
}

#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Lexer<'a> {
  input: &'a str,
  position: Position,
  abort: bool,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Self {
    Lexer{input: input, position: Position::zero(), abort: false}
  }

  pub fn next_position(&self) -> Position {
    self.position
  }

  fn peek_char(&self) -> Option<char> {
    self.input.chars().next()
  }

  fn take_char(&mut self) -> Option<char> {
    let mut chars = self.input.chars();
    let result = chars.next();
    for c in result {
      self.position.advance(c);
    }
    self.input = chars.as_str();
    result
  }

  fn take_chars_while<F>(&mut self, pred: F) -> &'a str
    where F: Fn(char) -> bool {
    let terminator = (self.input.len(), '\n');
    let mut len = 0;
    for (i, c) in self.input.char_indices().chain(iter::once(terminator)) {
      len = i;
      if !pred(c) {
        break;
      }
      self.position.advance(c);
    }
    let result = unsafe { self.input.slice_unchecked(0, len) };
    self.input = unsafe { self.input.slice_unchecked(len, self.input.len()) };
    result
  }
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Lexeme<'a, Position>, Position>;

  fn next(&mut self) -> Option<Self::Item> {
    if self.abort {
      return None;
    }
    self.take_chars_while(is_whitespace);
    let position = self.position;
    match self.peek_char() {
      None =>
        None,
      Some('(') => {
        self.take_char();
        Some(Ok(Lexeme(position, LexemeF::LeftParenthesis)))
      },
      Some(')') => {
        self.take_char();
        Some(Ok(Lexeme(position, LexemeF::RightParenthesis)))
      },
      Some('-') => {
        self.take_char();
        if self.peek_char() == Some('>') {
          self.take_char();
          Some(Ok(Lexeme(position, LexemeF::Arrow)))
        } else {
          self.abort = true;
          Some(Err(position))
        }
      },
      Some(c) if is_identifier_start(c) => {
        let name = self.take_chars_while(is_identifier_continue);
        Some(Ok(Lexeme(position, match name {
          "fun" => LexemeF::Fun,
          "end" => LexemeF::End,
          _ => LexemeF::Identifier(name),
        })))
      },
      Some(_) => {
        self.abort = true;
        Some(Err(position))
      },
    }
  }
}

fn is_whitespace(char: char) -> bool {
  char.is_whitespace()
}

// FIXME: Switch to is_xid_start once it is stable.
fn is_identifier_start(char: char) -> bool {
  char.is_alphabetic()
  || char == '_'
}

// FIXME: Switch to is_xid_continue once it is stable.
fn is_identifier_continue(char: char) -> bool {
  is_identifier_start(char)
  || char.is_numeric()
  || char == '\''
}

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

  #[test]
  fn test_empty() {
    assert_eq!(
      Lexer::new("").collect::<Vec<_>>(),
      vec![]
    );
  }

  #[test]
  fn test_whitespace() {
    assert_eq!(
      Lexer::new(" \t\r\n").collect::<Vec<_>>(),
      vec![]
    );
  }

  #[test]
  fn test_identifier() {
    assert_eq!(
      Lexer::new("a").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("a")))]
    );
    assert_eq!(
      Lexer::new("ab").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab")))]
    );
    assert_eq!(
      Lexer::new("ab_c").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab_c")))]
    );
    assert_eq!(
      Lexer::new("ab_cd'").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab_cd'")))]
    );
    assert_eq!(
      Lexer::new("funend").collect::<Vec<_>>(),
      vec![Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("funend")))]
    );
  }

  #[test]
  fn test_identifiers() {
    assert_eq!(
      Lexer::new("ab cd").collect::<Vec<_>>(),
      vec![
        Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Identifier("ab"))),
        Ok(Lexeme(Position::new(3, 1, 4), LexemeF::Identifier("cd"))),
      ]
    );
  }

  #[test]
  fn test_keywords() {
    assert_eq!(
      Lexer::new("fun end").collect::<Vec<_>>(),
      vec![
        Ok(Lexeme(Position::new(0, 1, 1), LexemeF::Fun)),
        Ok(Lexeme(Position::new(4, 1, 5), LexemeF::End)),
      ]
    );
  }

  #[test]
  fn test_punctuation() {
    assert_eq!(
      Lexer::new("()->").collect::<Vec<_>>(),
      vec![
        Ok(Lexeme(Position::new(0, 1, 1), LexemeF::LeftParenthesis)),
        Ok(Lexeme(Position::new(1, 1, 2), LexemeF::RightParenthesis)),
        Ok(Lexeme(Position::new(2, 1, 3), LexemeF::Arrow)),
      ]
    );
  }
}
<|endoftext|>


<commit_before>//! Implementation of the Micro Transport Protocol.[^spec]
//!
//! [^spec]: http://www.bittorrent.org/beps/bep_0029.html

//! # Examples
//!
//! ```no_run
//! extern crate utp;
//!
//! use utp::UtpStream;
//! use std::io::{Read, Write};
//!
//! fn main() {
//!     // Connect to an hypothetical local server running on port 8080
//!     let addr = "127.0.0.1:8080";
//!     let mut stream = match UtpStream::connect(addr) {
//!         Ok(stream) => stream,
//!         Err(e) => panic!("{}", e),
//!     };
//!
//!     // Send a string
//!     match stream.write("Hi there!".as_bytes()) {
//!         Ok(_) => (),
//!         Err(e) => println!("Write failed with {}", e)
//!     }
//!
//!     // Close the stream
//!     match stream.close() {
//!         Ok(()) => println!("Connection closed"),
//!         Err(e) => println!("{}", e)
//!     }
//! }
//! ```

//   __________  ____  ____
//  /_  __/ __ \/ __ \/ __ \
//   / / / / / / / / / / / /
//  / / / /_/ / /_/ / /_/ /
// /_/  \____/_____/\____/
//
// - Lossy UDP socket for testing purposes: send and receive ops are wrappers
// that stochastically drop or reorder packets.
// - Sending FIN on drop
// - Handle packet loss
// - Path MTU discovery (RFC4821)

#![deny(missing_docs)]
#![feature(core, collections, old_io)]

extern crate rand;
extern crate time;
extern crate num;
#[macro_use] extern crate log;

// Public API
pub use socket::UtpSocket;
pub use stream::UtpStream;

mod util;
mod bit_iterator;
mod packet;
mod socket;
mod stream;
<commit_msg>Remove unstable features.<commit_after>//! Implementation of the Micro Transport Protocol.[^spec]
//!
//! [^spec]: http://www.bittorrent.org/beps/bep_0029.html

//! # Examples
//!
//! ```no_run
//! extern crate utp;
//!
//! use utp::UtpStream;
//! use std::io::{Read, Write};
//!
//! fn main() {
//!     // Connect to an hypothetical local server running on port 8080
//!     let addr = "127.0.0.1:8080";
//!     let mut stream = match UtpStream::connect(addr) {
//!         Ok(stream) => stream,
//!         Err(e) => panic!("{}", e),
//!     };
//!
//!     // Send a string
//!     match stream.write("Hi there!".as_bytes()) {
//!         Ok(_) => (),
//!         Err(e) => println!("Write failed with {}", e)
//!     }
//!
//!     // Close the stream
//!     match stream.close() {
//!         Ok(()) => println!("Connection closed"),
//!         Err(e) => println!("{}", e)
//!     }
//! }
//! ```

//   __________  ____  ____
//  /_  __/ __ \/ __ \/ __ \
//   / / / / / / / / / / / /
//  / / / /_/ / /_/ / /_/ /
// /_/  \____/_____/\____/
//
// - Lossy UDP socket for testing purposes: send and receive ops are wrappers
// that stochastically drop or reorder packets.
// - Sending FIN on drop
// - Handle packet loss
// - Path MTU discovery (RFC4821)

#![deny(missing_docs)]

extern crate rand;
extern crate time;
extern crate num;
#[macro_use] extern crate log;

// Public API
pub use socket::UtpSocket;
pub use stream::UtpStream;

mod util;
mod bit_iterator;
mod packet;
mod socket;
mod stream;
<|endoftext|>