<commit_before>//! Support for ANSI terminal colors via the colored crate.
//!
//! To enable support for colors, add the `"colored"` feature in your
//! `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! fern = { version = "0.5", features = ["colored"] }
//! ```
//!
//! ---
//!
//! Colors are mainly supported via coloring the log level itself, but it's
//! also possible to color each entire log line based off of the log level.
//!
//! First, here's an example which colors the log levels themselves ("INFO" /
//! "WARN" text will have color, but won't color the rest of the line).
//! [`ColoredLevelConfig`] lets us configure the colors per-level, but also has
//! sane defaults.
//!
//! ```
//! use fern::colors::{Color, ColoredLevelConfig};
//!
//! let mut colors = ColoredLevelConfig::new()
//!     // use builder methods
//!     .info(Color::Green);
//! // or access raw fields
//! colors.warn = Color::Magenta;
//! ```
//!
//! It can then be used within any regular fern formatting closure:
//!
//! ```
//! # let colors = fern::colors::ColoredLevelConfig::new();
//! fern::Dispatch::new()
//!     // ...
//!     .format(move |out, message, record| {
//!         out.finish(format_args!(
//!             "[{}] {}",
//!             // just use 'colors.color(..)' instead of the level
//!             // itself to insert ANSI colors.
//!             colors.color(record.level()),
//!             message,
//!         ))
//!     })
//!     # .into_log();
//! ```
//!
//! ---
//!
//! Coloring levels is nice, but the alternative is good to. For an example
//! application coloring each entire log line with the right color, see
//! [examples/pretty-colored.rs][ex].
//!
//! [`ColoredLevelConfig`]: struct.ColoredLevelConfig.html
//! [ex]: https://github.com/daboross/fern/blob/master/examples/pretty-colored.rs
use std::fmt;

pub use colored::Color;
use log::Level;

/// Extension crate allowing the use of `.colored` on Levels.
trait ColoredLogLevel {
    /// Colors this log level with the given color.
    fn colored(&self, color: Color) -> WithFgColor<Level>;
}

/// Opaque structure which represents some text data and a color to display it
/// with.
///
/// This implements [`fmt::Display`] to displaying the inner text (usually a
/// log level) with ANSI color markers before to set the color and after to
/// reset the color.
///
/// `WithFgColor` instances can be created and displayed without any allocation.
// this is necessary in order to avoid using colored::ColorString, which has a
// Display implementation involving many allocations, and would involve two
// more string allocations even to create it.
//
// [`fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
pub struct WithFgColor<T>
where
    T: fmt::Display,
{
    text: T,
    color: Color,
}

impl<T> fmt::Display for WithFgColor<T>
where
    T: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\x1B[{}m", self.color.to_fg_str())?;
        fmt::Display::fmt(&self.text, f)?;
        write!(f, "\x1B[0m")?;
        Ok(())
    }
}

/// Configuration specifying colors a log level can be colored as.
///
/// Example usage setting custom 'info' and 'debug' colors:
///
/// ```
/// use fern::colors::{Color, ColoredLevelConfig};
///
/// let colors = ColoredLevelConfig::new()
///     .info(Color::Green)
///     .debug(Color::Magenta);
///
/// fern::Dispatch::new()
///     .format(move |out, message, record| {
///         out.finish(format_args!(
///             "[{}] {}",
///             colors.color(record.level()),
///             message
///         ))
///     })
///     .chain(std::io::stdout())
/// # /*
///     .apply()?;
/// # */
/// #   .into_log();
/// ```
#[derive(Copy, Clone)]
#[must_use = "builder methods take config by value and thus must be reassigned to variable"]
pub struct ColoredLevelConfig {
    /// The color to color logs with the [`Error`] level.
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    pub error: Color,
    /// The color to color logs with the [`Warn`] level.
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    pub warn: Color,
    /// The color to color logs with the [`Info`] level.
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    pub info: Color,
    /// The color to color logs with the [`Debug`] level.
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    pub debug: Color,
    /// The color to color logs with the [`Trace`] level.
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    pub trace: Color,
}

impl ColoredLevelConfig {
    /// Creates a new ColoredLevelConfig with the default colors.
    ///
    /// This matches the behavior of [`ColoredLevelConfig::default`].
    ///
    /// [`ColoredLevelConfig::default`]: #method.default
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Overrides the [`Error`] level color with the given color.
    ///
    /// The default color is [`Color::Red`].
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    pub fn error(mut self, error: Color) -> Self {
        self.error = error;
        self
    }

    /// Overrides the [`Warn`] level color with the given color.
    ///
    /// The default color is [`Color::Yellow`].
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    pub fn warn(mut self, warn: Color) -> Self {
        self.warn = warn;
        self
    }

    /// Overrides the [`Info`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn info(mut self, info: Color) -> Self {
        self.info = info;
        self
    }

    /// Overrides the [`Debug`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn debug(mut self, debug: Color) -> Self {
        self.debug = debug;
        self
    }

    /// Overrides the [`Trace`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn trace(mut self, trace: Color) -> Self {
        self.trace = trace;
        self
    }

    /// Colors the given log level with the color in this configuration
    /// corresponding to it's level.
    ///
    /// The structure returned is opaque, but will print the Level surrounded
    /// by ANSI color codes when displayed. This will work correctly for
    /// UNIX terminals, but due to a lack of support from the [`colored`]
    /// crate, this will not function in Windows.
    ///
    /// [`colored`]: https://github.com/mackwic/colored
    pub fn color(&self, level: Level) -> WithFgColor<Level> {
        level.colored(self.get_color(&level))
    }

    /// Retrieves the color that a log level should be colored as.
    pub fn get_color(&self, level: &Level) -> Color {
        match *level {
            Level::Error => self.error,
            Level::Warn => self.warn,
            Level::Info => self.info,
            Level::Debug => self.debug,
            Level::Trace => self.trace,
        }
    }
}

impl Default for ColoredLevelConfig {
    /// Retrieves the default configuration. This has:
    ///
    /// - [`Error`] as [`Color::Red`]
    /// - [`Warn`] as [`Color::Yellow`]
    /// - [`Info`] as [`Color::White`]
    /// - [`Debug`] as [`Color::White`]
    /// - [`Trace`] as [`Color::White`]
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    fn default() -> Self {
        ColoredLevelConfig {
            error: Color::Red,
            warn: Color::Yellow,
            debug: Color::White,
            info: Color::White,
            trace: Color::White,
        }
    }
}

impl ColoredLogLevel for Level {
    fn colored(&self, color: Color) -> WithFgColor<Level> {
        WithFgColor {
            text: *self,
            color: color,
        }
    }
}

#[cfg(test)]
mod test {
    use colored::Color::*;
    use colored::Colorize;

    use super::WithFgColor;

    #[test]
    fn fg_color_matches_colored_behavior() {
        for &color in &[
            Black,
            Red,
            Green,
            Yellow,
            Blue,
            Magenta,
            Cyan,
            White,
            BrightBlack,
            BrightRed,
            BrightGreen,
            BrightYellow,
            BrightBlue,
            BrightMagenta,
            BrightCyan,
            BrightWhite,
        ] {
            assert_eq!(
                format!("{}", "test".color(color)),
                format!(
                    "{}",
                    WithFgColor {
                        text: "test",
                        color: color,
                    }
                )
            );
            assert_eq!(
                format!("{:^7}", "test".color(color)),
                format!(
                    "{:^7}",
                    WithFgColor {
                        text: "test",
                        color: color,
                    }
                )
            );
        }
    }
}
<commit_msg>better test for colored formatting flags<commit_after>//! Support for ANSI terminal colors via the colored crate.
//!
//! To enable support for colors, add the `"colored"` feature in your
//! `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! fern = { version = "0.5", features = ["colored"] }
//! ```
//!
//! ---
//!
//! Colors are mainly supported via coloring the log level itself, but it's
//! also possible to color each entire log line based off of the log level.
//!
//! First, here's an example which colors the log levels themselves ("INFO" /
//! "WARN" text will have color, but won't color the rest of the line).
//! [`ColoredLevelConfig`] lets us configure the colors per-level, but also has
//! sane defaults.
//!
//! ```
//! use fern::colors::{Color, ColoredLevelConfig};
//!
//! let mut colors = ColoredLevelConfig::new()
//!     // use builder methods
//!     .info(Color::Green);
//! // or access raw fields
//! colors.warn = Color::Magenta;
//! ```
//!
//! It can then be used within any regular fern formatting closure:
//!
//! ```
//! # let colors = fern::colors::ColoredLevelConfig::new();
//! fern::Dispatch::new()
//!     // ...
//!     .format(move |out, message, record| {
//!         out.finish(format_args!(
//!             "[{}] {}",
//!             // just use 'colors.color(..)' instead of the level
//!             // itself to insert ANSI colors.
//!             colors.color(record.level()),
//!             message,
//!         ))
//!     })
//!     # .into_log();
//! ```
//!
//! ---
//!
//! Coloring levels is nice, but the alternative is good to. For an example
//! application coloring each entire log line with the right color, see
//! [examples/pretty-colored.rs][ex].
//!
//! [`ColoredLevelConfig`]: struct.ColoredLevelConfig.html
//! [ex]: https://github.com/daboross/fern/blob/master/examples/pretty-colored.rs
use std::fmt;

pub use colored::Color;
use log::Level;

/// Extension crate allowing the use of `.colored` on Levels.
trait ColoredLogLevel {
    /// Colors this log level with the given color.
    fn colored(&self, color: Color) -> WithFgColor<Level>;
}

/// Opaque structure which represents some text data and a color to display it
/// with.
///
/// This implements [`fmt::Display`] to displaying the inner text (usually a
/// log level) with ANSI color markers before to set the color and after to
/// reset the color.
///
/// `WithFgColor` instances can be created and displayed without any allocation.
// this is necessary in order to avoid using colored::ColorString, which has a
// Display implementation involving many allocations, and would involve two
// more string allocations even to create it.
//
// [`fmt::Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
pub struct WithFgColor<T>
where
    T: fmt::Display,
{
    text: T,
    color: Color,
}

impl<T> fmt::Display for WithFgColor<T>
where
    T: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "\x1B[{}m", self.color.to_fg_str())?;
        fmt::Display::fmt(&self.text, f)?;
        write!(f, "\x1B[0m")?;
        Ok(())
    }
}

/// Configuration specifying colors a log level can be colored as.
///
/// Example usage setting custom 'info' and 'debug' colors:
///
/// ```
/// use fern::colors::{Color, ColoredLevelConfig};
///
/// let colors = ColoredLevelConfig::new()
///     .info(Color::Green)
///     .debug(Color::Magenta);
///
/// fern::Dispatch::new()
///     .format(move |out, message, record| {
///         out.finish(format_args!(
///             "[{}] {}",
///             colors.color(record.level()),
///             message
///         ))
///     })
///     .chain(std::io::stdout())
/// # /*
///     .apply()?;
/// # */
/// #   .into_log();
/// ```
#[derive(Copy, Clone)]
#[must_use = "builder methods take config by value and thus must be reassigned to variable"]
pub struct ColoredLevelConfig {
    /// The color to color logs with the [`Error`] level.
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    pub error: Color,
    /// The color to color logs with the [`Warn`] level.
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    pub warn: Color,
    /// The color to color logs with the [`Info`] level.
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    pub info: Color,
    /// The color to color logs with the [`Debug`] level.
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    pub debug: Color,
    /// The color to color logs with the [`Trace`] level.
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    pub trace: Color,
}

impl ColoredLevelConfig {
    /// Creates a new ColoredLevelConfig with the default colors.
    ///
    /// This matches the behavior of [`ColoredLevelConfig::default`].
    ///
    /// [`ColoredLevelConfig::default`]: #method.default
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    /// Overrides the [`Error`] level color with the given color.
    ///
    /// The default color is [`Color::Red`].
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    pub fn error(mut self, error: Color) -> Self {
        self.error = error;
        self
    }

    /// Overrides the [`Warn`] level color with the given color.
    ///
    /// The default color is [`Color::Yellow`].
    ///
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    pub fn warn(mut self, warn: Color) -> Self {
        self.warn = warn;
        self
    }

    /// Overrides the [`Info`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn info(mut self, info: Color) -> Self {
        self.info = info;
        self
    }

    /// Overrides the [`Debug`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn debug(mut self, debug: Color) -> Self {
        self.debug = debug;
        self
    }

    /// Overrides the [`Trace`] level color with the given color.
    ///
    /// The default color is [`Color::White`].
    ///
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    pub fn trace(mut self, trace: Color) -> Self {
        self.trace = trace;
        self
    }

    /// Colors the given log level with the color in this configuration
    /// corresponding to it's level.
    ///
    /// The structure returned is opaque, but will print the Level surrounded
    /// by ANSI color codes when displayed. This will work correctly for
    /// UNIX terminals, but due to a lack of support from the [`colored`]
    /// crate, this will not function in Windows.
    ///
    /// [`colored`]: https://github.com/mackwic/colored
    pub fn color(&self, level: Level) -> WithFgColor<Level> {
        level.colored(self.get_color(&level))
    }

    /// Retrieves the color that a log level should be colored as.
    pub fn get_color(&self, level: &Level) -> Color {
        match *level {
            Level::Error => self.error,
            Level::Warn => self.warn,
            Level::Info => self.info,
            Level::Debug => self.debug,
            Level::Trace => self.trace,
        }
    }
}

impl Default for ColoredLevelConfig {
    /// Retrieves the default configuration. This has:
    ///
    /// - [`Error`] as [`Color::Red`]
    /// - [`Warn`] as [`Color::Yellow`]
    /// - [`Info`] as [`Color::White`]
    /// - [`Debug`] as [`Color::White`]
    /// - [`Trace`] as [`Color::White`]
    ///
    /// [`Error`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Error
    /// [`Warn`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Warn
    /// [`Info`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Info
    /// [`Debug`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Debug
    /// [`Trace`]: https://docs.rs/log/0.4/log/enum.Level.html#variant.Trace
    /// [`Color::White`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.White
    /// [`Color::Yellow`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Yellow
    /// [`Color::Red`]: https://docs.rs/colored/1/colored/enum.Color.html#variant.Red
    fn default() -> Self {
        ColoredLevelConfig {
            error: Color::Red,
            warn: Color::Yellow,
            debug: Color::White,
            info: Color::White,
            trace: Color::White,
        }
    }
}

impl ColoredLogLevel for Level {
    fn colored(&self, color: Color) -> WithFgColor<Level> {
        WithFgColor {
            text: *self,
            color: color,
        }
    }
}

#[cfg(test)]
mod test {
    use colored::Color::*;
    use colored::Colorize;

    use super::WithFgColor;

    #[test]
    fn fg_color_matches_colored_behavior() {
        for &color in &[
            Black,
            Red,
            Green,
            Yellow,
            Blue,
            Magenta,
            Cyan,
            White,
            BrightBlack,
            BrightRed,
            BrightGreen,
            BrightYellow,
            BrightBlue,
            BrightMagenta,
            BrightCyan,
            BrightWhite,
        ] {
            assert_eq!(
                format!("{}", "test".color(color)),
                format!(
                    "{}",
                    WithFgColor {
                        text: "test",
                        color: color,
                    }
                )
            );
        }
    }

    #[test]
    fn fg_color_respects_formatting_flags() {
        let s = format!(
            "{:^8}",
            WithFgColor {
                text: "test",
                color: Yellow,
            }
        );
        assert!(s.contains("  test  "));
        assert!(!s.contains("   test  "));
        assert!(!s.contains("  test   "));
    }
}
<|endoftext|>


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

//! Private functions and items to be used with the high-level library wrapper.

use std::cast;
use std::hashmap::*;
use std::libc::*;
use std::local_data::*;
use std::ptr;
use std::str;

use super::*;

///
/// Holds the callback functions associated with a window
///
pub struct WindowData {
    pos_fun:                Option<WindowPosFun>,
    size_fun:               Option<WindowSizeFun>,
    close_fun:              Option<WindowCloseFun>,
    refresh_fun:            Option<WindowRefreshFun>,
    focus_fun:              Option<WindowFocusFun>,
    iconify_fun:            Option<WindowIconifyFun>,
    framebuffer_size_fun:   Option<FramebufferSizeFun>,
    mouse_button_fun:       Option<MouseButtonFun>,
    cursor_pos_fun:         Option<CursorPosFun>,
    cursor_enter_fun:       Option<CursorEnterFun>,
    scroll_fun:             Option<ScrollFun>,
    key_fun:                Option<KeyFun>,
    char_fun:               Option<CharFun>,
}

impl WindowData {
    /// Initialize the struct with all callbacks set to `None`.
    pub fn new() -> WindowData {
        WindowData {
            pos_fun:                None,
            size_fun:               None,
            close_fun:              None,
            refresh_fun:            None,
            focus_fun:              None,
            iconify_fun:            None,
            framebuffer_size_fun:   None,
            mouse_button_fun:       None,
            cursor_pos_fun:         None,
            cursor_enter_fun:       None,
            scroll_fun:             None,
            key_fun:                None,
            char_fun:               None,
        }
    }
}

///
/// A map of window data to be stored in task-local storage.
///
pub struct WindowDataMap(HashMap<*ffi::GLFWwindow, @mut WindowData>);

impl WindowDataMap {
    /// Function stub used for retrieving a the map of window data from
    /// task-local storage.
    priv fn tls_key(_: @@mut WindowDataMap) {}

    /// Initializes a map of window data in task-local storage.
    pub fn init() {
        unsafe {
            local_data_set(
                WindowDataMap::tls_key,
                @@mut WindowDataMap(HashMap::new())
            )
        }
    }

    /// Retrieves a mutable pointer to the map of window data stored task-local
    /// storage, failing if the map could not be found.
    pub fn get() -> @mut WindowDataMap {
        match unsafe { local_data_get(WindowDataMap::tls_key) } {
            Some(@local_data) => local_data,
            None => fail!("Could not find a WindowDataMap in thread-local storage."),
        }
    }

    /// Clears all external callbacks and removes the window from the map.
    /// Returns `true` if the window was present in the map, otherwise `false`.
    pub fn remove(&mut self, window: &*ffi::GLFWwindow) -> bool {
        do self.pop(window).map |&data| {
            unsafe {
                // Clear all external callbacks
                data.pos_fun.map                (|_| ffi::glfwSetWindowPosCallback(*window, ptr::null()));
                data.size_fun.map               (|_| ffi::glfwSetWindowSizeCallback(*window, ptr::null()));
                data.close_fun.map              (|_| ffi::glfwSetWindowCloseCallback(*window, ptr::null()));
                data.refresh_fun.map            (|_| ffi::glfwSetWindowRefreshCallback(*window, ptr::null()));
                data.focus_fun.map              (|_| ffi::glfwSetWindowFocusCallback(*window, ptr::null()));
                data.iconify_fun.map            (|_| ffi::glfwSetWindowIconifyCallback(*window, ptr::null()));
                data.framebuffer_size_fun.map   (|_| ffi::glfwSetFramebufferSizeCallback(*window, ptr::null()));
                data.mouse_button_fun.map       (|_| ffi::glfwSetMouseButtonCallback(*window, ptr::null()));
                data.cursor_pos_fun.map         (|_| ffi::glfwSetCursorPosCallback(*window, ptr::null()));
                data.cursor_enter_fun.map       (|_| ffi::glfwSetCursorEnterCallback(*window, ptr::null()));
                data.scroll_fun.map             (|_| ffi::glfwSetScrollCallback(*window, ptr::null()));
                data.key_fun.map                (|_| ffi::glfwSetKeyCallback(*window, ptr::null()));
                data.char_fun.map               (|_| ffi::glfwSetCharCallback(*window, ptr::null()));
            }
        }.is_some()
    }
}

// Global callbacks

fn error_fun_tls_key(_: @ErrorFun) {}

pub extern "C" fn error_callback(error: c_int, description: *c_char) {
    unsafe {
        do local_data_get(error_fun_tls_key).map |&@cb| {
            cb(error, str::raw::from_c_str(description))
        };
    }
}

pub fn set_error_fun(cbfun: ErrorFun, f: &fn(ffi::GLFWerrorfun) ) {
    unsafe {
        local_data_set(error_fun_tls_key, @cbfun);
        f(error_callback);
    }
}

fn monitor_fun_tls_key(_: @MonitorFun) {}

pub extern "C" fn monitor_callback(monitor: *ffi::GLFWmonitor, event: c_int) {
    unsafe {
        do local_data_get(monitor_fun_tls_key).map |&@cb| {
            cb(&Monitor { ptr: monitor }, event)
        };
    }
}

pub fn set_monitor_fun(cbfun: MonitorFun, f: &fn(ffi::GLFWmonitorfun) ) {
    unsafe {
        local_data_set(monitor_fun_tls_key, @cbfun);
        f(monitor_callback);
    }
}

// External window callbacks

macro_rules! window_callback(
    (fn $name:ident () => $field:ident()) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            let window_ = Window { ptr: window };
            do window_.get_local_data().$field.map |&cb| {
                cb(&window_)
            };
            unsafe { cast::forget(window_); }
        }
    );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $field:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            let window_ = Window { ptr: window };
            do window_.get_local_data().$field.map |&cb| {
                cb(&window_ $(, $arg_conv)*)
            };
            unsafe { cast::forget(window_); }
        }
    );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => pos_fun(xpos as int, ypos as int))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => size_fun(width as int, height as int))
window_callback!(fn window_close_callback()                                                 => close_fun())
window_callback!(fn window_refresh_callback()                                               => refresh_fun())
window_callback!(fn window_focus_callback(focused: c_int)                                   => focus_fun(focused as bool))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => iconify_fun(iconified as bool))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => framebuffer_size_fun(width as int, height as int))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => mouse_button_fun(button, action, mods))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => cursor_pos_fun(xpos as float, ypos as float))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => cursor_enter_fun(entered as bool))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => scroll_fun(xpos as float, ypos as float))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => key_fun(key, scancode, action, mods))
window_callback!(fn char_callback(character: c_uint)                                        => char_fun(character as char))
<commit_msg>Replaced local_data_{set, get} by local_data::{set, get}.<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private functions and items to be used with the high-level library wrapper.

use std::cast;
use std::hashmap::*;
use std::libc::*;
use std::local_data;
use std::ptr;
use std::str;

use super::*;

///
/// Holds the callback functions associated with a window
///
pub struct WindowData {
    pos_fun:                Option<WindowPosFun>,
    size_fun:               Option<WindowSizeFun>,
    close_fun:              Option<WindowCloseFun>,
    refresh_fun:            Option<WindowRefreshFun>,
    focus_fun:              Option<WindowFocusFun>,
    iconify_fun:            Option<WindowIconifyFun>,
    framebuffer_size_fun:   Option<FramebufferSizeFun>,
    mouse_button_fun:       Option<MouseButtonFun>,
    cursor_pos_fun:         Option<CursorPosFun>,
    cursor_enter_fun:       Option<CursorEnterFun>,
    scroll_fun:             Option<ScrollFun>,
    key_fun:                Option<KeyFun>,
    char_fun:               Option<CharFun>,
}

impl WindowData {
    /// Initialize the struct with all callbacks set to `None`.
    pub fn new() -> WindowData {
        WindowData {
            pos_fun:                None,
            size_fun:               None,
            close_fun:              None,
            refresh_fun:            None,
            focus_fun:              None,
            iconify_fun:            None,
            framebuffer_size_fun:   None,
            mouse_button_fun:       None,
            cursor_pos_fun:         None,
            cursor_enter_fun:       None,
            scroll_fun:             None,
            key_fun:                None,
            char_fun:               None,
        }
    }
}

///
/// A map of window data to be stored in task-local storage.
///
pub struct WindowDataMap(HashMap<*ffi::GLFWwindow, @mut WindowData>);

impl WindowDataMap {
    /// Function stub used for retrieving a the map of window data from
    /// task-local storage.
    priv fn tls_key(_: @@mut WindowDataMap) {}

    /// Initializes a map of window data in task-local storage.
    pub fn init() {
        unsafe {
            local_data::set(
                WindowDataMap::tls_key,
                @@mut WindowDataMap(HashMap::new())
            )
        }
    }

    /// Retrieves a mutable pointer to the map of window data stored task-local
    /// storage, failing if the map could not be found.
    pub fn get() -> @mut WindowDataMap {
      unsafe {
        do local_data::get(WindowDataMap::tls_key) |data|
        {
          match data
          {
            Some(&@local_data) => local_data,
            None => fail!("Could not find a WindowDataMap in thread-local storage."),
          }
        }
      }
    }

    /// Clears all external callbacks and removes the window from the map.
    /// Returns `true` if the window was present in the map, otherwise `false`.
    pub fn remove(&mut self, window: &*ffi::GLFWwindow) -> bool {
        do self.pop(window).map |&data| {
            unsafe {
                // Clear all external callbacks
                data.pos_fun.map                (|_| ffi::glfwSetWindowPosCallback(*window, ptr::null()));
                data.size_fun.map               (|_| ffi::glfwSetWindowSizeCallback(*window, ptr::null()));
                data.close_fun.map              (|_| ffi::glfwSetWindowCloseCallback(*window, ptr::null()));
                data.refresh_fun.map            (|_| ffi::glfwSetWindowRefreshCallback(*window, ptr::null()));
                data.focus_fun.map              (|_| ffi::glfwSetWindowFocusCallback(*window, ptr::null()));
                data.iconify_fun.map            (|_| ffi::glfwSetWindowIconifyCallback(*window, ptr::null()));
                data.framebuffer_size_fun.map   (|_| ffi::glfwSetFramebufferSizeCallback(*window, ptr::null()));
                data.mouse_button_fun.map       (|_| ffi::glfwSetMouseButtonCallback(*window, ptr::null()));
                data.cursor_pos_fun.map         (|_| ffi::glfwSetCursorPosCallback(*window, ptr::null()));
                data.cursor_enter_fun.map       (|_| ffi::glfwSetCursorEnterCallback(*window, ptr::null()));
                data.scroll_fun.map             (|_| ffi::glfwSetScrollCallback(*window, ptr::null()));
                data.key_fun.map                (|_| ffi::glfwSetKeyCallback(*window, ptr::null()));
                data.char_fun.map               (|_| ffi::glfwSetCharCallback(*window, ptr::null()));
            }
        }.is_some()
    }
}

// Global callbacks

fn error_fun_tls_key(_: @ErrorFun) {}

pub extern "C" fn error_callback(error: c_int, description: *c_char) {
    unsafe {
        do local_data::get(error_fun_tls_key) |data|
        {
          do data.map |& &@cb| {
            cb(error, str::raw::from_c_str(description))
          };
        }
    }
}

pub fn set_error_fun(cbfun: ErrorFun, f: &fn(ffi::GLFWerrorfun) ) {
    unsafe {
        local_data::set(error_fun_tls_key, @cbfun);
        f(error_callback);
    }
}

fn monitor_fun_tls_key(_: @MonitorFun) {}

pub extern "C" fn monitor_callback(monitor: *ffi::GLFWmonitor, event: c_int) {
    unsafe {
        do local_data::get(monitor_fun_tls_key) |data|
        {
          do data.map |& &@cb| {
            cb(&Monitor { ptr: monitor }, event)
          };
        }
    }
}

pub fn set_monitor_fun(cbfun: MonitorFun, f: &fn(ffi::GLFWmonitorfun) ) {
    unsafe {
        local_data::set(monitor_fun_tls_key, @cbfun);
        f(monitor_callback);
    }
}

// External window callbacks

macro_rules! window_callback(
    (fn $name:ident () => $field:ident()) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow) {
            let window_ = Window { ptr: window };
            do window_.get_local_data().$field.map |&cb| {
                cb(&window_)
            };
            unsafe { cast::forget(window_); }
        }
    );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $field:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            let window_ = Window { ptr: window };
            do window_.get_local_data().$field.map |&cb| {
                cb(&window_ $(, $arg_conv)*)
            };
            unsafe { cast::forget(window_); }
        }
    );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => pos_fun(xpos as int, ypos as int))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => size_fun(width as int, height as int))
window_callback!(fn window_close_callback()                                                 => close_fun())
window_callback!(fn window_refresh_callback()                                               => refresh_fun())
window_callback!(fn window_focus_callback(focused: c_int)                                   => focus_fun(focused as bool))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => iconify_fun(iconified as bool))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => framebuffer_size_fun(width as int, height as int))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => mouse_button_fun(button, action, mods))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => cursor_pos_fun(xpos as float, ypos as float))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => cursor_enter_fun(entered as bool))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => scroll_fun(xpos as float, ypos as float))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => key_fun(key, scancode, action, mods))
window_callback!(fn char_callback(character: c_uint)                                        => char_fun(character as char))
<|endoftext|>


<commit_before>extern crate rustc_serialize;

use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
use std::io::prelude::*;
use std::fs::File;

use self::rustc_serialize::json;

use ngrams::ngrams;

pub type StringCountPair = (String, usize);
pub struct Profile {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Profile {
    pub fn build_from_text(text: &str) -> Profile {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                *ngram_counts.entry(ngram).or_insert(0usize) += 1;
            }
        }

        let mut ngrams_and_counts = vec_from_hashmap(&ngram_counts);
        ngrams_and_counts.sort_by(cmp_counts_reverse);

        let mut ngram_ranks = HashMap::new();
        for (index, item) in ngrams_and_counts.iter().enumerate() {
            ngram_ranks.insert((*item).clone().0, index);
        }

        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn load_from_file(path: &str) -> Profile {
        let mut f = File::open(path).unwrap();
        let mut encoded_profile = String::new();
        f.read_to_string(&mut encoded_profile);
        let ngram_ranks = json::decode(&encoded_profile).unwrap();
        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn save_to_file(self, path: &str) {
        let encoded_profile = json::encode(&self.ngram_ranks).unwrap();
        let mut f = File::create(path).unwrap();
        f.write_all(encoded_profile.as_bytes()).unwrap();
    }
}

// useful utils

fn vec_from_hashmap<K, V> (hashmap: &HashMap<K, V>) -> Vec<(K, V)>
         where K: Eq + Hash + Clone, V: Clone {
    let mut vec: Vec<(K, V)> = Vec::new();
    for (key, value) in hashmap.iter() {
        let item = ((*key).clone(), (*value).clone());
        vec.push(item);
    }
    vec
}

fn cmp_counts_reverse(a: &StringCountPair, b: &StringCountPair) -> Ordering {
    b.1.cmp(&a.1)
}
<commit_msg>Make save_to_file borrow, rather than take profile<commit_after>extern crate rustc_serialize;

use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;
use std::io::prelude::*;
use std::fs::File;

use self::rustc_serialize::json;

use ngrams::ngrams;

pub type StringCountPair = (String, usize);
pub struct Profile {
    pub ngram_ranks: HashMap<String, usize>,
}

impl Profile {
    pub fn build_from_text(text: &str) -> Profile {
        let mut ngram_counts = HashMap::new();
        for n in 1..6 {
            for ngram in ngrams(text, n) {
                *ngram_counts.entry(ngram).or_insert(0usize) += 1;
            }
        }

        let mut ngrams_and_counts = vec_from_hashmap(&ngram_counts);
        ngrams_and_counts.sort_by(cmp_counts_reverse);

        let mut ngram_ranks = HashMap::new();
        for (index, item) in ngrams_and_counts.iter().enumerate() {
            ngram_ranks.insert((*item).clone().0, index);
        }

        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn load_from_file(path: &str) -> Profile {
        let mut f = File::open(path).unwrap();
        let mut encoded_profile = String::new();
        f.read_to_string(&mut encoded_profile);
        let ngram_ranks = json::decode(&encoded_profile).unwrap();
        Profile { ngram_ranks: ngram_ranks }
    }

    pub fn save_to_file(&self, path: &str) {
        let encoded_profile = json::encode(&self.ngram_ranks).unwrap();
        let mut f = File::create(path).unwrap();
        f.write_all(encoded_profile.as_bytes()).unwrap();
    }
}

// useful utils

fn vec_from_hashmap<K, V> (hashmap: &HashMap<K, V>) -> Vec<(K, V)>
         where K: Eq + Hash + Clone, V: Clone {
    let mut vec: Vec<(K, V)> = Vec::new();
    for (key, value) in hashmap.iter() {
        let item = ((*key).clone(), (*value).clone());
        vec.push(item);
    }
    vec
}

fn cmp_counts_reverse(a: &StringCountPair, b: &StringCountPair) -> Ordering {
    b.1.cmp(&a.1)
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

pub const NB_CHAR: char = ' '; // non breaking space
pub const NB_CHAR_NARROW: char = '\u{202F}'; // narrow non breaking space
pub const NB_CHAR_EM: char = '\u{2002}'; // demi em space
<commit_msg>Revert "Remove is_whitespace function as no longer used" since actually STILL used<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

pub const NB_CHAR: char = ' '; // non breaking space
pub const NB_CHAR_NARROW: char = '\u{202F}'; // narrow non breaking space
pub const NB_CHAR_EM: char = '\u{2002}'; // demi em space

/// Custom function because we don't really want to touch \t or \n
///
/// This function detects spaces and non breking spaces
pub fn is_whitespace(c: char) -> bool {
    c == ' ' || c == ' ' || c == ' '
}
<|endoftext|>


<commit_before>use datum::*;
use primitive::*;
use numeric::LNumeric;
use std::fun_treemap;
use std::fun_treemap::Treemap;
use core::num::Zero::zero;
use core::num::One::one;

struct Runtime {
    stdin: @io::Reader,
    stdout: @io::Writer,
    stderr: @io::Writer,
    global: Treemap<@str, @LDatum>,
    syntax: Treemap<@str, PrimSyntax>,
}

#[deriving(Eq)]
enum RuntimeError {
    UnboundVariable(@str),
    NotCallable,
    NotList,
    ArgNumError,
    TypeError,
    DivideByZeroError,
    NilEval,
}

impl ToStr for RuntimeError {
    fn to_str(&self) -> ~str {
        err_to_str(self)
    }
}

priv fn err_to_str(&err: &RuntimeError) -> ~str {
    match err {
        UnboundVariable(name) => ~"unbound variable: " + copy name,
        NotCallable => ~"not callable",
        NotList => ~"not list",
        ArgNumError => ~"bad number of arguments",
        TypeError => ~"type error",
        DivideByZeroError => ~"divide by zero",
        NilEval => ~"() cannot be evaluated",
    }
}

fn load_prelude() -> Treemap<@str, @LDatum> {
    let mut map = fun_treemap::init();
    for vec::each(prelude()) |&pair| {
        let (key, func) = pair;
        map = fun_treemap::insert(map, key, @LPrim(func));
    }
    map
}

fn load_prelude_macro() -> Treemap<@str, PrimSyntax> {
    let mut map = fun_treemap::init();
    for vec::each(syntax_prelude()) |&pair| {
        let (key, syntax) = pair;
        map = fun_treemap::insert(map, key, syntax);
    }
    map
}

priv fn call_prim1(args: ~[@LDatum],
                op: &fn(@LDatum) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 1 {
        op(args[0])
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_prim2(args: ~[@LDatum],
                    op: &fn(&LNumeric, &LNumeric) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 2 {
        match *args[0] {
            LNum(lhs) => match *args[1] {
                LNum(rhs) => op(&lhs, &rhs),
                _ => Err(TypeError),
            },
            _ => Err(TypeError),
        }
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_foldl(args: ~[@LDatum],
                    a0: LNumeric,
                    op: &fn(&LNumeric, &LNumeric) -> Result<LNumeric, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    let mut res = a0;
    let mut err = false;
    do args.each |&arg| {
        match *arg {
            LNum(a) => {
                match op(&res, &a) {
                    Ok(n) => {
                        res = n;
                        err = false;
                    },
                    _ => {
                        err = true;
                    }
                }
            },
            _ => {
                err = true;
            }
        }
        !err
    }
    if err {
        Err(TypeError)
    } else {
        Ok(@LNum(res))
    }
}

priv impl Runtime {
    fn get_syntax(&self, val: @LDatum) -> Option<PrimSyntax> {
        match *val {
            LIdent(name) => fun_treemap::find(self.syntax, name),
            _ => None,
        }
    }

    fn run_syntax(&self, syn: PrimSyntax, args: ~[@LDatum]) -> Result<@LDatum, RuntimeError> {
        match syn {
            SynIf => if args.len() == 3 {
                    do result::chain(self.eval(args[0])) |cond| {
                        match *cond {
                            LBool(true) => self.eval(args[1]),
                            LBool(false) => self.eval(args[2]),
                            _ => Err(TypeError),
                        }
                    }
                } else {
                    Err(ArgNumError)
                },
        }
    }

    fn call_prim(&self, f: PFunc, args: ~[@LDatum]) -> Result<@LDatum, RuntimeError> {
        match f {
            PEval => do call_prim1(args) |arg| {
                self.eval(arg)
            },
            PAdd => do call_num_foldl(args, zero()) |&lhs, &rhs| { Ok(lhs + rhs) },
            PSub => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs - rhs) },
            PMul => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs * rhs) },
            PDiv => do call_num_foldl(args, one()) |&lhs, &rhs| {
                if rhs.is_zero() {
                    Err(DivideByZeroError)
                } else {
                    Ok(lhs / rhs)
                }
            },
            PCar => do call_prim1(args) |arg| {
                match *arg {
                    LCons(h, _) => Ok(h),
                    _ => Err(TypeError),
                }
            },
            PCdr => do call_prim1(args) |arg| {
                match *arg {
                    LCons(_, t) => Ok(t),
                    _ => Err(TypeError),
                }
            },
        }
    }
}

pub impl Runtime {
    fn new_std() -> Runtime {
        Runtime {
            stdin: io::stdin(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            global: load_prelude(),
            syntax: load_prelude_macro(),
        }
    }

    fn eval(&self, val: @LDatum) -> Result<@LDatum, RuntimeError> {
        match *val {
            LIdent(name) =>
                match fun_treemap::find(self.global, name) {
                    Some(datum) => Ok(datum),
                    None => Err(UnboundVariable(name)),
                },
            LCons(fexpr, aexpr) =>
                match aexpr.to_list() {
                    None => Err(NotList),
                    Some(aexprs) => {
                        match self.get_syntax(fexpr) {
                            Some(syntax) =>
                                self.run_syntax(syntax, aexprs),
                            None =>
                                match self.eval(fexpr) {
                                    Ok(@LPrim(f)) => {
                                        match result::map_vec(aexprs, |&expr| self.eval(expr)) {
                                            Ok(args) => self.call_prim(f, args),
                                            Err(e) => Err(e),
                                        }
                                    }
                                    Ok(_) => Err(NotCallable),
                                    Err(e) => Err(e),
                                },
                        }
                    },
                },
            LQuote(val) => Ok(val),
            LNil => Err(NilEval),
            _ => Ok(val),
        }
    }

}
<commit_msg>make eval to use stack frame<commit_after>use datum::*;
use primitive::*;
use numeric::LNumeric;
use std::fun_treemap;
use std::fun_treemap::Treemap;
use core::num::Zero::zero;
use core::num::One::one;

struct Runtime {
    stdin: @io::Reader,
    stdout: @io::Writer,
    stderr: @io::Writer,
    global: Treemap<@str, @LDatum>,
    syntax: Treemap<@str, PrimSyntax>,
}

#[deriving(Eq)]
enum RuntimeError {
    UnboundVariable(@str),
    NotCallable,
    NotList,
    ArgNumError,
    TypeError,
    DivideByZeroError,
    NilEval,
}

impl ToStr for RuntimeError {
    fn to_str(&self) -> ~str {
        err_to_str(self)
    }
}

priv fn err_to_str(&err: &RuntimeError) -> ~str {
    match err {
        UnboundVariable(name) => ~"unbound variable: " + copy name,
        NotCallable => ~"not callable",
        NotList => ~"not list",
        ArgNumError => ~"bad number of arguments",
        TypeError => ~"type error",
        DivideByZeroError => ~"divide by zero",
        NilEval => ~"() cannot be evaluated",
    }
}

fn load_prelude() -> Treemap<@str, @LDatum> {
    let mut map = fun_treemap::init();
    for vec::each(prelude()) |&pair| {
        let (key, func) = pair;
        map = fun_treemap::insert(map, key, @LPrim(func));
    }
    map
}

fn load_prelude_macro() -> Treemap<@str, PrimSyntax> {
    let mut map = fun_treemap::init();
    for vec::each(syntax_prelude()) |&pair| {
        let (key, syntax) = pair;
        map = fun_treemap::insert(map, key, syntax);
    }
    map
}

priv fn call_prim1(args: ~[@LDatum],
                op: &fn(@LDatum) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 1 {
        op(args[0])
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_prim2(args: ~[@LDatum],
                    op: &fn(&LNumeric, &LNumeric) -> Result<@LDatum, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    if args.len() == 2 {
        match *args[0] {
            LNum(lhs) => match *args[1] {
                LNum(rhs) => op(&lhs, &rhs),
                _ => Err(TypeError),
            },
            _ => Err(TypeError),
        }
    } else {
        Err(ArgNumError)
    }
}

priv fn call_num_foldl(args: ~[@LDatum],
                    a0: LNumeric,
                    op: &fn(&LNumeric, &LNumeric) -> Result<LNumeric, RuntimeError>)
    -> Result<@LDatum, RuntimeError>
{
    let mut res = a0;
    let mut err = false;
    do args.each |&arg| {
        match *arg {
            LNum(a) => {
                match op(&res, &a) {
                    Ok(n) => {
                        res = n;
                        err = false;
                    },
                    _ => {
                        err = true;
                    }
                }
            },
            _ => {
                err = true;
            }
        }
        !err
    }
    if err {
        Err(TypeError)
    } else {
        Ok(@LNum(res))
    }
}

priv impl Runtime {
    fn get_syntax(&self, val: @LDatum) -> Option<PrimSyntax> {
        match *val {
            LIdent(name) => fun_treemap::find(self.syntax, name),
            _ => None,
        }
    }

    fn run_syntax(&self,
                syn: PrimSyntax,
                args: ~[@LDatum],
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match syn {
            SynIf => if args.len() == 3 {
                    do result::chain(self.eval_local(args[0], stack)) |cond| {
                        match *cond {
                            LBool(true) => self.eval_local(args[1], stack),
                            LBool(false) => self.eval_local(args[2], stack),
                            _ => Err(TypeError),
                        }
                    }
                } else {
                    Err(ArgNumError)
                },
        }
    }

    fn call_prim(&self,
                f: PFunc,
                args: ~[@LDatum],
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match f {
            PEval => do call_prim1(args) |arg| {
                self.eval_local(arg, stack)
            },
            PAdd => do call_num_foldl(args, zero()) |&lhs, &rhs| { Ok(lhs + rhs) },
            PSub => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs - rhs) },
            PMul => do call_num_foldl(args, one()) |&lhs, &rhs| { Ok(lhs * rhs) },
            PDiv => do call_num_foldl(args, one()) |&lhs, &rhs| {
                if rhs.is_zero() {
                    Err(DivideByZeroError)
                } else {
                    Ok(lhs / rhs)
                }
            },
            PCar => do call_prim1(args) |arg| {
                match *arg {
                    LCons(h, _) => Ok(h),
                    _ => Err(TypeError),
                }
            },
            PCdr => do call_prim1(args) |arg| {
                match *arg {
                    LCons(_, t) => Ok(t),
                    _ => Err(TypeError),
                }
            },
        }
    }

    fn eager_eval_prim(&self,
                f: PFunc,
                aexprs: &[@LDatum],
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match result::map_vec(aexprs,
                            |&expr| self.eval_local(expr, stack))
        {
            Ok(args) => self.call_prim(f, args, stack),
            Err(e) => Err(e),
        }
    }

    fn eval_local(&self,
                val: @LDatum,
                stack: Treemap<@str, @LDatum>) -> Result<@LDatum, RuntimeError>
    {
        match *val {
            LIdent(name) =>
                match fun_treemap::find(stack, name) {
                    Some(datum) => Ok(datum),
                    None => Err(UnboundVariable(name)),
                },
            LCons(fexpr, aexpr) =>
                match aexpr.to_list() {
                    None => Err(NotList),
                    Some(aexprs) => {
                        match self.get_syntax(fexpr) {
                            Some(syntax) =>
                                self.run_syntax(syntax, aexprs, stack),
                            None =>
                                match self.eval_local(fexpr, stack) {
                                    Ok(@LPrim(f)) => {
                                        self.eager_eval_prim(f, aexprs, stack)
                                    }
                                    Ok(_) => Err(NotCallable),
                                    Err(e) => Err(e),
                                },
                        }
                    },
                },
            LQuote(val) => Ok(val),
            LNil => Err(NilEval),
            _ => Ok(val),
        }
    }
}

pub impl Runtime {
    fn new_std() -> Runtime {
        Runtime {
            stdin: io::stdin(),
            stdout: io::stdout(),
            stderr: io::stderr(),
            global: load_prelude(),
            syntax: load_prelude_macro(),
        }
    }

    fn eval(&self, val: @LDatum) -> Result<@LDatum, RuntimeError> {
        self.eval_local(val, self.global)
    }
}
<|endoftext|>


<commit_before>use request::ToParams;

#[derive(Debug)]
pub enum Application {
    AppId(String, Option<String>),
    UserKey(String),
    OAuthToken(String)
}

impl Application {
    pub fn from_app_id(app_id: String) -> Self {
        Application::AppId(app_id, None)
    }

    pub fn from_app_id_and_key(app_id: String, app_key: String) -> Self {
        Application::AppId(app_id, Some(app_key))
    }

    pub fn from_user_key(user_key: String) -> Self {
        Application::UserKey(user_key)
    }

    pub fn from_oauth_token(token: String) -> Self {
        Application::OAuthToken(token)
    }
}

impl ToParams for Application {
    fn to_params(&self) -> Vec<(&str, &str)>{
        use self::Application::*;

        let (field, value) = match *self {
            AppId(ref app_id, None) => {
                ("app_id", app_id)
            },
            UserKey(ref user_key) => ("user_key", user_key),
            OAuthToken(ref token) => ("access_token", token),
            // TODO case where there's an app_key
            _ => unimplemented!()
        };

        vec![(field, value)]
    }
}
<commit_msg>application: support app_id with app_key<commit_after>use request::ToParams;

#[derive(Debug)]
pub enum Application {
    AppId(String, Option<String>),
    UserKey(String),
    OAuthToken(String)
}

impl Application {
    pub fn from_app_id(app_id: String) -> Self {
        Application::AppId(app_id, None)
    }

    pub fn from_app_id_and_key(app_id: String, app_key: String) -> Self {
        Application::AppId(app_id, Some(app_key))
    }

    pub fn from_user_key(user_key: String) -> Self {
        Application::UserKey(user_key)
    }

    pub fn from_oauth_token(token: String) -> Self {
        Application::OAuthToken(token)
    }
}

impl ToParams for Application {
    fn to_params(&self) -> Vec<(&str, &str)>{
        use self::Application::*;

        let mut v = Vec::<(&str, &str)>::with_capacity(2);
        match *self {
            AppId(ref app_id, None) => {
                v.push(("app_id", app_id));
            },
            AppId(ref app_id, Some(ref app_key)) => {
                v.push(("app_id", app_id));
                v.push(("app_key", app_key));
            },
            UserKey(ref user_key) => v.push(("user_key", user_key)),
            OAuthToken(ref token) => v.push(("access_token", token)),
        };

        v
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::HashMap;
use std::str::FromStr;

use chrono::{DateTime, UTC};
use reqwest;
use serde_json::{self, Value};

use errors::*;

#[derive(Debug, Deserialize)]
pub struct Errors {
    pub detail: String,
}

#[derive(Debug, Deserialize)]
pub struct ErrorResponse {
    pub errors: Vec<Errors>,
}

impl ErrorResponse {
    pub fn detail(&self) -> &str {
        self.errors.get(0).map(|x| x.detail.as_str()).unwrap_or("")
    }
}

impl FromStr for ErrorResponse {
    type Err = Error;
    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        serde_json::from_str(s).chain_err(|| "Failed to parse JSON")
    }
}

#[derive(Debug, Deserialize)]
pub struct BadgeData {
    pub badge_type: String,
    pub attributes: HashMap<String, String>,
}

#[derive(Debug, Deserialize)]
pub struct CategoryData {
    pub category: String,
    pub crates_cnt: i32,
    pub created_at: DateTime<UTC>,
    pub description: String,
    pub id: String,
    pub slug: String,
}

#[derive(Debug, Deserialize)]
pub struct CrateLinks {
    pub version_downloads: String,
    pub versions: Option<String>,
    pub owners: Option<String>,
    pub reverse_dependencies: String,
}

#[derive(Debug, Deserialize)]
pub struct KeywordData {
    pub crates_cnt: i32,
    pub created_at: DateTime<UTC>,
    pub id: String,
    pub keyword: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionLinks {
    pub authors: String,
    pub dependencies: String,
    pub version_downloads: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionData {
    #[serde(rename(deserialize = "crate"))]
    pub krate: String,
    pub created_at: DateTime<UTC>,
    pub dl_path: String,
    pub id: i32,
    pub links: VersionLinks,
    pub num: String, // XXX should be semver::Version
    pub updated_at: DateTime<UTC>,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

#[derive(Debug, Deserialize)]
pub struct CrateData {
    pub badges: Option<Vec<BadgeData>>,
    pub categories: Option<Vec<String>>,
    pub created_at: DateTime<UTC>,
    pub description: Option<String>,
    pub documentation: Option<String>,
    pub downloads: i32,
    pub homepage: Option<String>,
    pub id: String,
    pub keywords: Option<Vec<String>>,
    pub name: String,
    pub license: Option<String>,
    pub links: CrateLinks,
    pub max_version: String,
    pub repository: Option<String>,
    pub updated_at: DateTime<UTC>,
    pub versions: Option<Vec<i32>>,
}

#[derive(Debug, Deserialize)]
pub struct ApiResponse {
    pub categories: Vec<CategoryData>,
    #[serde(rename(deserialize = "crate"))]
    pub krate: CrateData,
    pub keywords: Vec<KeywordData>,
    pub versions: Vec<VersionData>,
}

impl FromStr for ApiResponse {
    type Err = Error;
    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        serde_json::from_str(s).chain_err(|| "Failed to parse JSON")
    }
}

#[derive(Debug)]
pub struct CratesIO {
    response: reqwest::Response,
    body: String,
}

impl CratesIO {
    pub fn query(krate: &str) -> Result<Self> {
        let url = format!("https://crates.io/api/v1/crates/{}", krate);
        let mut response = reqwest::get(&url)?;
        let mut body = String::with_capacity(20480);
        response.read_to_string(&mut body)?;
        Ok(CratesIO {
               response: response,
               body: body,
           })
    }

    pub fn raw_data(&self) -> &str {
        &self.body
    }

    pub fn as_json(&self) -> Result<Value> {
        serde_json::from_str(&self.body).chain_err(|| "Failed to parse JSON")
        // serde_json::to_string_pretty(&json).chain_err(|| "Failed to prettify")
    }

    pub fn as_data(&self) -> Result<ApiResponse> {
        if *self.response.status() == reqwest::StatusCode::Ok {
            self.body.parse::<ApiResponse>()
        } else {
            self.body
                .parse::<ErrorResponse>()
                .and_then(|er| Err(ErrorKind::CratesIOError(er).into()))
        }
    }
}
<commit_msg>Fix badge data<commit_after>use std::io::Read;
use std::collections::HashMap;
use std::str::FromStr;

use chrono::{DateTime, UTC};
use reqwest;
use serde_json::{self, Value};

use errors::*;

#[derive(Debug, Deserialize)]
pub struct Errors {
    pub detail: String,
}

#[derive(Debug, Deserialize)]
pub struct ErrorResponse {
    pub errors: Vec<Errors>,
}

impl ErrorResponse {
    pub fn detail(&self) -> &str {
        self.errors.get(0).map(|x| x.detail.as_str()).unwrap_or("")
    }
}

impl FromStr for ErrorResponse {
    type Err = Error;
    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        serde_json::from_str(s).chain_err(|| "Failed to parse JSON")
    }
}

#[derive(Debug, Deserialize)]
pub struct BadgeData {
    pub attributes: HashMap<String, Option<String>>,
    pub badge_type: String,
}

#[derive(Debug, Deserialize)]
pub struct CategoryData {
    pub category: String,
    pub crates_cnt: i32,
    pub created_at: DateTime<UTC>,
    pub description: String,
    pub id: String,
    pub slug: String,
}

#[derive(Debug, Deserialize)]
pub struct CrateLinks {
    pub version_downloads: String,
    pub versions: Option<String>,
    pub owners: Option<String>,
    pub reverse_dependencies: String,
}

#[derive(Debug, Deserialize)]
pub struct KeywordData {
    pub crates_cnt: i32,
    pub created_at: DateTime<UTC>,
    pub id: String,
    pub keyword: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionLinks {
    pub authors: String,
    pub dependencies: String,
    pub version_downloads: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionData {
    #[serde(rename(deserialize = "crate"))]
    pub krate: String,
    pub created_at: DateTime<UTC>,
    pub dl_path: String,
    pub id: i32,
    pub links: VersionLinks,
    pub num: String, // XXX should be semver::Version
    pub updated_at: DateTime<UTC>,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

#[derive(Debug, Deserialize)]
pub struct CrateData {
    pub badges: Option<Vec<BadgeData>>,
    pub categories: Option<Vec<String>>,
    pub created_at: DateTime<UTC>,
    pub description: Option<String>,
    pub documentation: Option<String>,
    pub downloads: i32,
    pub homepage: Option<String>,
    pub id: String,
    pub keywords: Option<Vec<String>>,
    pub name: String,
    pub license: Option<String>,
    pub links: CrateLinks,
    pub max_version: String,
    pub repository: Option<String>,
    pub updated_at: DateTime<UTC>,
    pub versions: Option<Vec<i32>>,
}

#[derive(Debug, Deserialize)]
pub struct ApiResponse {
    pub categories: Vec<CategoryData>,
    #[serde(rename(deserialize = "crate"))]
    pub krate: CrateData,
    pub keywords: Vec<KeywordData>,
    pub versions: Vec<VersionData>,
}

impl FromStr for ApiResponse {
    type Err = Error;
    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        serde_json::from_str(s).chain_err(|| "Failed to parse JSON")
    }
}

#[derive(Debug)]
pub struct CratesIO {
    response: reqwest::Response,
    body: String,
}

impl CratesIO {
    pub fn query(krate: &str) -> Result<Self> {
        let url = format!("https://crates.io/api/v1/crates/{}", krate);
        let mut response = reqwest::get(&url)?;
        let mut body = String::with_capacity(20480);
        response.read_to_string(&mut body)?;
        Ok(CratesIO {
               response: response,
               body: body,
           })
    }

    pub fn raw_data(&self) -> &str {
        &self.body
    }

    pub fn as_json(&self) -> Result<Value> {
        serde_json::from_str(&self.body).chain_err(|| "Failed to parse JSON")
        // serde_json::to_string_pretty(&json).chain_err(|| "Failed to prettify")
    }

    pub fn as_data(&self) -> Result<ApiResponse> {
        if *self.response.status() == reqwest::StatusCode::Ok {
            self.body.parse::<ApiResponse>()
        } else {
            self.body
                .parse::<ErrorResponse>()
                .and_then(|er| Err(ErrorKind::CratesIOError(er).into()))
        }
    }
}
<|endoftext|>


<commit_before>use url::Url;
use serde_json;
use serde_json::Value;
use std::path::PathBuf;
use std::env;
use std::fs::File;
use errors::*;

#[derive(Clone,Debug)]
pub struct Config {
    pub endpoint: Option<Url>,
    pub user: Option<String>,
    pub keypath: Option<String>,
    pub sign_ver: String,
}

impl Config {
    pub fn new() -> Config {
        Config {
            endpoint: None,
            user: None,
            keypath: None,
            sign_ver: String::from("1.3"),
        }
    }

    /// Load a configuration file from JSON
    pub fn from_json(path: &str) -> Result<Config> {
        let path = get_absolute_path(path);
        match File::open(path) {
            Ok(fh) => {
                let val: Value = try!(serde_json::from_reader(fh));
                let obj = val.as_object().unwrap();

                let key: String = try!(serde_json::from_value(*obj.get("client_key").unwrap()));
                let key = get_absolute_path(key.as_ref());
                let endpoint: String = try!(serde_json::from_value(*obj.get("chef_server_url")
                    .unwrap()));
                let user: String = try!(serde_json::from_value(*obj.get("node_name").unwrap()));
                let sign_ver: String = serde_json::from_value(*obj.get("node_name").unwrap())
                    .unwrap_or("1.3".into());

                let endpoint = try!(Url::parse(endpoint.as_ref()));

                Ok(Config {
                    endpoint: Some(endpoint),
                    user: Some(user),
                    keypath: Some(key),
                    sign_ver: sign_ver,
                })
            }
            Err(_) => panic!("Couldn't open config file"),
        }
    }

    pub fn organization_path(&self) -> String {
        match self.endpoint {
            Some(ref endpoint) => endpoint.path().into(),
            None => panic!("Can't find an endpoint"),
        }
    }

    pub fn url_base(&self) -> String {
        match self.endpoint {
            Some(ref endpoint) => {
                let host = &endpoint.host_str().unwrap();
                let port = &endpoint.port_or_known_default().unwrap();
                let scheme = &endpoint.scheme();
                format!("{}://{}:{}", scheme, host, port)
            }
            None => panic!("Can't find an endpoint"),
        }
    }
}

fn get_absolute_path(val: &str) -> String {
    let mut p = PathBuf::from(val);
    if !p.is_absolute() {
        p = env::current_dir().unwrap();
        p.push(val);
    }
    p.to_str().unwrap().to_owned()
}

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

    const ENDPOINT: &'static str = "https://localhost/organizations/clownco";
    const CONFIG: &'static str = "fixtures/config.json";

    #[test]
    fn test_from_json() {
        let cfg = Config::from_json(CONFIG);
        assert_eq!(cfg.endpoint.unwrap().serialize_path().unwrap(),
                   "/organizations/rs_chef_api")
    }

    #[test]
    fn test_config_endpoint() {
        let cfg = Config::new().endpoint(ENDPOINT);
        assert_eq!(cfg.endpoint.unwrap().serialize_path().unwrap(),
                   "/organizations/clownco")
    }

    #[test]
    fn test_config_organization() {
        let cfg = Config::new().endpoint(ENDPOINT);
        assert_eq!(cfg.organization_path(), "/organizations/clownco")
    }

    #[test]
    fn test_config_base_url() {
        let cfg = Config::new().endpoint(ENDPOINT);
        assert_eq!(cfg.url_base(), "https://localhost:443")
    }

    #[test]
    fn test_default_sign_ver() {
        let cfg = Config::new();
        assert_eq!(cfg.sign_ver, "1.1")
    }
}
<commit_msg>clean up config getting<commit_after>use url::Url;
use serde_json;
use serde_json::Value;
use std::path::PathBuf;
use std::env;
use std::fs::File;
use errors::*;

#[derive(Clone,Debug)]
pub struct Config {
    pub endpoint: Option<Url>,
    pub user: Option<String>,
    pub keypath: Option<String>,
    pub sign_ver: String,
}

impl Config {
    pub fn new() -> Config {
        Config {
            endpoint: None,
            user: None,
            keypath: None,
            sign_ver: String::from("1.3"),
        }
    }

    /// Load a configuration file from JSON
    pub fn from_json(path: &str) -> Result<Config> {
        let path = get_absolute_path(path);
        let fh = try!(File::open(&path));
        let val: Value = try!(serde_json::from_reader(fh));

        if let Some(ref obj) = val.as_object() {
            let key = obj.get("client_key").unwrap();
            let key: String = try!(serde_json::from_value(key.clone()));
            let key = get_absolute_path(key.as_ref());

            let endpoint = obj.get("chef_server_url").unwrap();
            let endpoint: String = try!(serde_json::from_value(endpoint.clone()));

            let user = obj.get("node_name").unwrap();
            let user: String = try!(serde_json::from_value(user.clone()));

            let sign_ver: String = "1.3".into();

            let endpoint = try!(Url::parse(endpoint.as_ref()));

            Ok(Config {
                endpoint: Some(endpoint),
                user: Some(user),
                keypath: Some(key),
                sign_ver: sign_ver,
            })
        } else {
            Err(ErrorKind::UnparseableConfigError(path).into())
        }
    }

    pub fn organization_path(&self) -> String {
        match self.endpoint {
            Some(ref endpoint) => endpoint.path().into(),
            None => panic!("Can't find an endpoint"),
        }
    }

    pub fn url_base(&self) -> String {
        match self.endpoint {
            Some(ref endpoint) => {
                let host = &endpoint.host_str().unwrap();
                let port = &endpoint.port_or_known_default().unwrap();
                let scheme = &endpoint.scheme();
                format!("{}://{}:{}", scheme, host, port)
            }
            None => panic!("Can't find an endpoint"),
        }
    }
}

fn get_absolute_path(val: &str) -> String {
    let mut p = PathBuf::from(val);
    if !p.is_absolute() {
        p = env::current_dir().unwrap();
        p.push(val);
    }
    p.to_str().unwrap().to_owned()
}

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

    const ENDPOINT: &'static str = "https://localhost/organizations/clownco";
    const CONFIG: &'static str = "fixtures/config.json";

    #[test]
    fn test_from_json() {
        let cfg = Config::from_json(CONFIG).unwrap();
        assert_eq!(cfg.endpoint.unwrap().path(), "/organizations/rs_chef_api")
    }

    #[test]
    fn test_config_endpoint() {
        let url = Url::parse(ENDPOINT).unwrap();
        let cfg = Config {
            endpoint: Some(url),
            user: None,
            keypath: None,
            sign_ver: String::from("1.3"),
        };
        assert_eq!(cfg.endpoint.unwrap().path(), "/organizations/clownco")
    }

    #[test]
    fn test_config_organization() {
        let url = Url::parse(ENDPOINT).unwrap();
        let cfg = Config {
            endpoint: Some(url),
            user: None,
            keypath: None,
            sign_ver: String::from("1.3"),
        };
        assert_eq!(cfg.organization_path(), "/organizations/clownco")
    }

    #[test]
    fn test_config_base_url() {
        let url = Url::parse(ENDPOINT).unwrap();
        let cfg = Config {
            endpoint: Some(url),
            user: None,
            keypath: None,
            sign_ver: String::from("1.3"),
        };
        assert_eq!(cfg.url_base(), "https://localhost:443")
    }

    #[test]
    fn test_default_sign_ver() {
        let cfg = Config::new();
        assert_eq!(cfg.sign_ver, "1.3")
    }
}
<|endoftext|>


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

//!
//! Ways to configure the Roughenough server.
//!
//! The [ServerConfig](trait.ServerConfig.html) trait specifies the required and optional
//! parameters available for configuring a Roughenoguh server instance.
//!
//! Implementations of `ServerConfig` obtain configurations from different back-end sources.
//!

extern crate hex;

use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use std::time::Duration;
use yaml_rust::YamlLoader;
use Error;

const DEFAULT_BATCH_SIZE: u8 = 64;
const DEFAULT_STATUS_INTERVAL: Duration = Duration::from_secs(600);

///
/// Specifies parameters needed to configure a Roughenough server.
///
/// Parameters labeled "**Required**" must are always be provided and have no default value.
/// Parameters labeled "**Optional**" provide default values that can be overridden.
///
/// * **`interface`** - [Required] IP address or interface name for listening to client requests
/// * **`port`** - [Required] UDP port to listen for requests
/// * **`seed`** - [Required] A 32-byte hexadecimal value used to generate the server's long-term
///                key pair. **This is a secret value and must be un-guessable**,
///                treat it with care.
/// * **`batch_size`** - [Optional] The maximum number of requests to process in one batch. All
///                      nonces in a batch are used to build a Merkle tree, the root of which
///                      is signed. Default is 64 requests per batch.
/// * **`status_interval`** - [Optional] Amount of time between each logged status update.
///                           Default is 600 seconds (10 minutes).
///
/// Implementations of this trait obtain a valid configuration from different back-
/// end sources.
///
/// See:
///   * [FileConfig](struct.FileConfig.html)
///
pub trait ServerConfig {
    /// [Required] IP address or interface name to listen for client requests
    fn interface(&self) -> &str;

    /// [Required] UDP port to listen for requests
    fn port(&self) -> u16;

    /// [Required] A 32-byte hexadecimal value used to generate the server's
    /// long-term key pair. **This is a secret value and must be un-guessable**,
    /// treat it with care.
    fn seed(&self) -> &[u8];

    /// [Optional] The maximum number of requests to process in one batch. All
    /// nonces in a batch are used to build a Merkle tree, the root of which is signed.
    /// Default is 64 requests per batch.
    fn batch_size(&self) -> u8;

    /// [Optional] Amount of time between each logged status update.
    /// Default is 600 seconds (10 minutes).
    fn status_interval(&self) -> Duration;

    /// Convenience function to create a `SocketAddr` from the provided `interface` and `port`
    fn socket_addr(&self) -> SocketAddr;
}

///
/// Read the configuration from a YAML file
///
/// Example minimal config file with only the required parameters from
/// [ServerConfig](trait.ServerConfig.html):
///
/// ```yaml
/// interface: 127.0.0.1
/// port: 8686
/// seed: f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
/// ```
///
pub struct FileConfig {
    port: u16,
    interface: String,
    seed: Vec<u8>,
    batch_size: u8,
    status_interval: Duration,
}

impl FileConfig {
    pub fn from_file(config_file: &str) -> Result<Self, Error> {
        let mut infile = File::open(config_file).expect("failed to open config file");

        let mut contents = String::new();
        infile
            .read_to_string(&mut contents)
            .expect("could not read config file");

        let cfg = YamlLoader::load_from_str(&contents).expect("could not parse config file");

        if cfg.len() != 1 {
            return Err(Error::InvalidConfiguration(
                "Empty or malformed config file".to_string(),
            ));
        }

        let mut config = FileConfig {
            port: 0,
            interface: "unknown".to_string(),
            seed: Vec::new(),
            batch_size: DEFAULT_BATCH_SIZE,
            status_interval: DEFAULT_STATUS_INTERVAL,
        };

        for (key, value) in cfg[0].as_hash().unwrap() {
            match key.as_str().unwrap() {
                "port" => config.port = value.as_i64().unwrap() as u16,
                "interface" => config.interface = value.as_str().unwrap().to_string(),
                "batch_size" => config.batch_size = value.as_i64().unwrap() as u8,
                "seed" => {
                    let val = value.as_str().unwrap().to_string();
                    config.seed = hex::decode(val)
                        .expect("seed value invalid; 'seed' should be 32 byte hex value");
                }
                "status_interval" => {
                    let val = value.as_i64().expect("status_interval value invalid");
                    config.status_interval = Duration::from_secs(val as u64)
                }
                _ => {
                    return Err(Error::InvalidConfiguration(format!(
                        "unknown config key '{}'",
                        key.as_str().unwrap()
                    )));
                }
            }
        }

        Ok(config)
    }
}

impl ServerConfig for FileConfig {
    fn interface(&self) -> &str {
        self.interface.as_ref()
    }

    fn port(&self) -> u16 {
        self.port
    }

    fn seed(&self) -> &[u8] {
        &self.seed
    }

    fn batch_size(&self) -> u8 {
        self.batch_size
    }

    fn status_interval(&self) -> Duration {
        self.status_interval
    }

    fn socket_addr(&self) -> SocketAddr {
        let addr = format!("{}:{}", self.interface, self.port);
        addr.parse()
            .expect(&format!("could not create socket address from {}", addr))
    }
}
<commit_msg>Report unknown configuration key in FileConfig<commit_after>// Copyright 2017-2018 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! Ways to configure the Roughenough server.
//!
//! The [ServerConfig](trait.ServerConfig.html) trait specifies the required and optional
//! parameters available for configuring a Roughenoguh server instance.
//!
//! Implementations of `ServerConfig` obtain configurations from different back-end sources.
//!

extern crate hex;

use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use std::time::Duration;
use yaml_rust::YamlLoader;
use Error;

const DEFAULT_BATCH_SIZE: u8 = 64;
const DEFAULT_STATUS_INTERVAL: Duration = Duration::from_secs(600);

///
/// Specifies parameters needed to configure a Roughenough server.
///
/// Parameters labeled "**Required**" must are always be provided and have no default value.
/// Parameters labeled "**Optional**" provide default values that can be overridden.
///
/// * **`interface`** - [Required] IP address or interface name for listening to client requests
/// * **`port`** - [Required] UDP port to listen for requests
/// * **`seed`** - [Required] A 32-byte hexadecimal value used to generate the server's long-term
///                key pair. **This is a secret value and must be un-guessable**,
///                treat it with care.
/// * **`batch_size`** - [Optional] The maximum number of requests to process in one batch. All
///                      nonces in a batch are used to build a Merkle tree, the root of which
///                      is signed. Default is 64 requests per batch.
/// * **`status_interval`** - [Optional] Amount of time between each logged status update.
///                           Default is 600 seconds (10 minutes).
///
/// Implementations of this trait obtain a valid configuration from different back-
/// end sources.
///
/// See:
///   * [FileConfig](struct.FileConfig.html)
///
pub trait ServerConfig {
    /// [Required] IP address or interface name to listen for client requests
    fn interface(&self) -> &str;

    /// [Required] UDP port to listen for requests
    fn port(&self) -> u16;

    /// [Required] A 32-byte hexadecimal value used to generate the server's
    /// long-term key pair. **This is a secret value and must be un-guessable**,
    /// treat it with care.
    fn seed(&self) -> &[u8];

    /// [Optional] The maximum number of requests to process in one batch. All
    /// nonces in a batch are used to build a Merkle tree, the root of which is signed.
    /// Default is 64 requests per batch.
    fn batch_size(&self) -> u8;

    /// [Optional] Amount of time between each logged status update.
    /// Default is 600 seconds (10 minutes).
    fn status_interval(&self) -> Duration;

    /// Convenience function to create a `SocketAddr` from the provided `interface` and `port`
    fn socket_addr(&self) -> SocketAddr;
}

///
/// Read the configuration from a YAML file
///
/// Example minimal config file with only the required parameters from
/// [ServerConfig](trait.ServerConfig.html):
///
/// ```yaml
/// interface: 127.0.0.1
/// port: 8686
/// seed: f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
/// ```
///
pub struct FileConfig {
    port: u16,
    interface: String,
    seed: Vec<u8>,
    batch_size: u8,
    status_interval: Duration,
}

impl FileConfig {
    pub fn from_file(config_file: &str) -> Result<Self, Error> {
        let mut infile = File::open(config_file).expect("failed to open config file");

        let mut contents = String::new();
        infile
            .read_to_string(&mut contents)
            .expect("could not read config file");

        let cfg = YamlLoader::load_from_str(&contents).expect("could not parse config file");

        if cfg.len() != 1 {
            return Err(Error::InvalidConfiguration(
                "Empty or malformed config file".to_string(),
            ));
        }

        let mut config = FileConfig {
            port: 0,
            interface: "unknown".to_string(),
            seed: Vec::new(),
            batch_size: DEFAULT_BATCH_SIZE,
            status_interval: DEFAULT_STATUS_INTERVAL,
        };

        for (key, value) in cfg[0].as_hash().unwrap() {
            match key.as_str().unwrap() {
                "port" => config.port = value.as_i64().unwrap() as u16,
                "interface" => config.interface = value.as_str().unwrap().to_string(),
                "batch_size" => config.batch_size = value.as_i64().unwrap() as u8,
                "seed" => {
                    let val = value.as_str().unwrap().to_string();
                    config.seed = hex::decode(val)
                        .expect("seed value invalid; 'seed' should be 32 byte hex value");
                }
                "status_interval" => {
                    let val = value.as_i64().expect("status_interval value invalid");
                    config.status_interval = Duration::from_secs(val as u64)
                }
                unknown => {
                    return Err(Error::InvalidConfiguration(format!(
                        "unknown config key: {}", unknown
                    )));
                }
            }
        }

        Ok(config)
    }
}

impl ServerConfig for FileConfig {
    fn interface(&self) -> &str {
        self.interface.as_ref()
    }

    fn port(&self) -> u16 {
        self.port
    }

    fn seed(&self) -> &[u8] {
        &self.seed
    }

    fn batch_size(&self) -> u8 {
        self.batch_size
    }

    fn status_interval(&self) -> Duration {
        self.status_interval
    }

    fn socket_addr(&self) -> SocketAddr {
        let addr = format!("{}:{}", self.interface, self.port);
        addr.parse()
            .expect(&format!("could not create socket address from {}", addr))
    }
}
<|endoftext|>


<commit_before>//
//
//
#![macro_escape]

macro_rules! is
{
	($val:expr, $p:pat) => ( match $val { $p => true, _ => false } );
}

macro_rules! while_let
{
	($p:pat = $e:expr $code:block) => ( loop { match $e { $p => {$code}, _ => break } } );
}
macro_rules! if_let
{
	($p:pat = $e:expr $code:block) => ( match $e { $p => $code, _ =>{}} );
}

macro_rules! _count
{
	() => {0};
	($a:ident) => {1};
	($a:ident, $($b:ident)+) => {1+_count!($b)};
}

macro_rules! module_define_int
{
	($name:ident, $count:expr, $deps:expr, $init:path) => (
		//#[assume_reachable]
		#[link_section = ".MODULE_LIST"]
		pub static mut _s_module: ::modules::ModuleInfo = ::modules::ModuleInfo {
			name: stringify!($name),
			init: $init,
			deps: &S_DEPS,
			_rsvd: 0,
		};
		static S_DEPS: [&'static str, ..($count)] = $deps;
	);
}

macro_rules! module_define
{
	($name:ident, [], $init:path) => (module_define_int!($name, 0, [], $init));
	($name:ident, [$($deps:ident),+], $init:path) => (module_define_int!($name, _count!($($deps),+), [$(stringify!($deps)),+], $init));
}

// vim: ft=rust
<commit_msg>Core/macros - Fix bug in module define with multiple deps<commit_after>//
//
//
#![macro_escape]

macro_rules! is
{
	($val:expr, $p:pat) => ( match $val { $p => true, _ => false } );
}

macro_rules! while_let
{
	($p:pat = $e:expr $code:block) => ( loop { match $e { $p => {$code}, _ => break } } );
}
macro_rules! if_let
{
	($p:pat = $e:expr $code:block) => ( match $e { $p => $code, _ =>{}} );
}

macro_rules! _count
{
	() => {0};
	($a:ident) => {1};
	($a:ident, $($b:ident)+) => {1+_count!($($b),+)};
}

macro_rules! module_define_int
{
	($name:ident, $count:expr, $deps:expr, $init:path) => (
		//#[assume_reachable]
		#[link_section = ".MODULE_LIST"]
		pub static mut _s_module: ::modules::ModuleInfo = ::modules::ModuleInfo {
			name: stringify!($name),
			init: $init,
			deps: &S_DEPS,
			_rsvd: 0,
		};
		static S_DEPS: [&'static str, ..($count)] = $deps;
	);
}

macro_rules! module_define
{
	($name:ident, [], $init:path) => (module_define_int!($name, 0, [], $init));
	($name:ident, [$($deps:ident),+], $init:path) => (module_define_int!($name, _count!($($deps),+), [$(stringify!($deps)),+], $init));
}

// vim: ft=rust
<|endoftext|>