<commit_before>#![feature(custom_derive, plugin, stmt_expr_attributes)]
#![plugin(serde_macros, clippy)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces, unused_qualifications,
        warnings, clippy)]

//! Serializes and psudo-deserializes structs implementing the Error trait. This should only be done if you know you won't ever need an actual error value, only the description and causes.
//!
//! This crate assumes that the error descriptions are complete, and are indicative of the error going on.
//! There is also no way to get any values accoated with the error, since that would require real serialization of arbratrary structs, implementing a trait you didn't make.
//!
//! #Examples
//!
//! ```
//! use std::convert::From;
//! use std::fmt::Error;
//! use errorser::serialize_error_string;
//!
//! let error = Error;
//! let errser = serialize_error_string(&error);
//! assert_eq!(errser, "???");
//! ```

extern crate bincode;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;

mod real_error_impls;

use std::convert::{From, AsRef};
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

use bincode::SizeLimit;
use bincode::serde::serialize as bin_serialize;
use serde_json::to_string as json_serialize;

/// An error that can be serialized by serde or rustc_seralize.
#[derive(Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub enum SeralizableError {
    /// If the error is commonly used, such as something from std, some of it's fields may be preserved. This variant represents these kinds of errors.
    RealError(real_error_impls::RealError),
    /// If the error isn't in std or isn't common, it is automatically made a PseudoError, loosing it's fields.
    PseudoError(PseudoError),
}

impl Display for SeralizableError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => write!(fmt, "{}", perr),
        }
    }
}

impl<'a> From<&'a Error> for SeralizableError {
    fn from(err: &Error) -> SeralizableError {
        // TODO: Check if can be seralized as RealError.
        SeralizableError::PseudoError(PseudoError::from(err))
    }
}

impl Error for SeralizableError {
    fn description(&self) -> &str {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.description(),
        }
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.cause(),
        }
    }
}

/// An error that has been made seralization-capable, but has lost it's fields, due to incompatibility with the library or preserving fields being unnesacary.
///
/// See the crate root for more info.
#[derive(Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub struct PseudoError {
    cause: Option<Box<PseudoError>>,
    desc: String,
}

impl Display for PseudoError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.desc)
    }
}

impl<'a> From<&'a Error> for PseudoError {
    fn from(err: &Error) -> PseudoError {
        PseudoError {
            cause: err.cause().map(|cause| Box::new(PseudoError::from(cause))), /* In prevous versions of this line, it was almost lisp with the number of close perens here. */
            desc: err.description().to_owned(),
        }
    }
}

impl Error for PseudoError {
    fn description(&self) -> &str {
        &self.desc
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|cause| &**cause as &Error)    // Good luck. Also &**cause looks like it's cencoring profanity. Kinda feels like it would too, with how complacated it is.
        // Actually, I'm not that mean, I'll try to explain.

        // So cause.as_ref is Option::as_ref, turning Option<Box<PseudoError>> into Option<&Box<PseudoError>>.
        // Mapping lets me take an &Box<_>.
        // &**cause is best read right to left. The transforms work like this:
        // &Box<_> -> Box<_> -> _ -> &PseudoError
        // From there it's just &PseudoError as &Error.
    }
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_bytes.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_bytes;
///
/// let error = Error;
/// let errser = serialize_error_bytes(&error);
/// assert_eq!(errser, [0, 1]);
/// ```
pub fn serialize_error_bytes(to_ser: &Error) -> Vec<u8> {
    bin_serialize(&PseudoError::from(to_ser), SizeLimit::Infinite).unwrap()
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_string.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_string;
///
/// let error = Error;
/// let errser = serialize_error_string(&error);
/// assert_eq!(errser, "???");
/// ```
pub fn serialize_error_string(to_ser: &Error) -> String {
    json_serialize(&PseudoError::from(to_ser)).unwrap()
}

#[cfg(test)]
mod test {
    #[test]
    fn serialize_error_bytes() {}
}
<commit_msg>Make serialization methods use SeralizableError instead of PseudoError<commit_after>#![feature(custom_derive, plugin, stmt_expr_attributes)]
#![plugin(serde_macros, clippy)]
#![deny(missing_docs,
        missing_debug_implementations, missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unsafe_code,
        unused_import_braces, unused_qualifications,
        warnings, clippy)]

//! Serializes and psudo-deserializes structs implementing the Error trait. This should only be done if you know you won't ever need an actual error value, only the description and causes.
//!
//! This crate assumes that the error descriptions are complete, and are indicative of the error going on.
//! There is also no way to get any values accoated with the error, since that would require real serialization of arbratrary structs, implementing a trait you didn't make.
//!
//! #Examples
//!
//! ```
//! use std::convert::From;
//! use std::fmt::Error;
//! use errorser::serialize_error_string;
//!
//! let error = Error;
//! let errser = serialize_error_string(&error);
//! assert_eq!(errser, "???");
//! ```

extern crate bincode;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;

mod real_error_impls;

use std::convert::{From, AsRef};
use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};

use bincode::SizeLimit;
use bincode::serde::serialize as bin_serialize;
use serde_json::to_string as json_serialize;

/// An error that can be serialized by serde or rustc_seralize.
#[derive(Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub enum SeralizableError {
    /// If the error is commonly used, such as something from std, some of it's fields may be preserved. This variant represents these kinds of errors.
    RealError(real_error_impls::RealError),
    /// If the error isn't in std or isn't common, it is automatically made a PseudoError, loosing it's fields.
    PseudoError(PseudoError),
}

impl Display for SeralizableError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => write!(fmt, "{}", perr),
        }
    }
}

impl<'a> From<&'a Error> for SeralizableError {
    fn from(err: &Error) -> SeralizableError {
        // TODO: Check if can be seralized as RealError.
        SeralizableError::PseudoError(PseudoError::from(err))
    }
}

impl Error for SeralizableError {
    fn description(&self) -> &str {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.description(),
        }
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        use SeralizableError::*;
        match *self {
            RealError(ref _rerr) => unimplemented!(),
            PseudoError(ref perr) => perr.cause(),
        }
    }
}

/// An error that has been made seralization-capable, but has lost it's fields, due to incompatibility with the library or preserving fields being unnesacary.
///
/// See the crate root for more info.
#[derive(Serialize, Deserialize, Debug, RustcEncodable, RustcDecodable)]
pub struct PseudoError {
    cause: Option<Box<PseudoError>>,
    desc: String,
}

impl Display for PseudoError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.desc)
    }
}

impl<'a> From<&'a Error> for PseudoError {
    fn from(err: &Error) -> PseudoError {
        PseudoError {
            cause: err.cause().map(|cause| Box::new(PseudoError::from(cause))), /* In prevous versions of this line, it was almost lisp with the number of close perens here. */
            desc: err.description().to_owned(),
        }
    }
}

impl Error for PseudoError {
    fn description(&self) -> &str {
        &self.desc
    }

    #[allow(trivial_casts)]
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|cause| &**cause as &Error)    // Good luck. Also &**cause looks like it's cencoring profanity. Kinda feels like it would too, with how complacated it is.
        // Actually, I'm not that mean, I'll try to explain.

        // So cause.as_ref is Option::as_ref, turning Option<Box<PseudoError>> into Option<&Box<PseudoError>>.
        // Mapping lets me take an &Box<_>.
        // &**cause is best read right to left. The transforms work like this:
        // &Box<_> -> Box<_> -> _ -> &PseudoError
        // From there it's just &PseudoError as &Error.
    }
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_bytes.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_bytes;
///
/// let error = Error;
/// let errser = serialize_error_bytes(&error);
/// assert_eq!(errser, [0, 1]);
/// ```
pub fn serialize_error_bytes(to_ser: &Error) -> Vec<u8> {
    bin_serialize(&SeralizableError::from(to_ser), SizeLimit::Infinite).unwrap()
}

/// Serializes any type implementing Error to a string that can be deseralized with deserialize_string.
///
/// #Examples
///
/// ```
/// use std::convert::From;
/// use std::fmt::Error;
/// use errorser::serialize_error_string;
///
/// let error = Error;
/// let errser = serialize_error_string(&error);
/// assert_eq!(errser, "???");
/// ```
pub fn serialize_error_string(to_ser: &Error) -> String {
    json_serialize(&SeralizableError::from(to_ser)).unwrap()
}

#[cfg(test)]
mod test {
    #[test]
    fn serialize_error_bytes() {}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Asynchronous GUI library based on GTK+.
//!
//! This library provides a [`Widget`](trait.Widget.html) trait that you can use to create asynchronous GUI components.
//! This is the trait you will need to implement for your application.
//! It helps you to implement MVC (Model, View, Controller) in an elegant way.
//!
//! ## Installation
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! gtk = "^0.3.0"
//! relm = "^0.11.0"
//! relm-derive = "^0.11.0"
//! ```
//!
//! More info can be found in the [readme](https://github.com/antoyo/relm#relm).

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

/*
 * TODO: maybe remove SimpleMsg.
 *
 * TODO: improve README so that examples can be copy/pasted.
 * TODO: add tests for relm-derive-state.
 *
 * FIXME: some relm widgets requires { and } (see the rusic music-player) while other do not.
 * FIXME: should not require to import WidgetExt because it calls show().
 * FIXME: cannot have relm event with tuple as a value like:
 * RelmWidget {
 *     RelmEvent((value1, value2)) => …
 * }
 * TODO: use pub(crate) instead of pub so that we're not bound to make the model and msg structs pub.
 *
 * TODO: add init() method to the Widget (or Update) trait as a shortcut for init::<Widget>()?
 *
 * TODO: alternative to tokio with a trait to get FD and add this FD to glib (perhaps using a
 * GSource).
 * For timers, add a connect_timeout!() macro or something.
 *
 * TODO: show a warning when a component is imediately destroyed.
 * FIXME: cannot add a trailing coma at the end of a initializer list.
 * TODO: switch from gtk::main() to MainLoop to avoid issues with nested loops.
 * TODO: prefix generated container name with _ to hide warnings.
 * TODO: remove the code generation related to using self in event handling.
 * TODO: remove the closure transformer code.
 *
 * TODO: move most of the examples in the tests/ directory.
 * TODO: add construct-only properties for relm widget (to replace initial parameters) to allow
 * setting them by name (or with default value).
 * TODO: find a way to do two-step initialization (to avoid using unitialized in model()).
 * TODO: consider using GBinding instead of manually adding calls to set_property().
 *
 * TODO: add a FAQ with the question related to getting an error when not importing the gtk traits.
 *
 * TODO: show a warning when components are destroyed after the end of call to Widget::view().
 * TODO: warn in the attribute when an event cycle is found.
 * TODO: add a Deref<Widget> for Component?
 * TODO: look at how Elm works with the <canvas> element.
 * TODO: the widget names should start with __relm_field_.
 *
 * TODO: reset widget name counters when creating new widget?
 *
 * TODO: refactor the code.
 *
 * TODO: chat client/server example.
 *
 * TODO: err if trying to use the SimpleMsg custom derive on stable.
 *
 * TODO: add default type of () for Model in Widget when it is stable.
 * TODO: optionnaly multi-threaded.
 */

extern crate cairo;
extern crate glib;
extern crate gobject_sys;
extern crate gtk;
extern crate relm_core;
extern crate relm_state;

mod component;
mod container;
mod drawing;
mod macros;
#[doc(hidden)]
pub mod vendor;
mod widget;

#[doc(hidden)]
pub use glib::Cast;
#[doc(hidden)]
pub use glib::object::Downcast;
#[doc(hidden)]
pub use glib::translate::{FromGlibPtrNone, ToGlib, ToGlibPtr};
#[doc(hidden)]
pub use gobject_sys::{GParameter, g_object_newv};
use gtk::Continue;
#[doc(hidden)]
pub use relm_core::{Channel, EventStream, Sender};
pub use relm_state::{
    DisplayVariant,
    IntoOption,
    IntoPair,
    Relm,
    Update,
    UpdateNew,
    execute,
};
use relm_state::init_component;

pub use component::Component;
pub use container::{Container, ContainerComponent, ContainerWidget};
pub use drawing::DrawHandler;
pub use widget::{Widget, WidgetTest};

/// Dummy macro to be used with `#[derive(Widget)]`.
#[macro_export]
macro_rules! impl_widget {
    ($($tt:tt)*) => {
        ()
    };
}

/// Macro to be used as a stable alternative to the `#[widget]` attribute.
///
/// An example can be found [here](https://github.com/antoyo/relm/blob/master/examples/buttons-derive/src/main.rs#L50).
#[macro_export]
macro_rules! relm_widget {
    ($($tts:tt)*) => {
        mod __relm_gen_private {
            use super::*;

            #[derive(Widget)]
            struct __RelmPrivateWidget {
                widget: impl_widget! {
                    $($tts)*
                }
            }
        }

        use_impl_self_type!($($tts)*);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! use_impl_self_type {
    (impl $(::relm::)*Widget for $self_type:ident { $($tts:tt)* }) => {
        pub use self::__relm_gen_private::$self_type;
    };
}

fn create_widget_test<WIDGET>(model_param: WIDGET::ModelParam) -> (Component<WIDGET>, WIDGET::Widgets)
    where WIDGET: Widget + WidgetTest + 'static,
          WIDGET::Msg: DisplayVariant + 'static,
{
    let (widget, component, relm): (_, WIDGET, _) = create_widget(model_param);
    let widgets = component.get_widgets();
    init_component::<WIDGET>(widget.stream(), component, &relm);
    (widget, widgets)
}

/// Create a new relm widget without adding it to an existing widget.
/// This is useful when a relm widget is at the root of another relm widget.
pub fn create_component<CHILDWIDGET>(model_param: CHILDWIDGET::ModelParam)
        -> Component<CHILDWIDGET>
    where CHILDWIDGET: Widget + 'static,
          CHILDWIDGET::Msg: DisplayVariant + 'static,
{
    let (widget, component, child_relm) = create_widget::<CHILDWIDGET>(model_param);
    init_component::<CHILDWIDGET>(widget.stream(), component, &child_relm);
    widget
}

/// Create a new relm container widget without adding it to an existing widget.
/// This is useful when a relm widget is at the root of another relm widget.
pub fn create_container<CHILDWIDGET>(model_param: CHILDWIDGET::ModelParam)
        -> ContainerComponent<CHILDWIDGET>
    where CHILDWIDGET: Container + Widget + 'static,
          CHILDWIDGET::Msg: DisplayVariant + 'static,
{
    let (widget, component, child_relm) = create_widget::<CHILDWIDGET>(model_param);
    let container = component.container().clone();
    let containers = component.other_containers();
    init_component::<CHILDWIDGET>(widget.stream(), component, &child_relm);
    ContainerComponent::new(widget, container, containers)
}

/// Create a new relm widget with `model_param` as initialization value.
fn create_widget<WIDGET>(model_param: WIDGET::ModelParam)
    -> (Component<WIDGET>, WIDGET, Relm<WIDGET>)
    where WIDGET: Widget + 'static,
          WIDGET::Msg: DisplayVariant + 'static,
{
    let stream = EventStream::new();

    let relm = Relm::new(stream.clone());
    let model = WIDGET::model(&relm, model_param);
    let mut widget = WIDGET::view(&relm, model);
    widget.init_view();

    let root = widget.root().clone();
    (Component::new(stream, root), widget, relm)
}

/// Initialize a widget for a test.
///
/// It is to be used this way:
///
/// ```
/// # extern crate gtk;
/// # #[macro_use]
/// # extern crate relm;
/// # #[macro_use]
/// # extern crate relm_derive;
/// #
/// # use gtk::{Window, WindowType};
/// # use relm::{Relm, Update, Widget, WidgetTest};
/// #
/// # #[derive(Clone)]
/// # struct Win {
/// #     window: Window,
/// # }
/// #
/// # impl Update for Win {
/// #     type Model = ();
/// #     type ModelParam = ();
/// #     type Msg = Msg;
/// #
/// #     fn model(_: &Relm<Self>, _: ()) -> () {
/// #         ()
/// #     }
/// #
/// #     fn update(&mut self, event: Msg) {
/// #     }
/// # }
/// #
/// # impl WidgetTest for Win {
/// #     type Widgets = Win;
/// #
/// #     fn get_widgets(&self) -> Self::Widgets {
/// #         self.clone()
/// #     }
/// # }
/// #
/// # impl Widget for Win {
/// #     type Root = Window;
/// #
/// #     fn root(&self) -> Self::Root {
/// #         self.window.clone()
/// #     }
/// #
/// #     fn view(relm: &Relm<Self>, _model: Self::Model) -> Self {
/// #         let window = Window::new(WindowType::Toplevel);
/// #
/// #         Win {
/// #             window: window,
/// #         }
/// #     }
/// # }
/// #
/// # #[derive(Msg)]
/// # enum Msg {}
/// # fn main() {
/// let (component, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
/// # }
/// ```
pub fn init_test<WIDGET>(model_param: WIDGET::ModelParam) ->
    Result<(Component<WIDGET>, WIDGET::Widgets), ()>
    where WIDGET: Widget + WidgetTest + 'static,
          WIDGET::Msg: DisplayVariant + 'static,
{
    gtk::init().map_err(|_| ())?;
    let component = create_widget_test::<WIDGET>(model_param);
    Ok(component)
}

/// Initialize a widget.
pub fn init<WIDGET>(model_param: WIDGET::ModelParam) -> Result<Component<WIDGET>, ()>
    where WIDGET: Widget + 'static,
          WIDGET::Msg: DisplayVariant + 'static
{
    let (widget, component, relm) = create_widget::<WIDGET>(model_param);
    init_component::<WIDGET>(widget.stream(), component, &relm);
    Ok(widget)
}

/// Create the specified relm `Widget` and run the main event loops.
///
/// ```
/// # extern crate gtk;
/// # #[macro_use]
/// # extern crate relm;
/// # #[macro_use]
/// # extern crate relm_derive;
/// #
/// # use gtk::{Window, WindowType};
/// # use relm::{Relm, Update, Widget};
/// #
/// # struct Win {
/// #     window: Window,
/// # }
/// #
/// # impl Update for Win {
/// #     type Model = ();
/// #     type ModelParam = ();
/// #     type Msg = Msg;
/// #
/// #     fn model(_: &Relm<Self>, _: ()) -> () {
/// #         ()
/// #     }
/// #
/// #     fn update(&mut self, event: Msg) {
/// #     }
/// # }
/// #
/// # impl Widget for Win {
/// #     type Root = Window;
/// #
/// #     fn root(&self) -> Self::Root {
/// #         self.window.clone()
/// #     }
/// #
/// #     fn view(relm: &Relm<Self>, _model: Self::Model) -> Self {
/// #         let window = Window::new(WindowType::Toplevel);
/// #
/// #         Win {
/// #             window: window,
/// #         }
/// #     }
/// # }
/// # #[derive(Msg)]
/// # enum Msg {}
/// # fn main() {
/// # }
/// #
/// # fn run() {
/// /// `Win` is a relm `Widget`.
/// Win::run(()).expect("Win::run failed");
/// # }
/// ```
pub fn run<WIDGET>(model_param: WIDGET::ModelParam) -> Result<(), ()>
    where WIDGET: Widget + 'static,
{
    gtk::init().map_err(|_| ())?;
    let _component = init::<WIDGET>(model_param)?;
    gtk::main();
    Ok(())
}

/// Emit the `msg` every `duration` ms.
pub fn interval<F: Fn() -> MSG + 'static, MSG: 'static>(stream: &EventStream<MSG>, duration: u32, constructor: F) {
    let stream = stream.clone();
    gtk::timeout_add(duration, move || {
        let msg = constructor();
        stream.emit(msg);
        Continue(true)
    });
}

/// After `duration` ms, emit `msg`.
pub fn timeout<F: Fn() -> MSG + 'static, MSG: 'static>(stream: &EventStream<MSG>, duration: u32, constructor: F) {
    let stream = stream.clone();
    gtk::timeout_add(duration, move || {
        let msg = constructor();
        stream.emit(msg);
        Continue(false)
    });
}
<commit_msg>Reexport `relm_core` types<commit_after>/*
 * Copyright (c) 2017-2019 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Asynchronous GUI library based on GTK+.
//!
//! This library provides a [`Widget`](trait.Widget.html) trait that you can use to create asynchronous GUI components.
//! This is the trait you will need to implement for your application.
//! It helps you to implement MVC (Model, View, Controller) in an elegant way.
//!
//! ## Installation
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! gtk = "^0.3.0"
//! relm = "^0.11.0"
//! relm-derive = "^0.11.0"
//! ```
//!
//! More info can be found in the [readme](https://github.com/antoyo/relm#relm).

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

/*
 * TODO: maybe remove SimpleMsg.
 *
 * TODO: improve README so that examples can be copy/pasted.
 * TODO: add tests for relm-derive-state.
 *
 * FIXME: some relm widgets requires { and } (see the rusic music-player) while other do not.
 * FIXME: should not require to import WidgetExt because it calls show().
 * FIXME: cannot have relm event with tuple as a value like:
 * RelmWidget {
 *     RelmEvent((value1, value2)) => …
 * }
 * TODO: use pub(crate) instead of pub so that we're not bound to make the model and msg structs pub.
 *
 * TODO: add init() method to the Widget (or Update) trait as a shortcut for init::<Widget>()?
 *
 * TODO: alternative to tokio with a trait to get FD and add this FD to glib (perhaps using a
 * GSource).
 * For timers, add a connect_timeout!() macro or something.
 *
 * TODO: show a warning when a component is imediately destroyed.
 * FIXME: cannot add a trailing coma at the end of a initializer list.
 * TODO: switch from gtk::main() to MainLoop to avoid issues with nested loops.
 * TODO: prefix generated container name with _ to hide warnings.
 * TODO: remove the code generation related to using self in event handling.
 * TODO: remove the closure transformer code.
 *
 * TODO: move most of the examples in the tests/ directory.
 * TODO: add construct-only properties for relm widget (to replace initial parameters) to allow
 * setting them by name (or with default value).
 * TODO: find a way to do two-step initialization (to avoid using unitialized in model()).
 * TODO: consider using GBinding instead of manually adding calls to set_property().
 *
 * TODO: add a FAQ with the question related to getting an error when not importing the gtk traits.
 *
 * TODO: show a warning when components are destroyed after the end of call to Widget::view().
 * TODO: warn in the attribute when an event cycle is found.
 * TODO: add a Deref<Widget> for Component?
 * TODO: look at how Elm works with the <canvas> element.
 * TODO: the widget names should start with __relm_field_.
 *
 * TODO: reset widget name counters when creating new widget?
 *
 * TODO: refactor the code.
 *
 * TODO: chat client/server example.
 *
 * TODO: err if trying to use the SimpleMsg custom derive on stable.
 *
 * TODO: add default type of () for Model in Widget when it is stable.
 * TODO: optionnaly multi-threaded.
 */

extern crate cairo;
extern crate glib;
extern crate gobject_sys;
extern crate gtk;
extern crate relm_core;
extern crate relm_state;

mod component;
mod container;
mod drawing;
mod macros;
#[doc(hidden)]
pub mod vendor;
mod widget;

#[doc(hidden)]
pub use glib::Cast;
#[doc(hidden)]
pub use glib::object::Downcast;
#[doc(hidden)]
pub use glib::translate::{FromGlibPtrNone, ToGlib, ToGlibPtr};
#[doc(hidden)]
pub use gobject_sys::{GParameter, g_object_newv};
use gtk::Continue;

pub use relm_core::{Channel, EventStream, Sender};
pub use relm_state::{
    DisplayVariant,
    IntoOption,
    IntoPair,
    Relm,
    Update,
    UpdateNew,
    execute,
};
use relm_state::init_component;

pub use component::Component;
pub use container::{Container, ContainerComponent, ContainerWidget};
pub use drawing::DrawHandler;
pub use widget::{Widget, WidgetTest};

/// Dummy macro to be used with `#[derive(Widget)]`.
#[macro_export]
macro_rules! impl_widget {
    ($($tt:tt)*) => {
        ()
    };
}

/// Macro to be used as a stable alternative to the `#[widget]` attribute.
///
/// An example can be found [here](https://github.com/antoyo/relm/blob/master/examples/buttons-derive/src/main.rs#L50).
#[macro_export]
macro_rules! relm_widget {
    ($($tts:tt)*) => {
        mod __relm_gen_private {
            use super::*;

            #[derive(Widget)]
            struct __RelmPrivateWidget {
                widget: impl_widget! {
                    $($tts)*
                }
            }
        }

        use_impl_self_type!($($tts)*);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! use_impl_self_type {
    (impl $(::relm::)*Widget for $self_type:ident { $($tts:tt)* }) => {
        pub use self::__relm_gen_private::$self_type;
    };
}

fn create_widget_test<WIDGET>(model_param: WIDGET::ModelParam) -> (Component<WIDGET>, WIDGET::Widgets)
    where WIDGET: Widget + WidgetTest + 'static,
          WIDGET::Msg: DisplayVariant + 'static,
{
    let (widget, component, relm): (_, WIDGET, _) = create_widget(model_param);
    let widgets = component.get_widgets();
    init_component::<WIDGET>(widget.stream(), component, &relm);
    (widget, widgets)
}

/// Create a new relm widget without adding it to an existing widget.
/// This is useful when a relm widget is at the root of another relm widget.
pub fn create_component<CHILDWIDGET>(model_param: CHILDWIDGET::ModelParam)
        -> Component<CHILDWIDGET>
    where CHILDWIDGET: Widget + 'static,
          CHILDWIDGET::Msg: DisplayVariant + 'static,
{
    let (widget, component, child_relm) = create_widget::<CHILDWIDGET>(model_param);
    init_component::<CHILDWIDGET>(widget.stream(), component, &child_relm);
    widget
}

/// Create a new relm container widget without adding it to an existing widget.
/// This is useful when a relm widget is at the root of another relm widget.
pub fn create_container<CHILDWIDGET>(model_param: CHILDWIDGET::ModelParam)
        -> ContainerComponent<CHILDWIDGET>
    where CHILDWIDGET: Container + Widget + 'static,
          CHILDWIDGET::Msg: DisplayVariant + 'static,
{
    let (widget, component, child_relm) = create_widget::<CHILDWIDGET>(model_param);
    let container = component.container().clone();
    let containers = component.other_containers();
    init_component::<CHILDWIDGET>(widget.stream(), component, &child_relm);
    ContainerComponent::new(widget, container, containers)
}

/// Create a new relm widget with `model_param` as initialization value.
fn create_widget<WIDGET>(model_param: WIDGET::ModelParam)
    -> (Component<WIDGET>, WIDGET, Relm<WIDGET>)
    where WIDGET: Widget + 'static,
          WIDGET::Msg: DisplayVariant + 'static,
{
    let stream = EventStream::new();

    let relm = Relm::new(stream.clone());
    let model = WIDGET::model(&relm, model_param);
    let mut widget = WIDGET::view(&relm, model);
    widget.init_view();

    let root = widget.root().clone();
    (Component::new(stream, root), widget, relm)
}

/// Initialize a widget for a test.
///
/// It is to be used this way:
///
/// ```
/// # extern crate gtk;
/// # #[macro_use]
/// # extern crate relm;
/// # #[macro_use]
/// # extern crate relm_derive;
/// #
/// # use gtk::{Window, WindowType};
/// # use relm::{Relm, Update, Widget, WidgetTest};
/// #
/// # #[derive(Clone)]
/// # struct Win {
/// #     window: Window,
/// # }
/// #
/// # impl Update for Win {
/// #     type Model = ();
/// #     type ModelParam = ();
/// #     type Msg = Msg;
/// #
/// #     fn model(_: &Relm<Self>, _: ()) -> () {
/// #         ()
/// #     }
/// #
/// #     fn update(&mut self, event: Msg) {
/// #     }
/// # }
/// #
/// # impl WidgetTest for Win {
/// #     type Widgets = Win;
/// #
/// #     fn get_widgets(&self) -> Self::Widgets {
/// #         self.clone()
/// #     }
/// # }
/// #
/// # impl Widget for Win {
/// #     type Root = Window;
/// #
/// #     fn root(&self) -> Self::Root {
/// #         self.window.clone()
/// #     }
/// #
/// #     fn view(relm: &Relm<Self>, _model: Self::Model) -> Self {
/// #         let window = Window::new(WindowType::Toplevel);
/// #
/// #         Win {
/// #             window: window,
/// #         }
/// #     }
/// # }
/// #
/// # #[derive(Msg)]
/// # enum Msg {}
/// # fn main() {
/// let (component, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
/// # }
/// ```
pub fn init_test<WIDGET>(model_param: WIDGET::ModelParam) ->
    Result<(Component<WIDGET>, WIDGET::Widgets), ()>
    where WIDGET: Widget + WidgetTest + 'static,
          WIDGET::Msg: DisplayVariant + 'static,
{
    gtk::init().map_err(|_| ())?;
    let component = create_widget_test::<WIDGET>(model_param);
    Ok(component)
}

/// Initialize a widget.
pub fn init<WIDGET>(model_param: WIDGET::ModelParam) -> Result<Component<WIDGET>, ()>
    where WIDGET: Widget + 'static,
          WIDGET::Msg: DisplayVariant + 'static
{
    let (widget, component, relm) = create_widget::<WIDGET>(model_param);
    init_component::<WIDGET>(widget.stream(), component, &relm);
    Ok(widget)
}

/// Create the specified relm `Widget` and run the main event loops.
///
/// ```
/// # extern crate gtk;
/// # #[macro_use]
/// # extern crate relm;
/// # #[macro_use]
/// # extern crate relm_derive;
/// #
/// # use gtk::{Window, WindowType};
/// # use relm::{Relm, Update, Widget};
/// #
/// # struct Win {
/// #     window: Window,
/// # }
/// #
/// # impl Update for Win {
/// #     type Model = ();
/// #     type ModelParam = ();
/// #     type Msg = Msg;
/// #
/// #     fn model(_: &Relm<Self>, _: ()) -> () {
/// #         ()
/// #     }
/// #
/// #     fn update(&mut self, event: Msg) {
/// #     }
/// # }
/// #
/// # impl Widget for Win {
/// #     type Root = Window;
/// #
/// #     fn root(&self) -> Self::Root {
/// #         self.window.clone()
/// #     }
/// #
/// #     fn view(relm: &Relm<Self>, _model: Self::Model) -> Self {
/// #         let window = Window::new(WindowType::Toplevel);
/// #
/// #         Win {
/// #             window: window,
/// #         }
/// #     }
/// # }
/// # #[derive(Msg)]
/// # enum Msg {}
/// # fn main() {
/// # }
/// #
/// # fn run() {
/// /// `Win` is a relm `Widget`.
/// Win::run(()).expect("Win::run failed");
/// # }
/// ```
pub fn run<WIDGET>(model_param: WIDGET::ModelParam) -> Result<(), ()>
    where WIDGET: Widget + 'static,
{
    gtk::init().map_err(|_| ())?;
    let _component = init::<WIDGET>(model_param)?;
    gtk::main();
    Ok(())
}

/// Emit the `msg` every `duration` ms.
pub fn interval<F: Fn() -> MSG + 'static, MSG: 'static>(stream: &EventStream<MSG>, duration: u32, constructor: F) {
    let stream = stream.clone();
    gtk::timeout_add(duration, move || {
        let msg = constructor();
        stream.emit(msg);
        Continue(true)
    });
}

/// After `duration` ms, emit `msg`.
pub fn timeout<F: Fn() -> MSG + 'static, MSG: 'static>(stream: &EventStream<MSG>, duration: u32, constructor: F) {
    let stream = stream.clone();
    gtk::timeout_add(duration, move || {
        let msg = constructor();
        stream.emit(msg);
        Continue(false)
    });
}
<|endoftext|>


<commit_before>/*
Copyright ⓒ 2016 Daniel Keep.

Licensed under the MIT license (see LICENSE or <http://opensource.org
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
files in the project carrying such notice may not be copied, modified,
or distributed except according to those terms.
*/
/*!

This crate provides some macros for quickly parsing values out of text.  Roughly speaking, it does the inverse of the `print!`/`format!` macros; or, in other words, a similar job to `scanf` from C.

The macros of interest are:

* [`readln!`](macro.readln!.html) - reads and scans a line from standard input.
* [`try_readln!`](macro.try_readln!.html) - like `readln!`, except it returns a `Result` instead of panicking.
* [`scan!`](macro.scan!.html) - scans the provided string.

If you are interested in implementing support for your own types, see the [`ScanFromStr`](scanner/trait.ScanFromStr.html) trait.

The available abstract scanners can be found in the [`scanner`](scanner/index.html) module.

**Links**

* [Latest Release](https://crates.io/crates/scan-rules/)
* [Latest Docs](https://danielkeep.github.io/rust-scan-rules/doc/scan_rules/index.html)
* [Repository](https://github.com/DanielKeep/rust-scan-rules)

## Features

The following optional features are available:

* `arrays-32`: implement scanning for arrays of up to 32 elements.  The default is up to 8 elements.

* `tuples-16`: implement scanning for tuples of up to 16 elements.  The default is up to 4 elements.

## Important Notes

* There are no default scanners for `&str` or `String`; if you want a string, you should pick an appropriate abstract scanner from the [`scanner`](scanner/index.html) module.

* The macros in this crate are extremely complex.  Moderately complex usage can exhaust the standard macro recursion limit.  If this happens, you can raise the limit (from its default of 64) by adding the following attribute to your crate's root module:

  `#![recursion_limit="128"]`

## Quick Examples

Here is a simple CLI program that asks the user their name and age.  You can run this using `cargo run --example ask_age`.

```ignore
#[macro_use] extern crate scan_rules;

use scan_rules::scanner::Word;

fn main() {
    print!("What's your name? ");
    let name: String = readln! { (let name: Word<String>) => name };
    //                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ rule
    //                                                       ^~~^ body
    //                           ^~~~~~~~~~~~~~~~~~~~~~~^ pattern
    //                            ^~~~~~~~~~~~~~~~~~~~~^ variable binding

    print!("Hi, {}.  How old are you? ", name);
    readln! {
        (let age) => {
    //   ^~~~~~^ implicitly typed variable binding
            let age: i32 = age;
            println!("{} years old, huh?  Neat.", age);
        },
        (..other) => println!("`{}` doesn't *look* like a number...", other),
    //   ^~~~~~^ bind to any input "left over"
    }
}
```

This example shows how to parse one of several different syntaxes.  You can run this using `cargo run --example scan_data`.

```ignore
#[macro_use] extern crate scan_rules;

use std::collections::BTreeSet;

// `Word` is an "abstract" scanner; rather than scanning itself, it scans some
// *other* type using custom rules.  In this case, it scans a word into a
// string slice.  You can use `Word<String>` to get an owned string.
use scan_rules::scanner::Word;

#[derive(Debug)]
enum Data {
    Vector(i32, i32, i32),
    Truthy(bool),
    Words(Vec<String>),
    Lucky(BTreeSet<i32>),
    Other(String),
}

fn main() {
    print!("Enter some data: ");
    let data = readln! {
        ("<", let x, ",", let y, ",", let z, ">") => Data::Vector(x, y, z),
    //      ^ pattern terms are comma-separated
    //   ^~^ literal text match

        // Rules are tried top-to-bottom, stopping as soon as one matches.
        (let b) => Data::Truthy(b),
        ("yes") => Data::Truthy(true),
        ("no") => Data::Truthy(false),

        ("words:", [ let words: Word<String> ],+) => Data::Words(words),
    //             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~^ repetition pattern
    //                                         ^ one or more matches
    //                                        ^ matches must be comma-separated

        ("lucky numbers:", [ let ns: i32 ]*: BTreeSet<_>) => Data::Lucky(ns),
    //          collect into specific type ^~~~~~~~~~~~^
    //                                    ^ zero or more (you might be unlucky!)
    //                                      (no separator this time)

        // Rather than scanning a sequence of values and collecting them into
        // a `BTreeSet`, we can instead scan the `BTreeSet` *directly*.  This
        // scans the syntax `BTreeSet` uses when printed using `{:?}`:
        // `{1, 5, 13, ...}`.
        ("lucky numbers:", let ns) => Data::Lucky(ns),

        (..other) => Data::Other(String::from(other))
    };
    println!("data: {:?}", data);
}
```

This example demonstrates using runtime scanners and the `let_scan!` convenience macro.  You can run this using `cargo run --example runtime_scanners`.

```ignore
#[macro_use] extern crate scan_rules;

use scan_rules::scanner::{
    NonSpace, Number, Word,             // static scanners
    max_width_a, exact_width_a, re_str, // runtime scanners
};

fn main() {
    // Adapted example from <http://en.cppreference.com/w/cpp/io/c/fscanf>.
    let inp = "25 54.32E-1 Thompson 56789 0123 56ß水";

    // `let_scan!` avoids the need for indentation and braces, but only supports
    // a single pattern, and panics if anything goes wrong.
    let_scan!(inp; (
        let i: i32, let x: f32, let str1 <| max_width_a::<NonSpace>(9),
    //               use runtime scanner ^~~~~~~~~~~~~~~~~~~~~~~~~~~~^
    //          limit maximum width of a... ^~~~~~~~~~^
    //                      ...static NonSpace scanner... ^~~~~~~^
    //                                                      9 bytes ^
        let j <| exact_width_a::<i32>(2), let y: f32, let _: Number,
    //        ^~~~~~~~~~~~~~~~~~~~~~~~~^ scan an i32 with exactly 2 digits
        let str2 <| re_str(r"^[0-9]{1,3}"), let warr: Word
    //           ^~~~~~~~~~~~~~~~~~~~~~~~^ scan using a regular expression
    ));

    println!(
        "Converted fields:\n\
            i = {i:?}\n\
            x = {x:?}\n\
            str1 = {str1:?}\n\
            j = {j:?}\n\
            y = {y:?}\n\
            str2 = {str2:?}\n\
            warr = {warr:?}",
        i=i, j=j, x=x, y=y,
        str1=str1, str2=str2, warr=warr);
}
```

## Rule Syntax

Scanning rules are written as one or more arms like so:

```ignore
scan! { input_expression;
    ( pattern ) => body,
    ( pattern ) => body,
    ...
    ( pattern ) => body,
}
```

Note that the trailing comma on the last rule is optional.

Rules are checked top-to-bottom, stopping at the first that matches.

Patterns (explained under ["Pattern Syntax"](#pattern-syntax)) must be enclosed in parentheses.  If a pattern matches the provided input, the corresponding body is evaluated.

### Pattern Syntax

A scanning pattern is made up of one or more pattern terms, separated by commas.  The following terms are supported:

* *strings* - any expression that evaluates to a string will be used as a literal match on the input.  Exactly *how* this match is done depends on the kind of input, but the default is to do a case-sensitive match of whole words, individual non-letter characters, and to ignore all whitespace.

  *E.g.* `"Two words"`, `"..."` (counts as three "words"), `&format!("{} {}", "Two", "words")`.

* `let` *name* \[ `:` *type* ] - scans a value out of the input text, and binds it to *name*.  If *type* is omitted, it will be inferred.

  *E.g.* `let x`, `let n: i32`, `let words: Vec<_>`, `let _: &str` (scans and discards a value).

* `let` *name* `<|` *expression* - scans a value out of the input text and binds it to *name*, using the value of *expression* to perform the scan.  The expression must evaluate to something that implements the `ScanStr` trait.

  *E.g.* `let n <| scan_a::<i32>()` (same as above example for `n`), `let three_digits <| max_width_a::<u32>()` (scan a three-digit `u32`).

* `..` *name* - binds the remaining, unscanned input as a string to *name*.  This can *only* appear as the final term in a top-level pattern.

* `[` *pattern* `]` \[ *(nothing)* | `,` | `(` *seperator pattern* `)` ] ( `?` | `*` | `+` | `{` *range* `}` ) \[ ":" *collection type* ] - scans *pattern* repeatedly.

  The first (mandatory) part of the term specifies the *pattern* that should be repeatedly scanned.

  The second (optional) part of the term controls if (and what) repeats are separated by.  `,` is provided as a short-cut to an obvious common case; it is equivalent to writing `(",")`.  Otherwise, you may write any arbitrary *separator pattern* as the separator, including variable bindings and more repetitions.

  The third (mandatory) part of the term specifies how many times *pattern* should be scanned.  The available options are:

  * `?` - match zero or one times.
  * `*` - match zero or more times.
  * `+` - match one or more times.
  * `{n}` - match exactly *n* times.
  * `{a,}` - match at least *a* times.
  * `{,b}` - match at most *b* times.
  * `{a, b}` - match at least *a* times, and at most *b* times.

  The fourth (optional) part of the term specifies what type of collection scanned values should be added to.  Note that the type specified here applies to *all* values captured by this repetition.  As such, you typically want to use a partially inferred type such as `BTreeSet<_>`.  If omitted, it defaults to `Vec<_>`.

  *E.g.* `[ let nums: i32 ],+`, `[ "pretty" ]*, "please"`.

*/
#![forbid(missing_docs)]
#![recursion_limit="128"]
#[macro_use] extern crate lazy_static;
extern crate itertools;
extern crate regex;
extern crate strcursor;

#[macro_use] mod macros;

pub use error::{ScanError, ScanErrorKind};

mod error;
pub mod input;
pub mod scanner;

/**
Remove a single trailing line terminator from `s`.

This is publicly exposed for the sake of macros and **is not** considered a stable part of the public API.
*/
#[doc(hidden)]
pub fn strip_line_term(s: &str) -> &str {
    if s.ends_with("\r\n") {
        &s[0..s.len()-2]
    } else if s.ends_with("\n") {
        &s[0..s.len()-1]
    } else if s.ends_with("\r") {
        &s[0..s.len()-1]
    } else {
        s
    }
}

/**
Compute the offset of `b`, which must be a subslice of `a`.

This is publicly exposed for the sake of macros and **is not** considered a stable part of the public API.
*/
#[doc(hidden)]
pub fn subslice_offset(a: &str, b: &str) -> Option<usize> {
    use scanner::util::StrUtil;
    a.subslice_offset(b)
}
<commit_msg>Updated crate docs: `let_scan!` and `ScanStr`.<commit_after>/*
Copyright ⓒ 2016 Daniel Keep.

Licensed under the MIT license (see LICENSE or <http://opensource.org
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
files in the project carrying such notice may not be copied, modified,
or distributed except according to those terms.
*/
/*!

This crate provides some macros for quickly parsing values out of text.  Roughly speaking, it does the inverse of the `print!`/`format!` macros; or, in other words, a similar job to `scanf` from C.

The macros of interest are:

* [`readln!`](macro.readln!.html) - reads and scans a line from standard input.
* [`try_readln!`](macro.try_readln!.html) - like `readln!`, except it returns a `Result` instead of panicking.
* [`scan!`](macro.scan!.html) - scans the provided string.

Plus a convenience macro:

* [`let_scan!`](macro.let_scan!.html) - scans a string and binds captured values directly to local variables.  Only supports *one* pattern and panics if it doesn't match.

If you are interested in implementing support for your own types, see the [`ScanFromStr`](scanner/trait.ScanFromStr.html) and [`ScanStr`](scanner/trait.ScanStr.html) traits.

The provided scanners can be found in the [`scanner`](scanner/index.html) module.

**Links**

* [Latest Release](https://crates.io/crates/scan-rules/)
* [Latest Docs](https://danielkeep.github.io/rust-scan-rules/doc/scan_rules/index.html)
* [Repository](https://github.com/DanielKeep/rust-scan-rules)

## Features

The following optional features are available:

* `arrays-32`: implement scanning for arrays of up to 32 elements.  The default is up to 8 elements.

* `tuples-16`: implement scanning for tuples of up to 16 elements.  The default is up to 4 elements.

## Important Notes

* There are no default scanners for `&str` or `String`; if you want a string, you should pick an appropriate abstract scanner from the [`scanner`](scanner/index.html) module.

* The macros in this crate are extremely complex.  Moderately complex usage can exhaust the standard macro recursion limit.  If this happens, you can raise the limit (from its default of 64) by adding the following attribute to your crate's root module:

  `#![recursion_limit="128"]`

## Quick Examples

Here is a simple CLI program that asks the user their name and age.  You can run this using `cargo run --example ask_age`.

```ignore
#[macro_use] extern crate scan_rules;

use scan_rules::scanner::Word;

fn main() {
    print!("What's your name? ");
    let name: String = readln! { (let name: Word<String>) => name };
    //                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ rule
    //                                                       ^~~^ body
    //                           ^~~~~~~~~~~~~~~~~~~~~~~^ pattern
    //                            ^~~~~~~~~~~~~~~~~~~~~^ variable binding

    print!("Hi, {}.  How old are you? ", name);
    readln! {
        (let age) => {
    //   ^~~~~~^ implicitly typed variable binding
            let age: i32 = age;
            println!("{} years old, huh?  Neat.", age);
        },
        (..other) => println!("`{}` doesn't *look* like a number...", other),
    //   ^~~~~~^ bind to any input "left over"
    }
}
```

This example shows how to parse one of several different syntaxes.  You can run this using `cargo run --example scan_data`.

```ignore
#[macro_use] extern crate scan_rules;

use std::collections::BTreeSet;

// `Word` is an "abstract" scanner; rather than scanning itself, it scans some
// *other* type using custom rules.  In this case, it scans a word into a
// string slice.  You can use `Word<String>` to get an owned string.
use scan_rules::scanner::Word;

#[derive(Debug)]
enum Data {
    Vector(i32, i32, i32),
    Truthy(bool),
    Words(Vec<String>),
    Lucky(BTreeSet<i32>),
    Other(String),
}

fn main() {
    print!("Enter some data: ");
    let data = readln! {
        ("<", let x, ",", let y, ",", let z, ">") => Data::Vector(x, y, z),
    //      ^ pattern terms are comma-separated
    //   ^~^ literal text match

        // Rules are tried top-to-bottom, stopping as soon as one matches.
        (let b) => Data::Truthy(b),
        ("yes") => Data::Truthy(true),
        ("no") => Data::Truthy(false),

        ("words:", [ let words: Word<String> ],+) => Data::Words(words),
    //             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~^ repetition pattern
    //                                         ^ one or more matches
    //                                        ^ matches must be comma-separated

        ("lucky numbers:", [ let ns: i32 ]*: BTreeSet<_>) => Data::Lucky(ns),
    //          collect into specific type ^~~~~~~~~~~~^
    //                                    ^ zero or more (you might be unlucky!)
    //                                      (no separator this time)

        // Rather than scanning a sequence of values and collecting them into
        // a `BTreeSet`, we can instead scan the `BTreeSet` *directly*.  This
        // scans the syntax `BTreeSet` uses when printed using `{:?}`:
        // `{1, 5, 13, ...}`.
        ("lucky numbers:", let ns) => Data::Lucky(ns),

        (..other) => Data::Other(String::from(other))
    };
    println!("data: {:?}", data);
}
```

This example demonstrates using runtime scanners and the `let_scan!` convenience macro.  You can run this using `cargo run --example runtime_scanners`.

```ignore
#[macro_use] extern crate scan_rules;

use scan_rules::scanner::{
    NonSpace, Number, Word,             // static scanners
    max_width_a, exact_width_a, re_str, // runtime scanners
};

fn main() {
    // Adapted example from <http://en.cppreference.com/w/cpp/io/c/fscanf>.
    let inp = "25 54.32E-1 Thompson 56789 0123 56ß水";

    // `let_scan!` avoids the need for indentation and braces, but only supports
    // a single pattern, and panics if anything goes wrong.
    let_scan!(inp; (
        let i: i32, let x: f32, let str1 <| max_width_a::<NonSpace>(9),
    //               use runtime scanner ^~~~~~~~~~~~~~~~~~~~~~~~~~~~^
    //          limit maximum width of a... ^~~~~~~~~~^
    //                      ...static NonSpace scanner... ^~~~~~~^
    //                                                      9 bytes ^
        let j <| exact_width_a::<i32>(2), let y: f32, let _: Number,
    //        ^~~~~~~~~~~~~~~~~~~~~~~~~^ scan an i32 with exactly 2 digits
        let str2 <| re_str(r"^[0-9]{1,3}"), let warr: Word
    //           ^~~~~~~~~~~~~~~~~~~~~~~~^ scan using a regular expression
    ));

    println!(
        "Converted fields:\n\
            i = {i:?}\n\
            x = {x:?}\n\
            str1 = {str1:?}\n\
            j = {j:?}\n\
            y = {y:?}\n\
            str2 = {str2:?}\n\
            warr = {warr:?}",
        i=i, j=j, x=x, y=y,
        str1=str1, str2=str2, warr=warr);
}
```

## Rule Syntax

Scanning rules are written as one or more arms like so:

```ignore
scan! { input_expression;
    ( pattern ) => body,
    ( pattern ) => body,
    ...
    ( pattern ) => body,
}
```

Note that the trailing comma on the last rule is optional.

Rules are checked top-to-bottom, stopping at the first that matches.

Patterns (explained under ["Pattern Syntax"](#pattern-syntax)) must be enclosed in parentheses.  If a pattern matches the provided input, the corresponding body is evaluated.

### Pattern Syntax

A scanning pattern is made up of one or more pattern terms, separated by commas.  The following terms are supported:

* *strings* - any expression that evaluates to a string will be used as a literal match on the input.  Exactly *how* this match is done depends on the kind of input, but the default is to do a case-sensitive match of whole words, individual non-letter characters, and to ignore all whitespace.

  *E.g.* `"Two words"`, `"..."` (counts as three "words"), `&format!("{} {}", "Two", "words")`.

* `let` *name* \[ `:` *type* ] - scans a value out of the input text, and binds it to *name*.  If *type* is omitted, it will be inferred.

  *E.g.* `let x`, `let n: i32`, `let words: Vec<_>`, `let _: &str` (scans and discards a value).

* `let` *name* `<|` *expression* - scans a value out of the input text and binds it to *name*, using the value of *expression* to perform the scan.  The expression must evaluate to something that implements the `ScanStr` trait.

  *E.g.* `let n <| scan_a::<i32>()` (same as above example for `n`), `let three_digits <| max_width_a::<u32>()` (scan a three-digit `u32`).

* `..` *name* - binds the remaining, unscanned input as a string to *name*.  This can *only* appear as the final term in a top-level pattern.

* `[` *pattern* `]` \[ *(nothing)* | `,` | `(` *seperator pattern* `)` ] ( `?` | `*` | `+` | `{` *range* `}` ) \[ ":" *collection type* ] - scans *pattern* repeatedly.

  The first (mandatory) part of the term specifies the *pattern* that should be repeatedly scanned.

  The second (optional) part of the term controls if (and what) repeats are separated by.  `,` is provided as a short-cut to an obvious common case; it is equivalent to writing `(",")`.  Otherwise, you may write any arbitrary *separator pattern* as the separator, including variable bindings and more repetitions.

  The third (mandatory) part of the term specifies how many times *pattern* should be scanned.  The available options are:

  * `?` - match zero or one times.
  * `*` - match zero or more times.
  * `+` - match one or more times.
  * `{n}` - match exactly *n* times.
  * `{a,}` - match at least *a* times.
  * `{,b}` - match at most *b* times.
  * `{a, b}` - match at least *a* times, and at most *b* times.

  The fourth (optional) part of the term specifies what type of collection scanned values should be added to.  Note that the type specified here applies to *all* values captured by this repetition.  As such, you typically want to use a partially inferred type such as `BTreeSet<_>`.  If omitted, it defaults to `Vec<_>`.

  *E.g.* `[ let nums: i32 ],+`, `[ "pretty" ]*, "please"`.

*/
#![forbid(missing_docs)]
#![recursion_limit="128"]
#[macro_use] extern crate lazy_static;
extern crate itertools;
extern crate regex;
extern crate strcursor;

#[macro_use] mod macros;

pub use error::{ScanError, ScanErrorKind};

mod error;
pub mod input;
pub mod scanner;

/**
Remove a single trailing line terminator from `s`.

This is publicly exposed for the sake of macros and **is not** considered a stable part of the public API.
*/
#[doc(hidden)]
pub fn strip_line_term(s: &str) -> &str {
    if s.ends_with("\r\n") {
        &s[0..s.len()-2]
    } else if s.ends_with("\n") {
        &s[0..s.len()-1]
    } else if s.ends_with("\r") {
        &s[0..s.len()-1]
    } else {
        s
    }
}

/**
Compute the offset of `b`, which must be a subslice of `a`.

This is publicly exposed for the sake of macros and **is not** considered a stable part of the public API.
*/
#[doc(hidden)]
pub fn subslice_offset(a: &str, b: &str) -> Option<usize> {
    use scanner::util::StrUtil;
    a.subslice_offset(b)
}
<|endoftext|>


<commit_before>//! A library for build scripts to compile custom C code
//!
//! This library is intended to be used as a `build-dependencies` entry in
//! `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! gcc = "0.2"
//! ```
//!
//! The purpose of this crate is to provide the utility functions necessary to
//! compile C code into a static archive which is then linked into a Rust crate.
//! The top-level `compile_library` function serves as a convenience and more
//! advanced configuration is available through the `Config` builder.
//!
//! This crate will automatically detect situations such as cross compilation or
//! other environment variables set by Cargo and will build code appropriately.
//!
//! # Examples
//!
//! Use the default configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::compile_library("libfoo.a", &["src/foo.c"]);
//! }
//! ```
//!
//! Use more advanced configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::Config::new()
//!                 .file("src/foo.c")
//!                 .define("FOO", Some("bar"))
//!                 .include("src")
//!                 .compile("libfoo.a");
//! }
//! ```

#![doc(html_root_url = "http://alexcrichton.com/gcc-rs")]
#![feature(io, std_misc)]
#![cfg_attr(test, deny(warnings))]

use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, AsPath};
use std::process::{Command, Stdio};

/// Extra configuration to pass to gcc.
pub struct Config {
    include_directories: Vec<PathBuf>,
    definitions: Vec<(String, Option<String>)>,
    objects: Vec<PathBuf>,
    flags: Vec<String>,
    files: Vec<PathBuf>,
}

fn getenv(v: &str) -> Option<String> {
    let r = env::var(v).ok();
    println!("{} = {:?}", v, r);
    r
}

fn getenv_unwrap(v: &str) -> String {
    match getenv(v) {
        Some(s) => s,
        None => fail(&format!("environment variable `{}` not defined", v)),
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// This function will also print all metadata on standard output for Cargo.
///
/// # Example
///
/// ```no_run
/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
/// ```
pub fn compile_library(output: &str, files: &[&str]) {
    let mut c = Config::new();
    for f in files.iter() {
        c.file(*f);
    }
    c.compile(output)
}

impl Config {
    /// Construct a new instance of a blank set of configuration.
    ///
    /// This builder is finished with the `compile` function.
    pub fn new() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
            flags: Vec::new(),
            files: Vec::new(),
        }
    }

    /// Add a directory to the `-I` or include path for headers
    pub fn include<P: AsPath>(&mut self, dir: P) -> &mut Config {
        self.include_directories.push(dir.as_path().to_path_buf());
        self
    }

    /// Specify a `-D` variable with an optional value.
    pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config {
        self.definitions.push((var.to_string(), val.map(|s| s.to_string())));
        self
    }

    /// Add an arbitrary object file to link in
    pub fn object<P: AsPath>(&mut self, obj: P) -> &mut Config {
        self.objects.push(obj.as_path().to_path_buf());
        self
    }

    /// Add an arbitrary flag to the invocation of the compiler
    pub fn flag(&mut self, flag: &str) -> &mut Config {
        self.flags.push(flag.to_string());
        self
    }

    /// Add a file which will be compiled
    pub fn file<P: AsPath>(&mut self, p: P) -> &mut Config {
        self.files.push(p.as_path().to_path_buf());
        self
    }

    /// Run the compiler, generating the file `output`
    ///
    /// The name `output` must begin with `lib` and end with `.a`
    pub fn compile(&self, output: &str) {
        assert!(output.starts_with("lib"));
        assert!(output.ends_with(".a"));

        let target = getenv_unwrap("TARGET");
        let src = PathBuf::new(&getenv_unwrap("CARGO_MANIFEST_DIR"));
        let dst = PathBuf::new(&getenv_unwrap("OUT_DIR"));
        let mut objects = Vec::new();
        for file in self.files.iter() {
            let mut cmd = self.gcc();
            let obj = dst.join(file).with_extension("o");
            fs::create_dir_all(&obj.parent().unwrap()).unwrap();
            run(cmd.arg(&src.join(file)).arg("-o").arg(&obj),
                &gcc(&target));
            objects.push(obj);
        }

        run(Command::new(&ar(&target)).arg("crus")
                                      .arg(&dst.join(output))
                                      .args(&objects)
                                      .args(&self.objects),
            &ar(&target));
        println!("cargo:rustc-flags=-L native={} -l static={}",
                 dst.display(), &output[3..output.len() - 2]);
    }

    fn gcc(&self) -> Command {
        let target = getenv_unwrap("TARGET");
        let opt_level = getenv_unwrap("OPT_LEVEL");
        let profile = getenv_unwrap("PROFILE");
        println!("{} {}", profile, opt_level);

        let mut cmd = Command::new(&gcc(&target));
        cmd.arg(&format!("-O{}", opt_level));
        cmd.arg("-c");
        cmd.arg("-ffunction-sections").arg("-fdata-sections");
        cmd.args(&cflags());

        if target.contains("-ios") {
            cmd.args(&ios_flags(&target));
        } else {
            if target.contains("windows") {
                cmd.arg("-mwin32");
            }

            if target.contains("i686") {
                cmd.arg("-m32");
            } else if target.contains("x86_64") {
                cmd.arg("-m64");
            }

            if !target.contains("i686") {
                cmd.arg("-fPIC");
            }
        }

        for directory in self.include_directories.iter() {
            cmd.arg("-I").arg(directory);
        }

        for flag in self.flags.iter() {
            cmd.arg(flag);
        }

        for &(ref key, ref value) in self.definitions.iter() {
            if let &Some(ref value) = value {
                cmd.arg(&format!("-D{}={}", key, value));
            } else {
                cmd.arg(&format!("-D{}", key));
            }
        }
        return cmd;
    }
}

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

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv_unwrap("TARGET");
    let host = getenv_unwrap("HOST");
    let kind = if host == target {"HOST"} else {"TARGET"};
    let target_u = target.replace("-", "_");
    let res = getenv(&format!("{}_{}", var_base, target))
        .or_else(|| getenv(&format!("{}_{}", var_base, target_u)))
        .or_else(|| getenv(&format!("{}_{}", kind, var_base)))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty())
       .map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    enum ArchSpec {
        Device(&'static str),
        Simulator(&'static str),
    }

    let mut res = Vec::new();

    let arch = target.split('-').nth(0).expect("expected target in format `arch-vendor-os`");
    let arch = match arch {
        "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
        "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
        "arm64" | "aarch64" => ArchSpec::Device("arm64"),
        "i386" | "i686" => ArchSpec::Simulator("-m32"),
        "x86_64" => ArchSpec::Simulator("-m64"),
        _ => unreachable!("Unknown arch for iOS target")
    };

    let sdk = match arch {
        ArchSpec::Device(arch) => {
            res.push("-arch".to_string());
            res.push(arch.to_string());
            "iphoneos"
        },
        ArchSpec::Simulator(arch) => {
            res.push(arch.to_string());
            "iphonesimulator"
        }
    };

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(Stdio::inherit())
        .output()
        .unwrap()
        .stdout;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot".to_string());
    res.push(sdk_path.trim().to_string());

    res
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    panic!()
}
<commit_msg>Use new dedicated metadata for Cargo<commit_after>//! A library for build scripts to compile custom C code
//!
//! This library is intended to be used as a `build-dependencies` entry in
//! `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! gcc = "0.2"
//! ```
//!
//! The purpose of this crate is to provide the utility functions necessary to
//! compile C code into a static archive which is then linked into a Rust crate.
//! The top-level `compile_library` function serves as a convenience and more
//! advanced configuration is available through the `Config` builder.
//!
//! This crate will automatically detect situations such as cross compilation or
//! other environment variables set by Cargo and will build code appropriately.
//!
//! # Examples
//!
//! Use the default configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::compile_library("libfoo.a", &["src/foo.c"]);
//! }
//! ```
//!
//! Use more advanced configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::Config::new()
//!                 .file("src/foo.c")
//!                 .define("FOO", Some("bar"))
//!                 .include("src")
//!                 .compile("libfoo.a");
//! }
//! ```

#![doc(html_root_url = "http://alexcrichton.com/gcc-rs")]
#![feature(io, std_misc)]
#![cfg_attr(test, deny(warnings))]

use std::env;
use std::fs;
use std::io;
use std::path::{PathBuf, AsPath};
use std::process::{Command, Stdio};

/// Extra configuration to pass to gcc.
pub struct Config {
    include_directories: Vec<PathBuf>,
    definitions: Vec<(String, Option<String>)>,
    objects: Vec<PathBuf>,
    flags: Vec<String>,
    files: Vec<PathBuf>,
}

fn getenv(v: &str) -> Option<String> {
    let r = env::var(v).ok();
    println!("{} = {:?}", v, r);
    r
}

fn getenv_unwrap(v: &str) -> String {
    match getenv(v) {
        Some(s) => s,
        None => fail(&format!("environment variable `{}` not defined", v)),
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// This function will also print all metadata on standard output for Cargo.
///
/// # Example
///
/// ```no_run
/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
/// ```
pub fn compile_library(output: &str, files: &[&str]) {
    let mut c = Config::new();
    for f in files.iter() {
        c.file(*f);
    }
    c.compile(output)
}

impl Config {
    /// Construct a new instance of a blank set of configuration.
    ///
    /// This builder is finished with the `compile` function.
    pub fn new() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
            flags: Vec::new(),
            files: Vec::new(),
        }
    }

    /// Add a directory to the `-I` or include path for headers
    pub fn include<P: AsPath>(&mut self, dir: P) -> &mut Config {
        self.include_directories.push(dir.as_path().to_path_buf());
        self
    }

    /// Specify a `-D` variable with an optional value.
    pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config {
        self.definitions.push((var.to_string(), val.map(|s| s.to_string())));
        self
    }

    /// Add an arbitrary object file to link in
    pub fn object<P: AsPath>(&mut self, obj: P) -> &mut Config {
        self.objects.push(obj.as_path().to_path_buf());
        self
    }

    /// Add an arbitrary flag to the invocation of the compiler
    pub fn flag(&mut self, flag: &str) -> &mut Config {
        self.flags.push(flag.to_string());
        self
    }

    /// Add a file which will be compiled
    pub fn file<P: AsPath>(&mut self, p: P) -> &mut Config {
        self.files.push(p.as_path().to_path_buf());
        self
    }

    /// Run the compiler, generating the file `output`
    ///
    /// The name `output` must begin with `lib` and end with `.a`
    pub fn compile(&self, output: &str) {
        assert!(output.starts_with("lib"));
        assert!(output.ends_with(".a"));

        let target = getenv_unwrap("TARGET");
        let src = PathBuf::new(&getenv_unwrap("CARGO_MANIFEST_DIR"));
        let dst = PathBuf::new(&getenv_unwrap("OUT_DIR"));
        let mut objects = Vec::new();
        for file in self.files.iter() {
            let mut cmd = self.gcc();
            let obj = dst.join(file).with_extension("o");
            fs::create_dir_all(&obj.parent().unwrap()).unwrap();
            run(cmd.arg(&src.join(file)).arg("-o").arg(&obj),
                &gcc(&target));
            objects.push(obj);
        }

        run(Command::new(&ar(&target)).arg("crus")
                                      .arg(&dst.join(output))
                                      .args(&objects)
                                      .args(&self.objects),
            &ar(&target));
        println!("cargo:rustc-link-search=native={}", dst.display());
        println!("cargo:rustc-link-lib=static={}",
                 &output[3..output.len() - 2]);
    }

    fn gcc(&self) -> Command {
        let target = getenv_unwrap("TARGET");
        let opt_level = getenv_unwrap("OPT_LEVEL");
        let profile = getenv_unwrap("PROFILE");
        println!("{} {}", profile, opt_level);

        let mut cmd = Command::new(&gcc(&target));
        cmd.arg(&format!("-O{}", opt_level));
        cmd.arg("-c");
        cmd.arg("-ffunction-sections").arg("-fdata-sections");
        cmd.args(&cflags());

        if target.contains("-ios") {
            cmd.args(&ios_flags(&target));
        } else {
            if target.contains("windows") {
                cmd.arg("-mwin32");
            }

            if target.contains("i686") {
                cmd.arg("-m32");
            } else if target.contains("x86_64") {
                cmd.arg("-m64");
            }

            if !target.contains("i686") {
                cmd.arg("-fPIC");
            }
        }

        for directory in self.include_directories.iter() {
            cmd.arg("-I").arg(directory);
        }

        for flag in self.flags.iter() {
            cmd.arg(flag);
        }

        for &(ref key, ref value) in self.definitions.iter() {
            if let &Some(ref value) = value {
                cmd.arg(&format!("-D{}={}", key, value));
            } else {
                cmd.arg(&format!("-D{}", key));
            }
        }
        return cmd;
    }
}

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

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv_unwrap("TARGET");
    let host = getenv_unwrap("HOST");
    let kind = if host == target {"HOST"} else {"TARGET"};
    let target_u = target.replace("-", "_");
    let res = getenv(&format!("{}_{}", var_base, target))
        .or_else(|| getenv(&format!("{}_{}", var_base, target_u)))
        .or_else(|| getenv(&format!("{}_{}", kind, var_base)))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty())
       .map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    enum ArchSpec {
        Device(&'static str),
        Simulator(&'static str),
    }

    let mut res = Vec::new();

    let arch = target.split('-').nth(0).expect("expected target in format `arch-vendor-os`");
    let arch = match arch {
        "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
        "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
        "arm64" | "aarch64" => ArchSpec::Device("arm64"),
        "i386" | "i686" => ArchSpec::Simulator("-m32"),
        "x86_64" => ArchSpec::Simulator("-m64"),
        _ => unreachable!("Unknown arch for iOS target")
    };

    let sdk = match arch {
        ArchSpec::Device(arch) => {
            res.push("-arch".to_string());
            res.push(arch.to_string());
            "iphoneos"
        },
        ArchSpec::Simulator(arch) => {
            res.push(arch.to_string());
            "iphonesimulator"
        }
    };

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(Stdio::inherit())
        .output()
        .unwrap()
        .stdout;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot".to_string());
    res.push(sdk_path.trim().to_string());

    res
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    panic!()
}
<|endoftext|>


<commit_before>extern crate conduit;

use std::error::Error;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync {
    fn before(&self, _: &mut Request) -> Result<(), Box<Error+Send>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Error+Send>>)
             -> Result<Response, Box<Error+Send>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Sync>>,
    handler: Option<Box<Handler + Send + Sync>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(Box::new(handler) as Box<Handler + Send + Sync>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(Box::new(middleware) as Box<Middleware + Send + Sync>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(Box::new(middleware) as Box<Handler + Send + Sync>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = self.middlewares.slice_to(i);
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Error+Send>>)
                  -> Result<Response, Box<Error+Send>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::collections::HashMap;
    use std::error::Error;
    use std::io::net::ip::IpAddr;
    use std::io::{self, MemReader};

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions};
    use conduit::{Handler, TypeMap};

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<u64> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Error+Send>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Error+Send>>)
                     -> Result<Response, Box<Error+Send>>
        {
            res.or_else(|e| {
                let e = e.description().to_string();
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: Box::new(MemReader::new(e.into_bytes()))
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Error+Send>> {
            Err(Box::new(io::standard_error(io::OtherIoError)) as Box<Error+Send>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Error+Send>>)
                     -> Result<Response, Box<Error+Send>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(MemReader::new(vec!()))
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Sync>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(MemReader::new(string.into_bytes()))
        }
    }

    fn handler(req: &mut Request) -> Result<Response, Box<Error+Send>> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, Box<Error+Send>> {
        Err(Box::new(io::IoError {
            kind: io::OtherIoError,
            desc: "Error in handler",
            detail: None,
        }) as Box<Error+Send>)
    }

    fn middle_handler(req: &mut Request) -> Result<Response, Box<Error+Send>> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello".to_string());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_string().ok().expect("No body"), "Error in handler".to_string());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello hello".to_string());
    }
}
<commit_msg>Add some feature attributes<commit_after>#![feature(core)]
#![cfg_attr(test, feature(io, collections))]

extern crate conduit;

use std::error::Error;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync {
    fn before(&self, _: &mut Request) -> Result<(), Box<Error+Send>> {
        Ok(())
    }

    fn after(&self, _: &mut Request, res: Result<Response, Box<Error+Send>>)
             -> Result<Response, Box<Error+Send>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<Handler + Send + Sync>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<Middleware + Send + Sync>>,
    handler: Option<Box<Handler + Send + Sync>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(Box::new(handler) as Box<Handler + Send + Sync>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(Box::new(middleware) as Box<Middleware + Send + Sync>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(Box::new(middleware) as Box<Handler + Send + Sync>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = &self.middlewares[..i];
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = self.middlewares.as_slice();

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<Middleware>],
                  req: &mut Request,
                  res: Result<Response, Box<Error+Send>>)
                  -> Result<Response, Box<Error+Send>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::collections::HashMap;
    use std::error::Error;
    use std::old_io::net::ip::IpAddr;
    use std::old_io::{self, MemReader};

    use conduit;
    use conduit::{Request, Response, Host, Headers, Method, Scheme, Extensions};
    use conduit::{Handler, TypeMap};

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: TypeMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<u64> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut Request) -> Result<(), Box<Error+Send>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut Request, res: Result<Response, Box<Error+Send>>)
                     -> Result<Response, Box<Error+Send>>
        {
            res.or_else(|e| {
                let e = e.description().to_string();
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: Box::new(MemReader::new(e.into_bytes()))
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut Request) -> Result<(), Box<Error+Send>> {
            Err(Box::new(old_io::standard_error(old_io::OtherIoError)) as Box<Error+Send>)
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut Request, _: Result<Response, Box<Error+Send>>)
                     -> Result<Response, Box<Error+Send>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(MemReader::new(vec!()))
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<Handler + Send + Sync>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<Handler + Send + Sync>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    fn get_extension<'a, T: 'static>(req: &'a Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(MemReader::new(string.into_bytes()))
        }
    }

    fn handler(req: &mut Request) -> Result<Response, Box<Error+Send>> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut Request) -> Result<Response, Box<Error+Send>> {
        Err(Box::new(old_io::IoError {
            kind: old_io::OtherIoError,
            desc: "Error in handler",
            detail: None,
        }) as Box<Error+Send>)
    }

    fn middle_handler(req: &mut Request) -> Result<Response, Box<Error+Send>> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello".to_string());
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        assert_eq!(res.body.read_to_string().ok().expect("No body"), "Error in handler".to_string());
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        assert_eq!(res.body.read_to_string().ok().expect("No body"), "hello hello".to_string());
    }
}
<|endoftext|>