<commit_before>use vec::push;

pub fn init(flags: &[InitFlag]) -> int {
    SDL::SDL_Init(util::init_flags_to_bitfield(flags)) as int
}

pub fn init_subsystem(flags: &[InitFlag]) -> int {
    SDL::SDL_InitSubSystem(util::init_flags_to_bitfield(flags)) as int
}

pub fn quit_subsystem(flags: &[InitFlag]) {
    SDL::SDL_QuitSubSystem(util::init_flags_to_bitfield(flags))
}

pub fn quit() {
    SDL::SDL_Quit()
}

pub fn was_init(flags: &[InitFlag]) -> ~[InitFlag] {
    let bitflags = SDL::SDL_WasInit(util::init_flags_to_bitfield(flags));
    let all_flags = ~[
        InitTimer,
        InitAudio,
        InitVideo,
        InitCDRom,
        InitJoystick
    ];

    let mut vecflags = ~[];

    vec::map(all_flags, |flag| {
        if bitflags & (*flag as c_int) != 0 as c_int {
            push(&mut vecflags, *flag);
        }
    });
    move vecflags
}

pub fn get_error() -> ~str unsafe {
    let cstr = SDL::SDL_GetError();
    // FIXME: Converting sbuf to *c_char
    let cstr = cast::reinterpret_cast(&cstr);
    str::raw::from_c_str(cstr)
}

pub fn set_error(s: &str) {
    str::as_buf(s, |buf, _len| {
        // FIXME: Converting sbuf to *c_char
        let buf = unsafe { cast::reinterpret_cast(&buf) };
        SDL::SDL_SetError(buf)
    });
}

pub fn error(code: ErrorCode) {
    SDL::SDL_Error(code as c_int)
}

pub fn clear_error() {
    SDL::SDL_ClearError()
}

mod util {
    pub fn init_flags_to_bitfield(flags: &[InitFlag]) -> u32 {
        vec::foldl(0u32, flags, |flags, flag| {
            flags | *flag as u32
        })
    }
}
<commit_msg>Started adding notes as to how I'll tackle each subsystem<commit_after>use vec::push;

/*
    Ze plan:
        As much as it'd be nice for this to be object oriented, there's little to be gained
        As none of the basic calls return any sort of handles to store
*/
pub fn init(flags: &[InitFlag]) -> int {
    SDL::SDL_Init(util::init_flags_to_bitfield(flags)) as int
}

pub fn init_subsystem(flags: &[InitFlag]) -> int {
    SDL::SDL_InitSubSystem(util::init_flags_to_bitfield(flags)) as int
}

pub fn quit_subsystem(flags: &[InitFlag]) {
    SDL::SDL_QuitSubSystem(util::init_flags_to_bitfield(flags))
}

pub fn quit() {
    SDL::SDL_Quit()
}

pub fn was_init(flags: &[InitFlag]) -> ~[InitFlag] {
    let bitflags = SDL::SDL_WasInit(util::init_flags_to_bitfield(flags));
    let all_flags = ~[
        InitTimer,
        InitAudio,
        InitVideo,
        InitCDRom,
        InitJoystick
    ];

    let mut vecflags = ~[];

    vec::map(all_flags, |flag| {
        if bitflags & (*flag as c_int) != 0 as c_int {
            push(&mut vecflags, *flag);
        }
    });
    move vecflags
}

pub fn get_error() -> ~str unsafe {
    let cstr = SDL::SDL_GetError();
    // FIXME: Converting sbuf to *c_char
    let cstr = cast::reinterpret_cast(&cstr);
    str::raw::from_c_str(cstr)
}

pub fn set_error(s: &str) {
    str::as_buf(s, |buf, _len| {
        // FIXME: Converting sbuf to *c_char
        let buf = unsafe { cast::reinterpret_cast(&buf) };
        SDL::SDL_SetError(buf)
    });
}

pub fn error(code: ErrorCode) {
    SDL::SDL_Error(code as c_int)
}

pub fn clear_error() {
    SDL::SDL_ClearError()
}

mod util {
    pub fn init_flags_to_bitfield(flags: &[InitFlag]) -> u32 {
        vec::foldl(0u32, flags, |flags, flag| {
            flags | *flag as u32
        })
    }
}
<|endoftext|>


<commit_before>//! `log` crate adapter for slog-rs
//!
//! This crate provides two way compatibility with Rust standard `log` crate.
//!
//! ### `log` -> `slog`
//!
//! After calling `init()` `slog-stdlog` will take a role of `log` crate
//! back-end, forwarding all the `log` logging to `slog_scope::logger()`.
//! In other words, any `log` crate logging statement will behave like it was `slog`
//! logging statement executed with logger returned by `slog_scope::logger()`.
//!
//! See documentation of `slog-scope` for more information about logging scopes.
//!
//! See [`init` documentation](fn.init.html) for an example.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is `slog::Drain` that will pass all `Record`s passing through it to
//! `log` crate just like they were crated with `log` crate logging macros in
//! the first place.
//!
//! ## `slog-scope`
//!
//! Since `log` does not have any form of context, and does not support `Logger`
//! `slog-stdlog` relies on "logging scopes" to establish it.
//!
//! You must set up logging context for `log` -> `slog` via `slog_scope::scope`
//! or `slog_scope::set_global_logger`. Setting a global logger upfront via
//! `slog_scope::set_global_logger` is highly recommended.
//!
//! Note: Since `slog-stdlog` v2, unlike previous releases, `slog-stdlog` uses
//! logging scopes provided by `slog-scope` crate instead of it's own.
//!
//! Refer to `slog-scope` crate documentation for more information.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily
//! created: `log` -> `slog` -> `log` -> ...
//!
//! ## Compile-time log level filtering
//!
//! For filtering `debug!` and other `log` statements at compile-time, configure
//! the features on the `log` crate in your `Cargo.toml`:
//!
//! ```norust
//! log = { version = "*", features = ["max_level_trace", "release_max_level_warn"] }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_scope;
extern crate log;

use log::LogMetadata;
use std::{io, fmt};

use slog::Level;
use slog::KV;

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();

        let s = slog::RecordStatic {
            location: &slog::RecordLocation {
                           file: file,
                           line: line,
                           column: 0,
                           function: "",
                           module: module,
                       },
            level: level,
            tag: target,
        };
        slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!())))

    }
}

/// Register `slog-stdlog` as `log` backend.
///
/// This will pass all logging statements crated with `log`
/// crate to current `slog-scope::logger()`.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// #[macro_use(slog_o, slog_kv)]
/// extern crate slog;
/// extern crate slog_stdlog;
/// extern crate slog_scope;
/// extern crate slog_term;
/// extern crate slog_async;
///
/// use slog::Drain;
///
/// fn main() {
///     let decorator = slog_term::TermDecorator::new().build();
///     let drain = slog_term::FullFormat::new(decorator).build().fuse();
///     let drain = slog_async::Async::new(drain).build().fuse();
///     let logger = slog::Logger::root(drain, slog_o!("version" => env!("CARGO_PKG_VERSION")));
///
///     let _scope_guard = slog_scope::set_global_logger(logger);
///     let _log_guard = slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
                        max_log_level.set(log::LogLevelFilter::max());
                        Box::new(Logger)
                    })
}

/// Drain logging `Record`s into `log` crate
///
/// Any `Record` passing through this `Drain` will be forwarded
/// to `log` crate, just like it was created with `log` crate macros
/// in the first place. The message and key-value pairs will be formated
/// to be one string.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKVList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io);

        let res = {
            || -> io::Result<()> {
                try!(self.logger_values.serialize(self.info, &mut ser));
                try!(self.info.kv().serialize(self.info, &mut ser));
                Ok(())
            }
        }()
                .map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Err = io::Error;
    type Ok = ();
    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.tag();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W) -> Self {
        KSV { io: io }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> slog::Serializer for KSV<W> {
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> slog::Result {
        try!(write!(self.io, ", {}: {}", key, val));
        Ok(())
    }
}
<commit_msg>KSV serialize key: slog::Key instead of &str<commit_after>//! `log` crate adapter for slog-rs
//!
//! This crate provides two way compatibility with Rust standard `log` crate.
//!
//! ### `log` -> `slog`
//!
//! After calling `init()` `slog-stdlog` will take a role of `log` crate
//! back-end, forwarding all the `log` logging to `slog_scope::logger()`.
//! In other words, any `log` crate logging statement will behave like it was `slog`
//! logging statement executed with logger returned by `slog_scope::logger()`.
//!
//! See documentation of `slog-scope` for more information about logging scopes.
//!
//! See [`init` documentation](fn.init.html) for an example.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is `slog::Drain` that will pass all `Record`s passing through it to
//! `log` crate just like they were crated with `log` crate logging macros in
//! the first place.
//!
//! ## `slog-scope`
//!
//! Since `log` does not have any form of context, and does not support `Logger`
//! `slog-stdlog` relies on "logging scopes" to establish it.
//!
//! You must set up logging context for `log` -> `slog` via `slog_scope::scope`
//! or `slog_scope::set_global_logger`. Setting a global logger upfront via
//! `slog_scope::set_global_logger` is highly recommended.
//!
//! Note: Since `slog-stdlog` v2, unlike previous releases, `slog-stdlog` uses
//! logging scopes provided by `slog-scope` crate instead of it's own.
//!
//! Refer to `slog-scope` crate documentation for more information.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily
//! created: `log` -> `slog` -> `log` -> ...
//!
//! ## Compile-time log level filtering
//!
//! For filtering `debug!` and other `log` statements at compile-time, configure
//! the features on the `log` crate in your `Cargo.toml`:
//!
//! ```norust
//! log = { version = "*", features = ["max_level_trace", "release_max_level_warn"] }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_scope;
extern crate log;

use log::LogMetadata;
use std::{io, fmt};

use slog::Level;
use slog::KV;

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();

        let s = slog::RecordStatic {
            location: &slog::RecordLocation {
                           file: file,
                           line: line,
                           column: 0,
                           function: "",
                           module: module,
                       },
            level: level,
            tag: target,
        };
        slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!())))

    }
}

/// Register `slog-stdlog` as `log` backend.
///
/// This will pass all logging statements crated with `log`
/// crate to current `slog-scope::logger()`.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// #[macro_use(slog_o, slog_kv)]
/// extern crate slog;
/// extern crate slog_stdlog;
/// extern crate slog_scope;
/// extern crate slog_term;
/// extern crate slog_async;
///
/// use slog::Drain;
///
/// fn main() {
///     let decorator = slog_term::TermDecorator::new().build();
///     let drain = slog_term::FullFormat::new(decorator).build().fuse();
///     let drain = slog_async::Async::new(drain).build().fuse();
///     let logger = slog::Logger::root(drain, slog_o!("version" => env!("CARGO_PKG_VERSION")));
///
///     let _scope_guard = slog_scope::set_global_logger(logger);
///     let _log_guard = slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
                        max_log_level.set(log::LogLevelFilter::max());
                        Box::new(Logger)
                    })
}

/// Drain logging `Record`s into `log` crate
///
/// Any `Record` passing through this `Drain` will be forwarded
/// to `log` crate, just like it was created with `log` crate macros
/// in the first place. The message and key-value pairs will be formated
/// to be one string.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKVList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io);

        let res = {
            || -> io::Result<()> {
                try!(self.logger_values.serialize(self.info, &mut ser));
                try!(self.info.kv().serialize(self.info, &mut ser));
                Ok(())
            }
        }()
                .map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Err = io::Error;
    type Ok = ();
    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.tag();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W) -> Self {
        KSV { io: io }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> slog::Serializer for KSV<W> {
    fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
        try!(write!(self.io, ", {}: {}", key, val));
        Ok(())
    }
}
<|endoftext|>


<commit_before>use associations::HasTable;
use backend::SupportsReturningClause;
use connection::Connection;
use helper_types::*;
use query_builder::{AsChangeset, IntoUpdateTarget};
use query_dsl::*;
use query_source::Queryable;
use result::QueryResult;
use types::HasSqlType;

pub trait SaveChangesDsl<Conn, ST> where
    Conn: Connection,
    Conn::Backend: HasSqlType<ST>,
{
    fn save_changes<T>(self, connection: &Conn) -> QueryResult<T> where
        T: Queryable<ST, Conn::Backend>;
}

impl<T, ST, Conn> SaveChangesDsl<Conn, ST> for T where
    Conn: Connection,
    Conn::Backend: HasSqlType<ST> + SupportsReturningClause,
    T: Copy + AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    Update<T, T>: LoadDsl<Conn, SqlType=ST>,
{
    fn save_changes<U>(self, conn: &Conn) -> QueryResult<U> where
        U: Queryable<ST, Conn::Backend>,
    {
        ::update(self).set(self).get_result(conn)
    }
}

#[cfg(feature = "sqlite")]
use sqlite::{SqliteConnection, Sqlite};
#[cfg(feature = "sqlite")]
use associations::Identifiable;

#[cfg(feature = "sqlite")]
impl<T, ST> SaveChangesDsl<SqliteConnection, ST> for T where
    Sqlite: HasSqlType<ST>,
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id, SqlType=ST>,
    Update<T, T>: ExecuteDsl<SqliteConnection>,
    Find<T::Table, T::Id>: LoadDsl<SqliteConnection, SqlType=ST>,
{
    fn save_changes<U>(self, conn: &SqliteConnection) -> QueryResult<U> where
        U: Queryable<ST, Sqlite>,
    {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}

#[cfg(feature = "mysql")]
use mysql::{MysqlConnection, Mysql};
#[cfg(feature = "mysql")]
use associations::Identifiable;

#[cfg(feature = "mysql")]
impl<T, ST> SaveChangesDsl<MysqlConnection, ST> for T where
    Mysql: HasSqlType<ST>,
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id, SqlType=ST>,
    Update<T, T>: ExecuteDsl<MysqlConnection>,
    Find<T::Table, T::Id>: LoadDsl<MysqlConnection, SqlType=ST>,
{
    fn save_changes<U>(self, conn: &MysqlConnection) -> QueryResult<U> where
        U: Queryable<ST, Mysql>,
    {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}
<commit_msg>Fix compile master with all database systems enabled<commit_after>use associations::HasTable;
use backend::SupportsReturningClause;
use connection::Connection;
use helper_types::*;
use query_builder::{AsChangeset, IntoUpdateTarget};
use query_dsl::*;
use query_source::Queryable;
use result::QueryResult;
use types::HasSqlType;
#[cfg(any(feature = "sqlite", feature = "mysql"))]
use associations::Identifiable;

pub trait SaveChangesDsl<Conn, ST> where
    Conn: Connection,
    Conn::Backend: HasSqlType<ST>,
{
    fn save_changes<T>(self, connection: &Conn) -> QueryResult<T> where
        T: Queryable<ST, Conn::Backend>;
}

impl<T, ST, Conn> SaveChangesDsl<Conn, ST> for T where
    Conn: Connection,
    Conn::Backend: HasSqlType<ST> + SupportsReturningClause,
    T: Copy + AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    Update<T, T>: LoadDsl<Conn, SqlType=ST>,
{
    fn save_changes<U>(self, conn: &Conn) -> QueryResult<U> where
        U: Queryable<ST, Conn::Backend>,
    {
        ::update(self).set(self).get_result(conn)
    }
}

#[cfg(feature = "sqlite")]
use sqlite::{SqliteConnection, Sqlite};

#[cfg(feature = "sqlite")]
impl<T, ST> SaveChangesDsl<SqliteConnection, ST> for T where
    Sqlite: HasSqlType<ST>,
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id, SqlType=ST>,
    Update<T, T>: ExecuteDsl<SqliteConnection>,
    Find<T::Table, T::Id>: LoadDsl<SqliteConnection, SqlType=ST>,
{
    fn save_changes<U>(self, conn: &SqliteConnection) -> QueryResult<U> where
        U: Queryable<ST, Sqlite>,
    {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}

#[cfg(feature = "mysql")]
use mysql::{MysqlConnection, Mysql};

#[cfg(feature = "mysql")]
impl<T, ST> SaveChangesDsl<MysqlConnection, ST> for T where
    Mysql: HasSqlType<ST>,
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id, SqlType=ST>,
    Update<T, T>: ExecuteDsl<MysqlConnection>,
    Find<T::Table, T::Id>: LoadDsl<MysqlConnection, SqlType=ST>,
{
    fn save_changes<U>(self, conn: &MysqlConnection) -> QueryResult<U> where
        U: Queryable<ST, Mysql>,
    {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}
<|endoftext|>


<commit_before>#![feature(old_path)]

extern crate piston;
extern crate ai_behavior;
extern crate sprite;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::old_path::*;

use std::cell::RefCell;
use std::rc::Rc;

use sprite::*;
use ai_behavior::{
    Action,
    Sequence,
    Wait,
    WaitForever,
    While,
};

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

fn main() {
    let (width, height) = (300, 300);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "piston-example-sprite".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut scene = Scene::new();
    let tex = Path::new("./bin/assets/rust-logo.png");
    let tex = Rc::new(Texture::from_path(&tex).unwrap());
    let mut sprite = Sprite::from_texture(tex.clone());
    sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

    let id = scene.add_child(sprite);

    // Run a sequence or animations.
    let seq = Sequence(vec![
        Action(Ease(EaseFunction::CubicOut, Box::new(ScaleTo(2.0, 0.5, 0.5)))),
        Action(Ease(EaseFunction::BounceOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Ease(EaseFunction::ElasticOut, Box::new(MoveBy(2.0, 0.0, -100.0)))),
        Action(Ease(EaseFunction::BackInOut, Box::new(MoveBy(1.0, 0.0, -100.0)))),
        Wait(0.5),
        Action(Ease(EaseFunction::ExponentialInOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Blink(1.0, 5)),
        While(Box::new(WaitForever), vec![
            Action(Ease(EaseFunction::QuadraticIn, Box::new(FadeOut(1.0)))),
            Action(Ease(EaseFunction::QuadraticOut, Box::new(FadeIn(1.0)))),
        ]),
    ]);
    scene.run(id.clone(), &seq);

    // This animation and the one above can run in parallel.
    let rotate = Action(Ease(EaseFunction::ExponentialInOut,
        Box::new(RotateTo(2.0, 360.0))));
    scene.run(id.clone(), &rotate);

    println!("Press any key to pause/resume the animation!");

    let ref mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        scene.event(&e);

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0, 1.0, 1.0, 1.0], gl);
                scene.draw(c.transform, gl);
            });
        }
        if let Some(_) = e.press_args() {
            scene.toggle(id.clone(), &seq);
            scene.toggle(id.clone(), &rotate);
        }
    }
}
<commit_msg>Upgrade sprite example to new path<commit_after>extern crate piston;
extern crate ai_behavior;
extern crate sprite;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::path::Path;
use std::cell::RefCell;
use std::rc::Rc;

use sprite::*;
use ai_behavior::{
    Action,
    Sequence,
    Wait,
    WaitForever,
    While,
};

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

fn main() {
    let (width, height) = (300, 300);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "piston-example-sprite".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut scene = Scene::new();
    let tex = Path::new("./bin/assets/rust-logo.png");
    let tex = Rc::new(Texture::from_path(&tex).unwrap());
    let mut sprite = Sprite::from_texture(tex.clone());
    sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

    let id = scene.add_child(sprite);

    // Run a sequence or animations.
    let seq = Sequence(vec![
        Action(Ease(EaseFunction::CubicOut, Box::new(ScaleTo(2.0, 0.5, 0.5)))),
        Action(Ease(EaseFunction::BounceOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Ease(EaseFunction::ElasticOut, Box::new(MoveBy(2.0, 0.0, -100.0)))),
        Action(Ease(EaseFunction::BackInOut, Box::new(MoveBy(1.0, 0.0, -100.0)))),
        Wait(0.5),
        Action(Ease(EaseFunction::ExponentialInOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Blink(1.0, 5)),
        While(Box::new(WaitForever), vec![
            Action(Ease(EaseFunction::QuadraticIn, Box::new(FadeOut(1.0)))),
            Action(Ease(EaseFunction::QuadraticOut, Box::new(FadeIn(1.0)))),
        ]),
    ]);
    scene.run(id.clone(), &seq);

    // This animation and the one above can run in parallel.
    let rotate = Action(Ease(EaseFunction::ExponentialInOut,
        Box::new(RotateTo(2.0, 360.0))));
    scene.run(id.clone(), &rotate);

    println!("Press any key to pause/resume the animation!");

    let ref mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        scene.event(&e);

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0, 1.0, 1.0, 1.0], gl);
                scene.draw(c.transform, gl);
            });
        }
        if let Some(_) = e.press_args() {
            scene.toggle(id.clone(), &seq);
            scene.toggle(id.clone(), &rotate);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//!
use std::fmt;
use std::time::Instant;
use std::{io, result};

use crate::BusDevice;
use logger::{warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
//use bus::Error;

// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
// From 0x0 to 0x1C we have following registers:
const RTCDR: u64 = 0x0; // Data Register.
const RTCMR: u64 = 0x4; // Match Register.
const RTCLR: u64 = 0x8; // Load Regiser.
const RTCCR: u64 = 0xc; // Control Register.
const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
                          // From 0x020 to 0xFDC => reserved space.
                          // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
                          // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
                          // of these devices (i.e look at the `amba_device_try_add` function).
                          // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
const PL031_ID: [u8; 8] = [0x31, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
// We are only interested in the margins.
const AMBA_ID_LOW: u64 = 0xFE0;
const AMBA_ID_HIGH: u64 = 0x1000;

pub enum Error {
    BadOffset(u64, &'static str),
    InterruptFailure(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BadOffset(offset, ops) => write!(f, "Bad {} offset: {}", ops, offset),
            Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
        }
    }
}
type Result<T> = result::Result<T, Error>;

/// A RTC device following the PL031 specification..
pub struct RTC {
    previous_now: Instant,
    tick_offset: i64,
    // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
    match_value: u32,
    // Writes to this register load an update value into the RTC.
    load: u32,
    imsc: u32,
    ris: u32,
    interrupt_evt: EventFd,
}

impl RTC {
    /// Constructs an AMBA PL031 RTC device.
    pub fn new(interrupt_evt: EventFd) -> RTC {
        RTC {
            // This is used only for duration measuring purposes.
            previous_now: Instant::now(),
            tick_offset: utils::time::get_time_ns(utils::time::ClockType::Real) as i64,
            match_value: 0,
            load: 0,
            imsc: 0,
            ris: 0,
            interrupt_evt,
        }
    }

    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.write(1).map_err(Error::InterruptFailure)
    }

    fn get_time(&self) -> u32 {
        let ts = (self.tick_offset as i128)
            + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
        (ts / utils::time::NANOS_PER_SECOND as i128) as u32
    }

    fn handle_read(&mut self, offset: u64) -> Result<u32> {
        let val;

        if offset < AMBA_ID_HIGH && offset >= AMBA_ID_LOW {
            let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
            val = u32::from(PL031_ID[index]);
        } else {
            val = match offset {
                RTCDR => self.get_time(),
                RTCMR => {
                    METRICS.rtc.missed_read_count.inc();
                    // Even though we are not implementing RTC alarm we return the last value
                    self.match_value
                }
                RTCLR => self.load,
                RTCCR => 1, // RTC is always enabled.
                RTCIMSC => self.imsc,
                RTCRIS => self.ris,
                RTCMIS => self.ris & self.imsc,
                off => {
                    return Err(Error::BadOffset(off, "read"));
                }
            };
        }
        Ok(val)
    }

    fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
        match offset {
            RTCMR => {
                // The MR register is used for implementing the RTC alarm. A real time clock alarm is
                // a feature that can be used to allow a computer to 'wake up' after shut down to execute
                // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
                // section of a motherboard's BIOS setup. This is functionality that extends beyond
                // Firecracker intended use. However, we increment a metric just in case.
                self.match_value = val;
                METRICS.rtc.missed_write_count.inc();
            }
            RTCLR => {
                self.load = val;
                self.previous_now = Instant::now();
                // If the unwrap fails, then the internal value of the clock has been corrupted and
                // we want to terminate the execution of the process.
                self.tick_offset = utils::time::seconds_to_nanoseconds(i64::from(val))
                    .expect("Time conversion overflow");
            }
            RTCIMSC => {
                self.imsc = val & 1;
                self.trigger_interrupt()?;
            }
            RTCICR => {
                // As per above mentioned doc, the interrupt is cleared by writing any data value to
                // the Interrupt Clear Register.
                self.ris = 0;
                self.trigger_interrupt()?;
            }
            RTCCR => (), // ignore attempts to turn off the timer.
            off => {
                return Err(Error::BadOffset(off, "write"));
            }
        }
        Ok(())
    }
    /// Provides a reference to the interrupt event fd.
    pub fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }
}

impl BusDevice for RTC {
    fn read(&mut self, offset: u64, data: &mut [u8]) {
        if data.len() <= 4 {
            match self.handle_read(offset) {
                Ok(val) => byte_order::write_le_u32(data, val),
                Err(e) => {
                    warn!("Failed to read from the RTC PL031 device: {}", e);
                    METRICS.rtc.error_count.inc();
                }
            }
        } else {
            warn!("Invalid RTC PL031 data length {}", data.len());
            METRICS.rtc.error_count.inc();
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if data.len() <= 4 {
            let v = byte_order::read_le_u32(&data[..]);
            if let Err(e) = self.handle_write(offset, v) {
                warn!("Failed to write to the RTC PL031 device: {}", e);
                METRICS.rtc.error_count.inc();
            }
        } else {
            warn!("Invalid RTC PL031 data length {}", data.len());
            METRICS.rtc.error_count.inc();
        }
    }
}

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

    #[test]
    fn test_rtc_read_write_and_event() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [0; 4];

        // Read and write to the MR register.
        byte_order::write_le_u32(&mut data, 123);
        rtc.write(RTCMR, &data);
        rtc.read(RTCMR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 123);

        // Read and write to the LR register.
        let v = utils::time::get_time_ns(utils::time::ClockType::Real);
        byte_order::write_le_u32(&mut data, (v / utils::time::NANOS_PER_SECOND) as u32);
        let previous_now_before = rtc.previous_now;
        rtc.write(RTCLR, &data);

        assert!(rtc.previous_now > previous_now_before);

        rtc.read(RTCLR, &mut data);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_eq!((v / utils::time::NANOS_PER_SECOND) as u32, v_read);

        // Read and write to IMSC register.
        // Test with non zero value.
        let non_zero = 1;
        byte_order::write_le_u32(&mut data, non_zero);
        rtc.write(RTCIMSC, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() == 1);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(non_zero & 1, v);

        // Now test with 0.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCIMSC, &data);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(0, v);

        // Read and write to the ICR register.
        byte_order::write_le_u32(&mut data, 1);
        rtc.write(RTCICR, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() > 1);
        let v_before = byte_order::read_le_u32(&data[..]);
        let no_errors_before = METRICS.rtc.error_count.count();

        rtc.read(RTCICR, &mut data);
        let no_errors_after = METRICS.rtc.error_count.count();
        let v = byte_order::read_le_u32(&data[..]);
        // ICR is a  write only register. Data received should stay equal to data sent.
        assert_eq!(v, v_before);
        assert_eq!(no_errors_after - no_errors_before, 1);

        // Attempts to turn off the RTC should not go through.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCCR, &data);
        rtc.read(RTCCR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 1);

        // Attempts to write beyond the writable space. Using here the space used to read
        // the CID and PID from.
        byte_order::write_le_u32(&mut data, 0);
        let no_errors_before = METRICS.rtc.error_count.count();
        rtc.write(AMBA_ID_LOW, &data);
        let no_errors_after = METRICS.rtc.error_count.count();
        assert_eq!(no_errors_after - no_errors_before, 1);
        // However, reading from the AMBA_ID_LOW should succeed upon read.

        let mut data = [0; 4];
        rtc.read(AMBA_ID_LOW, &mut data);
        let index = AMBA_ID_LOW + 3;
        assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
    }
}
<commit_msg>rtc: test bad offset error case<commit_after>// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//! ARM PL031 Real Time Clock
//!
//! This module implements a PL031 Real Time Clock (RTC) that provides to provides long time base counter.
//! This is achieved by generating an interrupt signal after counting for a programmed number of cycles of
//! a real-time clock input.
//!
use std::fmt;
use std::time::Instant;
use std::{io, result};

use crate::BusDevice;
use logger::{warn, IncMetric, METRICS};
use utils::byte_order;
use utils::eventfd::EventFd;
//use bus::Error;

// As you can see in https://static.docs.arm.com/ddi0224/c/real_time_clock_pl031_r1p3_technical_reference_manual_DDI0224C.pdf
// at section 3.2 Summary of RTC registers, the total size occupied by this device is 0x000 -> 0xFFC + 4 = 0x1000.
// From 0x0 to 0x1C we have following registers:
const RTCDR: u64 = 0x0; // Data Register.
const RTCMR: u64 = 0x4; // Match Register.
const RTCLR: u64 = 0x8; // Load Regiser.
const RTCCR: u64 = 0xc; // Control Register.
const RTCIMSC: u64 = 0x10; // Interrupt Mask Set or Clear Register.
const RTCRIS: u64 = 0x14; // Raw Interrupt Status.
const RTCMIS: u64 = 0x18; // Masked Interrupt Status.
const RTCICR: u64 = 0x1c; // Interrupt Clear Register.
                          // From 0x020 to 0xFDC => reserved space.
                          // From 0xFE0 to 0x1000 => Peripheral and PrimeCell Identification Registers which are Read Only registers.
                          // AMBA standard devices have CIDs (Cell IDs) and PIDs (Peripheral IDs). The linux kernel will look for these in order to assert the identity
                          // of these devices (i.e look at the `amba_device_try_add` function).
                          // We are putting the expected values (look at 'Reset value' column from above mentioned document) in an array.
const PL031_ID: [u8; 8] = [0x31, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
// We are only interested in the margins.
const AMBA_ID_LOW: u64 = 0xFE0;
const AMBA_ID_HIGH: u64 = 0x1000;

pub enum Error {
    BadOffset(u64, &'static str),
    InterruptFailure(io::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::BadOffset(offset, ops) => write!(f, "Bad {} offset: {}", ops, offset),
            Error::InterruptFailure(e) => write!(f, "Failed to trigger interrupt: {}", e),
        }
    }
}
type Result<T> = result::Result<T, Error>;

/// A RTC device following the PL031 specification..
pub struct RTC {
    previous_now: Instant,
    tick_offset: i64,
    // This is used for implementing the RTC alarm. However, in Firecracker we do not need it.
    match_value: u32,
    // Writes to this register load an update value into the RTC.
    load: u32,
    imsc: u32,
    ris: u32,
    interrupt_evt: EventFd,
}

impl RTC {
    /// Constructs an AMBA PL031 RTC device.
    pub fn new(interrupt_evt: EventFd) -> RTC {
        RTC {
            // This is used only for duration measuring purposes.
            previous_now: Instant::now(),
            tick_offset: utils::time::get_time_ns(utils::time::ClockType::Real) as i64,
            match_value: 0,
            load: 0,
            imsc: 0,
            ris: 0,
            interrupt_evt,
        }
    }

    fn trigger_interrupt(&mut self) -> Result<()> {
        self.interrupt_evt.write(1).map_err(Error::InterruptFailure)
    }

    fn get_time(&self) -> u32 {
        let ts = (self.tick_offset as i128)
            + (Instant::now().duration_since(self.previous_now).as_nanos() as i128);
        (ts / utils::time::NANOS_PER_SECOND as i128) as u32
    }

    fn handle_read(&mut self, offset: u64) -> Result<u32> {
        let val;

        if offset < AMBA_ID_HIGH && offset >= AMBA_ID_LOW {
            let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
            val = u32::from(PL031_ID[index]);
        } else {
            val = match offset {
                RTCDR => self.get_time(),
                RTCMR => {
                    METRICS.rtc.missed_read_count.inc();
                    // Even though we are not implementing RTC alarm we return the last value
                    self.match_value
                }
                RTCLR => self.load,
                RTCCR => 1, // RTC is always enabled.
                RTCIMSC => self.imsc,
                RTCRIS => self.ris,
                RTCMIS => self.ris & self.imsc,
                off => {
                    return Err(Error::BadOffset(off, "read"));
                }
            };
        }
        Ok(val)
    }

    fn handle_write(&mut self, offset: u64, val: u32) -> Result<()> {
        match offset {
            RTCMR => {
                // The MR register is used for implementing the RTC alarm. A real time clock alarm is
                // a feature that can be used to allow a computer to 'wake up' after shut down to execute
                // tasks every day or on a certain day. It can sometimes be found in the 'Power Management'
                // section of a motherboard's BIOS setup. This is functionality that extends beyond
                // Firecracker intended use. However, we increment a metric just in case.
                self.match_value = val;
                METRICS.rtc.missed_write_count.inc();
            }
            RTCLR => {
                self.load = val;
                self.previous_now = Instant::now();
                // If the unwrap fails, then the internal value of the clock has been corrupted and
                // we want to terminate the execution of the process.
                self.tick_offset = utils::time::seconds_to_nanoseconds(i64::from(val))
                    .expect("Time conversion overflow");
            }
            RTCIMSC => {
                self.imsc = val & 1;
                self.trigger_interrupt()?;
            }
            RTCICR => {
                // As per above mentioned doc, the interrupt is cleared by writing any data value to
                // the Interrupt Clear Register.
                self.ris = 0;
                self.trigger_interrupt()?;
            }
            RTCCR => (), // ignore attempts to turn off the timer.
            off => {
                return Err(Error::BadOffset(off, "write"));
            }
        }
        Ok(())
    }
    /// Provides a reference to the interrupt event fd.
    pub fn interrupt_evt(&self) -> &EventFd {
        &self.interrupt_evt
    }
}

impl BusDevice for RTC {
    fn read(&mut self, offset: u64, data: &mut [u8]) {
        if data.len() <= 4 {
            match self.handle_read(offset) {
                Ok(val) => byte_order::write_le_u32(data, val),
                Err(e) => {
                    warn!("Failed to read from the RTC PL031 device: {}", e);
                    METRICS.rtc.error_count.inc();
                }
            }
        } else {
            warn!("Invalid RTC PL031 data length {}", data.len());
            METRICS.rtc.error_count.inc();
        }
    }

    fn write(&mut self, offset: u64, data: &[u8]) {
        if data.len() <= 4 {
            let v = byte_order::read_le_u32(&data[..]);
            if let Err(e) = self.handle_write(offset, v) {
                warn!("Failed to write to the RTC PL031 device: {}", e);
                METRICS.rtc.error_count.inc();
            }
        } else {
            warn!("Invalid RTC PL031 data length {}", data.len());
            METRICS.rtc.error_count.inc();
        }
    }
}

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

    #[test]
    fn test_rtc_read_write_and_event() {
        let mut rtc = RTC::new(EventFd::new(libc::EFD_NONBLOCK).unwrap());
        let mut data = [0; 4];

        // Read and write to the DR register. Since this is a RO register, the write
        // function should fail.
        byte_order::write_le_u32(&mut data, 0);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCDR, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCDR, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 0);

        // Read and write to the MR register.
        byte_order::write_le_u32(&mut data, 123);
        rtc.write(RTCMR, &data);
        rtc.read(RTCMR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 123);

        // Read and write to the LR register.
        let v = utils::time::get_time_ns(utils::time::ClockType::Real);
        byte_order::write_le_u32(&mut data, (v / utils::time::NANOS_PER_SECOND) as u32);
        let previous_now_before = rtc.previous_now;
        rtc.write(RTCLR, &data);

        assert!(rtc.previous_now > previous_now_before);

        rtc.read(RTCLR, &mut data);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_eq!((v / utils::time::NANOS_PER_SECOND) as u32, v_read);

        // Read and write to IMSC register.
        // Test with non zero value.
        let non_zero = 1;
        byte_order::write_le_u32(&mut data, non_zero);
        rtc.write(RTCIMSC, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() == 1);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(non_zero & 1, v);

        // Now test with 0.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCIMSC, &data);
        rtc.read(RTCIMSC, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(0, v);

        // Read and write to the RIS RO register.
        byte_order::write_le_u32(&mut data, 1);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCRIS, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCRIS, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 1);

        // Read and write to the MIS RO register.
        byte_order::write_le_u32(&mut data, 1);
        let err_cnt_before_write = METRICS.rtc.error_count.count();
        rtc.write(RTCMIS, &data);
        let err_cnt_after_write = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write - err_cnt_before_write, 1);
        rtc.read(RTCMIS, &mut data);
        let err_cnt_after_read = METRICS.rtc.error_count.count();
        assert_eq!(err_cnt_after_write, err_cnt_after_read);
        let v_read = byte_order::read_le_u32(&data[..]);
        assert_ne!(v_read, 1);

        // Read and write to the ICR register.
        byte_order::write_le_u32(&mut data, 1);
        rtc.write(RTCICR, &data);
        // The interrupt line should be on.
        assert!(rtc.interrupt_evt.read().unwrap() > 1);
        let v_before = byte_order::read_le_u32(&data[..]);
        let no_errors_before = METRICS.rtc.error_count.count();

        rtc.read(RTCICR, &mut data);
        let no_errors_after = METRICS.rtc.error_count.count();
        let v = byte_order::read_le_u32(&data[..]);
        // ICR is a  write only register. Data received should stay equal to data sent.
        assert_eq!(v, v_before);
        assert_eq!(no_errors_after - no_errors_before, 1);

        // Attempts to turn off the RTC should not go through.
        byte_order::write_le_u32(&mut data, 0);
        rtc.write(RTCCR, &data);
        rtc.read(RTCCR, &mut data);
        let v = byte_order::read_le_u32(&data[..]);
        assert_eq!(v, 1);

        // Attempts to write beyond the writable space. Using here the space used to read
        // the CID and PID from.
        byte_order::write_le_u32(&mut data, 0);
        let no_errors_before = METRICS.rtc.error_count.count();
        rtc.write(AMBA_ID_LOW, &data);
        let no_errors_after = METRICS.rtc.error_count.count();
        assert_eq!(no_errors_after - no_errors_before, 1);
        // However, reading from the AMBA_ID_LOW should succeed upon read.

        let mut data = [0; 4];
        rtc.read(AMBA_ID_LOW, &mut data);
        let index = AMBA_ID_LOW + 3;
        assert_eq!(data[0], PL031_ID[((index - AMBA_ID_LOW) >> 2) as usize]);
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate nom;
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate libc;
extern crate slab;
extern crate rand;
extern crate nix;
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;

#[cfg(target_os = "linux")]
extern crate num_cpus;
//extern crate procinfo;

mod command;
mod worker;
mod logging;
mod upgrade;
mod limits;

use std::net::{UdpSocket,ToSocketAddrs};
use std::{mem,env};
use sozu::network::metrics::{METRICS,ProxyMetrics};
use sozu_command::config::Config;
use clap::{App,Arg,SubCommand};

#[cfg(target_os = "linux")]
use libc::{cpu_set_t,pid_t};

use command::Worker;
use worker::{begin_worker_process,start_workers};
use upgrade::begin_new_master_process;

fn main() {
  let matches = App::new("sozu")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .subcommand(SubCommand::with_name("start")
                                    .about("launch the master process")
                                    .arg(Arg::with_name("config")
                                        .short("c")
                                        .long("config")
                                        .value_name("FILE")
                                        .help("Sets a custom config file")
                                        .takes_value(true)
                                        .required(true)))
                        .subcommand(SubCommand::with_name("worker")
                                    .about("start a worker (internal command, should not be used directly)")
                                    .arg(Arg::with_name("id").long("id")
                                         .takes_value(true).required(true).help("worker identifier"))
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("start a new master process (internal command, should not be used directly)")
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id");
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(10000);

    begin_worker_process(fd, id, buffer_size);
    return;
  }

  if let Some(matches) = matches.subcommand_matches("upgrade") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(10000);

    begin_new_master_process(fd, buffer_size);
    return;
  }

  let submatches = matches.subcommand_matches("start").expect("unknown subcommand");
  let config_file = submatches.value_of("config").expect("required config file");

  if let Ok(config) = Config::load_from_path(config_file) {
    //FIXME: should have an id for the master too
    logging::setup("MASTER".to_string(), &config.log_level, &config.log_target);
    info!("starting up");

    let metrics_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
    let metrics_host   = (&config.metrics.address[..], config.metrics.port).to_socket_addrs().unwrap().next().unwrap();
    METRICS.lock().unwrap().set_up_remote(metrics_socket, metrics_host);
    let metrics_guard = ProxyMetrics::run();

    if check_process_limits(&config) {
      match start_workers(&config) {
        Ok(workers) => {
          info!("created workers: {:?}", workers);

          let handle_process_affinity = match config.handle_process_affinity {
            Some(val) => val,
            None => false
          };

          if cfg!(target_os = "linux") && handle_process_affinity {
            set_workers_affinity(&workers);
          }

          command::start(config, workers);
        },
        Err(e) => error!("Error while creating workers: {}", e)
      }
    }

    info!("master process stopped");
  } else {
    error!("could not load configuration file at '{}', stopping", config_file);
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(target_os = "linux")]
fn set_workers_affinity(workers: &Vec<Worker>) {
  let mut cpu_count = 0;
  let max_cpu = num_cpus::get();

  // +1 for the master process that will also be bound to its CPU core
  if (workers.len() + 1) > max_cpu {
    warn!("There are more workers than available CPU cores, \
          multiple workers will be bound to the same CPU core. \
          This may impact performances");
  }

  let master_pid = unsafe { libc::getpid() };
  set_process_affinity(master_pid, cpu_count);
  cpu_count = cpu_count + 1;

  for ref worker in workers {
    if cpu_count >= max_cpu {
      cpu_count = 0;
    }

    set_process_affinity(worker.pid, cpu_count);

    cpu_count = cpu_count + 1;
  }
}

/// Set a specific process to run onto a specific CPU core
#[cfg(target_os = "linux")]
fn set_process_affinity(pid: pid_t, cpu: usize) {
  unsafe {
    let mut cpu_set: cpu_set_t = mem::zeroed();
    let size_cpu_set = mem::size_of::<cpu_set_t>();
    libc::CPU_SET(cpu, &mut cpu_set);
    libc::sched_setaffinity(pid, size_cpu_set, &mut cpu_set);

    debug!("Worker {} bound to CPU core {}", pid, cpu);
  };
}

/* FIXME: uncomment this feature once code has been merged back into the procinfo crate
#[cfg(target_os="linux")]
fn check_process_limits(config: &Config) -> bool {
  let process_limits = procinfo::pid::limits_self().expect("Couldn't read /proc/self/limits to determine max open file descriptors limit");
  // We check the hard_limit. The soft_limit can be changed at runtime
  // by the process. hard_limit can only be changed by root
  let hard_limit = process_limits.max_open_files.hard_limit;

  // If limit is "unlimited"
  if hard_limit == -1 {
    return true;
  }

  let max_limit_per_proxy = config.proxies.values().all(|proxy| (proxy.max_connections as isize) <= hard_limit);
  if !max_limit_per_proxy {
    error!("At least one proxy can't have that much of connections. Current max file descriptor hard limit is: {}", hard_limit);
    return false;
  }

  let total_proxies_connections = config.proxies.values().fold(0, |acc, ref proxy| acc + proxy.max_connections);
  let system_max_fd = limits::limits_file_max().expect("Couldn't read /proc/sys/fs/file-max");

  if total_proxies_connections > system_max_fd {
    error!("Proxies total max_connections can't be higher than system's file-max limit. Current limit: {}, current value: {}",
           system_max_fd, total_proxies_connections);
    return false;
  }

  true
}
*/

//#[cfg(not(target_os="linux"))]
fn check_process_limits(_: &Config) -> bool {
  true
}
<commit_msg>add a placeholder for set_workers_affinity on non linux platforms<commit_after>#[macro_use] extern crate nom;
#[macro_use] extern crate clap;
#[macro_use] extern crate serde_derive;
extern crate mio;
extern crate mio_uds;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate libc;
extern crate slab;
extern crate rand;
extern crate nix;
#[macro_use] extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;

#[cfg(target_os = "linux")]
extern crate num_cpus;
//extern crate procinfo;

mod command;
mod worker;
mod logging;
mod upgrade;
mod limits;

use std::net::{UdpSocket,ToSocketAddrs};
use std::{mem,env};
use sozu::network::metrics::{METRICS,ProxyMetrics};
use sozu_command::config::Config;
use clap::{App,Arg,SubCommand};

#[cfg(target_os = "linux")]
use libc::{cpu_set_t,pid_t};

use command::Worker;
use worker::{begin_worker_process,start_workers};
use upgrade::begin_new_master_process;

fn main() {
  let matches = App::new("sozu")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .subcommand(SubCommand::with_name("start")
                                    .about("launch the master process")
                                    .arg(Arg::with_name("config")
                                        .short("c")
                                        .long("config")
                                        .value_name("FILE")
                                        .help("Sets a custom config file")
                                        .takes_value(true)
                                        .required(true)))
                        .subcommand(SubCommand::with_name("worker")
                                    .about("start a worker (internal command, should not be used directly)")
                                    .arg(Arg::with_name("id").long("id")
                                         .takes_value(true).required(true).help("worker identifier"))
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("start a new master process (internal command, should not be used directly)")
                                    .arg(Arg::with_name("fd").long("fd")
                                         .takes_value(true).required(true).help("IPC file descriptor"))
                                    .arg(Arg::with_name("channel-buffer-size").long("channel-buffer-size")
                                         .takes_value(true).required(false).help("Worker's channel buffer size")))
                        .get_matches();

  if let Some(matches) = matches.subcommand_matches("worker") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let id  = matches.value_of("id").expect("needs a worker id");
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(10000);

    begin_worker_process(fd, id, buffer_size);
    return;
  }

  if let Some(matches) = matches.subcommand_matches("upgrade") {
    let fd  = matches.value_of("fd").expect("needs a file descriptor")
      .parse::<i32>().expect("the file descriptor must be a number");
    let buffer_size = matches.value_of("channel-buffer-size")
      .and_then(|size| size.parse::<usize>().ok())
      .unwrap_or(10000);

    begin_new_master_process(fd, buffer_size);
    return;
  }

  let submatches = matches.subcommand_matches("start").expect("unknown subcommand");
  let config_file = submatches.value_of("config").expect("required config file");

  if let Ok(config) = Config::load_from_path(config_file) {
    //FIXME: should have an id for the master too
    logging::setup("MASTER".to_string(), &config.log_level, &config.log_target);
    info!("starting up");

    let metrics_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
    let metrics_host   = (&config.metrics.address[..], config.metrics.port).to_socket_addrs().unwrap().next().unwrap();
    METRICS.lock().unwrap().set_up_remote(metrics_socket, metrics_host);
    let metrics_guard = ProxyMetrics::run();

    if check_process_limits(&config) {
      match start_workers(&config) {
        Ok(workers) => {
          info!("created workers: {:?}", workers);

          let handle_process_affinity = match config.handle_process_affinity {
            Some(val) => val,
            None => false
          };

          if cfg!(target_os = "linux") && handle_process_affinity {
            set_workers_affinity(&workers);
          }

          command::start(config, workers);
        },
        Err(e) => error!("Error while creating workers: {}", e)
      }
    }

    info!("master process stopped");
  } else {
    error!("could not load configuration file at '{}', stopping", config_file);
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(target_os = "linux")]
fn set_workers_affinity(workers: &Vec<Worker>) {
  let mut cpu_count = 0;
  let max_cpu = num_cpus::get();

  // +1 for the master process that will also be bound to its CPU core
  if (workers.len() + 1) > max_cpu {
    warn!("There are more workers than available CPU cores, \
          multiple workers will be bound to the same CPU core. \
          This may impact performances");
  }

  let master_pid = unsafe { libc::getpid() };
  set_process_affinity(master_pid, cpu_count);
  cpu_count = cpu_count + 1;

  for ref worker in workers {
    if cpu_count >= max_cpu {
      cpu_count = 0;
    }

    set_process_affinity(worker.pid, cpu_count);

    cpu_count = cpu_count + 1;
  }
}

/// Set workers process affinity, see man sched_setaffinity
/// Bind each worker (including the master) process to a CPU core.
/// Can bind multiple processes to a CPU core if there are more processes
/// than CPU cores. Only works on Linux.
#[cfg(not(target_os = "linux"))]
fn set_workers_affinity(_: &Vec<Worker>) {
}

/// Set a specific process to run onto a specific CPU core
#[cfg(target_os = "linux")]
fn set_process_affinity(pid: pid_t, cpu: usize) {
  unsafe {
    let mut cpu_set: cpu_set_t = mem::zeroed();
    let size_cpu_set = mem::size_of::<cpu_set_t>();
    libc::CPU_SET(cpu, &mut cpu_set);
    libc::sched_setaffinity(pid, size_cpu_set, &mut cpu_set);

    debug!("Worker {} bound to CPU core {}", pid, cpu);
  };
}

/* FIXME: uncomment this feature once code has been merged back into the procinfo crate
#[cfg(target_os="linux")]
fn check_process_limits(config: &Config) -> bool {
  let process_limits = procinfo::pid::limits_self().expect("Couldn't read /proc/self/limits to determine max open file descriptors limit");
  // We check the hard_limit. The soft_limit can be changed at runtime
  // by the process. hard_limit can only be changed by root
  let hard_limit = process_limits.max_open_files.hard_limit;

  // If limit is "unlimited"
  if hard_limit == -1 {
    return true;
  }

  let max_limit_per_proxy = config.proxies.values().all(|proxy| (proxy.max_connections as isize) <= hard_limit);
  if !max_limit_per_proxy {
    error!("At least one proxy can't have that much of connections. Current max file descriptor hard limit is: {}", hard_limit);
    return false;
  }

  let total_proxies_connections = config.proxies.values().fold(0, |acc, ref proxy| acc + proxy.max_connections);
  let system_max_fd = limits::limits_file_max().expect("Couldn't read /proc/sys/fs/file-max");

  if total_proxies_connections > system_max_fd {
    error!("Proxies total max_connections can't be higher than system's file-max limit. Current limit: {}, current value: {}",
           system_max_fd, total_proxies_connections);
    return false;
  }

  true
}
*/

//#[cfg(not(target_os="linux"))]
fn check_process_limits(_: &Config) -> bool {
  true
}
<|endoftext|>


<commit_before>use executor::Variables;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;

enum Sample {
    One,
    Two,
}

struct Scalar(i32);

struct Interface {}

struct Root {}

graphql_scalar!(Scalar as "SampleScalar" {
    resolve(&self) -> Value {
        Value::int(self.0)
    }

    from_input_value(v: &InputValue) -> Option<Scalar> {
        v.as_int_value().map(|i| Scalar(i))
    }
});

graphql_enum!(Sample as "SampleEnum" {
    Sample::One => "ONE",
    Sample::Two => "TWO",
});

graphql_interface!(Interface: () as "SampleInterface" |&self| {
    description: "A sample interface"

    field sample_enum() -> Sample as "A sample field in the interface" {
        Sample::One
    }

    instance_resolvers: |&_| {
        Root => Some(Root {}),
    }
});

graphql_object!(Root: () |&self| {
    description: "The root query object in the schema"

    interfaces: [Interface]

    field sample_enum() -> Sample {
        Sample::One
    }

    field sample_scalar(
        first: i32 as "The first number",
        second = 123: i32 as "The second number"
    ) -> Scalar as "A sample scalar field on the object" {
        Scalar(first + second)
    }
});

#[test]
fn test_execution() {
    let doc = r#"
    {
        sampleEnum
        first: sampleScalar(first: 0)
        second: sampleScalar(first: 10 second: 20)
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    assert_eq!(result, Value::object(vec![
        ("sampleEnum", Value::string("ONE")),
        ("first", Value::int(123)),
        ("second", Value::int(30)),
    ].into_iter().collect()));
}

#[test]
fn enum_introspection() {
    let doc = r#"
    {
        __type(name: "SampleEnum") {
            name
            kind
            description
            enumValues {
                name
                description
                isDeprecated
                deprecationReason
            }
            interfaces { name }
            possibleTypes { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing")
        .as_object_value().expect("__type field not an object value");

    assert_eq!(type_info.get("name"), Some(&Value::string("SampleEnum")));
    assert_eq!(type_info.get("kind"), Some(&Value::string("ENUM")));
    assert_eq!(type_info.get("description"), Some(&Value::null()));
    assert_eq!(type_info.get("interfaces"), Some(&Value::null()));
    assert_eq!(type_info.get("possibleTypes"), Some(&Value::null()));
    assert_eq!(type_info.get("inputFields"), Some(&Value::null()));
    assert_eq!(type_info.get("ofType"), Some(&Value::null()));

    let values = type_info
        .get("enumValues").expect("enumValues field missing")
        .as_list_value().expect("enumValues not a list");

    assert_eq!(values.len(), 2);

    assert!(values.contains(&Value::object(vec![
        ("name", Value::string("ONE")),
        ("description", Value::null()),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));

    assert!(values.contains(&Value::object(vec![
        ("name", Value::string("TWO")),
        ("description", Value::null()),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));
}

#[test]
fn interface_introspection() {
    let doc = r#"
    {
        __type(name: "SampleInterface") {
            name
            kind
            description
            possibleTypes {
                name
            }
            fields {
                name
                description
                args {
                    name
                }
                type {
                    name
                    kind
                    ofType {
                        name
                        kind
                    }
                }
                isDeprecated
                deprecationReason
            }
            interfaces { name }
            enumValues { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing")
        .as_object_value().expect("__type field not an object value");

    assert_eq!(type_info.get("name"), Some(&Value::string("SampleInterface")));
    assert_eq!(type_info.get("kind"), Some(&Value::string("INTERFACE")));
    assert_eq!(type_info.get("description"), Some(&Value::string("A sample interface")));
    assert_eq!(type_info.get("interfaces"), Some(&Value::null()));
    assert_eq!(type_info.get("enumValues"), Some(&Value::null()));
    assert_eq!(type_info.get("inputFields"), Some(&Value::null()));
    assert_eq!(type_info.get("ofType"), Some(&Value::null()));

    let possible_types = type_info
        .get("possibleTypes").expect("possibleTypes field missing")
        .as_list_value().expect("possibleTypes not a list");

    assert_eq!(possible_types.len(), 1);

    assert!(possible_types.contains(&Value::object(vec![
        ("name", Value::string("Root")),
    ].into_iter().collect())));

    let fields = type_info
        .get("fields").expect("fields field missing")
        .as_list_value().expect("fields field not an object value");

    assert_eq!(fields.len(), 2);

    assert!(fields.contains(&Value::object(vec![
        ("name", Value::string("sampleEnum")),
        ("description", Value::string("A sample field in the interface")),
        ("args", Value::list(vec![])),
        ("type", Value::object(vec![
            ("name", Value::null()),
            ("kind", Value::string("NON_NULL")),
            ("ofType", Value::object(vec![
                ("name", Value::string("SampleEnum")),
                ("kind", Value::string("ENUM")),
            ].into_iter().collect())),
        ].into_iter().collect())),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));
}

#[test]
fn object_introspection() {
    let doc = r#"
    {
        __type(name: "Root") {
            name
            kind
            description
            fields {
                name
                description
                args {
                    name
                    description
                    type {
                        name
                        kind
                        ofType {
                            name
                            kind
                            ofType {
                                name
                            }
                        }
                    }
                    defaultValue
                }
                type {
                    name
                    kind
                    ofType {
                        name
                        kind
                    }
                }
                isDeprecated
                deprecationReason
            }
            possibleTypes { name }
            interfaces { name }
            enumValues { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing")
        .as_object_value().expect("__type field not an object value");

    assert_eq!(type_info.get("name"), Some(&Value::string("Root")));
    assert_eq!(type_info.get("kind"), Some(&Value::string("OBJECT")));
    assert_eq!(type_info.get("description"), Some(&Value::string("The root query object in the schema")));
    assert_eq!(
        type_info.get("interfaces"),
        Some(&Value::list(vec![
            Value::object(vec![
                ("name", Value::string("SampleInterface")),
            ].into_iter().collect()),
        ])));
    assert_eq!(type_info.get("enumValues"), Some(&Value::null()));
    assert_eq!(type_info.get("inputFields"), Some(&Value::null()));
    assert_eq!(type_info.get("ofType"), Some(&Value::null()));
    assert_eq!(type_info.get("possibleTypes"), Some(&Value::null()));

    let fields = type_info
        .get("fields").expect("fields field missing")
        .as_list_value().expect("fields field not an object value");

    assert_eq!(fields.len(), 5); // The two fields, __typename, __type, __schema

    println!("Fields: {:#?}", fields);

    assert!(fields.contains(&Value::object(vec![
        ("name", Value::string("sampleEnum")),
        ("description", Value::null()),
        ("args", Value::list(vec![])),
        ("type", Value::object(vec![
            ("name", Value::null()),
            ("kind", Value::string("NON_NULL")),
            ("ofType", Value::object(vec![
                ("name", Value::string("SampleEnum")),
                ("kind", Value::string("ENUM")),
            ].into_iter().collect())),
        ].into_iter().collect())),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));

    assert!(fields.contains(&Value::object(vec![
        ("name", Value::string("sampleScalar")),
        ("description", Value::string("A sample scalar field on the object")),
        ("args", Value::list(vec![
            Value::object(vec![
                ("name", Value::string("first")),
                ("description", Value::string("The first number")),
                ("type", Value::object(vec![
                    ("name", Value::null()),
                    ("kind", Value::string("NON_NULL")),
                    ("ofType", Value::object(vec![
                        ("name", Value::string("Int")),
                        ("kind", Value::string("SCALAR")),
                        ("ofType", Value::null()),
                    ].into_iter().collect())),
                ].into_iter().collect())),
                ("defaultValue", Value::null()),
            ].into_iter().collect()),
            Value::object(vec![
                ("name", Value::string("second")),
                ("description", Value::string("The second number")),
                ("type", Value::object(vec![
                    ("name", Value::string("Int")),
                    ("kind", Value::string("SCALAR")),
                    ("ofType", Value::null()),
                ].into_iter().collect())),
                ("defaultValue", Value::string("123")),
            ].into_iter().collect()),
        ])),
        ("type", Value::object(vec![
            ("name", Value::null()),
            ("kind", Value::string("NON_NULL")),
            ("ofType", Value::object(vec![
                ("name", Value::string("SampleScalar")),
                ("kind", Value::string("SCALAR")),
            ].into_iter().collect())),
        ].into_iter().collect())),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));
}

#[test]
fn scalar_introspection() {
    let doc = r#"
    {
        __type(name: "SampleScalar") {
            name
            kind
            description
            fields { name }
            interfaces { name }
            possibleTypes { name }
            enumValues { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing");

    assert_eq!(type_info, &Value::object(vec![
        ("name", Value::string("SampleScalar")),
        ("kind", Value::string("SCALAR")),
        ("description", Value::null()),
        ("fields", Value::null()),
        ("interfaces", Value::null()),
        ("possibleTypes", Value::null()),
        ("enumValues", Value::null()),
        ("inputFields", Value::null()),
        ("ofType", Value::null()),
    ].into_iter().collect()));
}
<commit_msg>Fix tests after removing internal fields from introspection<commit_after>use executor::Variables;
use value::Value;
use schema::model::RootNode;
use types::scalars::EmptyMutation;

enum Sample {
    One,
    Two,
}

struct Scalar(i32);

struct Interface {}

struct Root {}

graphql_scalar!(Scalar as "SampleScalar" {
    resolve(&self) -> Value {
        Value::int(self.0)
    }

    from_input_value(v: &InputValue) -> Option<Scalar> {
        v.as_int_value().map(|i| Scalar(i))
    }
});

graphql_enum!(Sample as "SampleEnum" {
    Sample::One => "ONE",
    Sample::Two => "TWO",
});

graphql_interface!(Interface: () as "SampleInterface" |&self| {
    description: "A sample interface"

    field sample_enum() -> Sample as "A sample field in the interface" {
        Sample::One
    }

    instance_resolvers: |&_| {
        Root => Some(Root {}),
    }
});

graphql_object!(Root: () |&self| {
    description: "The root query object in the schema"

    interfaces: [Interface]

    field sample_enum() -> Sample {
        Sample::One
    }

    field sample_scalar(
        first: i32 as "The first number",
        second = 123: i32 as "The second number"
    ) -> Scalar as "A sample scalar field on the object" {
        Scalar(first + second)
    }
});

#[test]
fn test_execution() {
    let doc = r#"
    {
        sampleEnum
        first: sampleScalar(first: 0)
        second: sampleScalar(first: 10 second: 20)
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    assert_eq!(result, Value::object(vec![
        ("sampleEnum", Value::string("ONE")),
        ("first", Value::int(123)),
        ("second", Value::int(30)),
    ].into_iter().collect()));
}

#[test]
fn enum_introspection() {
    let doc = r#"
    {
        __type(name: "SampleEnum") {
            name
            kind
            description
            enumValues {
                name
                description
                isDeprecated
                deprecationReason
            }
            interfaces { name }
            possibleTypes { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing")
        .as_object_value().expect("__type field not an object value");

    assert_eq!(type_info.get("name"), Some(&Value::string("SampleEnum")));
    assert_eq!(type_info.get("kind"), Some(&Value::string("ENUM")));
    assert_eq!(type_info.get("description"), Some(&Value::null()));
    assert_eq!(type_info.get("interfaces"), Some(&Value::null()));
    assert_eq!(type_info.get("possibleTypes"), Some(&Value::null()));
    assert_eq!(type_info.get("inputFields"), Some(&Value::null()));
    assert_eq!(type_info.get("ofType"), Some(&Value::null()));

    let values = type_info
        .get("enumValues").expect("enumValues field missing")
        .as_list_value().expect("enumValues not a list");

    assert_eq!(values.len(), 2);

    assert!(values.contains(&Value::object(vec![
        ("name", Value::string("ONE")),
        ("description", Value::null()),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));

    assert!(values.contains(&Value::object(vec![
        ("name", Value::string("TWO")),
        ("description", Value::null()),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));
}

#[test]
fn interface_introspection() {
    let doc = r#"
    {
        __type(name: "SampleInterface") {
            name
            kind
            description
            possibleTypes {
                name
            }
            fields {
                name
                description
                args {
                    name
                }
                type {
                    name
                    kind
                    ofType {
                        name
                        kind
                    }
                }
                isDeprecated
                deprecationReason
            }
            interfaces { name }
            enumValues { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing")
        .as_object_value().expect("__type field not an object value");

    assert_eq!(type_info.get("name"), Some(&Value::string("SampleInterface")));
    assert_eq!(type_info.get("kind"), Some(&Value::string("INTERFACE")));
    assert_eq!(type_info.get("description"), Some(&Value::string("A sample interface")));
    assert_eq!(type_info.get("interfaces"), Some(&Value::null()));
    assert_eq!(type_info.get("enumValues"), Some(&Value::null()));
    assert_eq!(type_info.get("inputFields"), Some(&Value::null()));
    assert_eq!(type_info.get("ofType"), Some(&Value::null()));

    let possible_types = type_info
        .get("possibleTypes").expect("possibleTypes field missing")
        .as_list_value().expect("possibleTypes not a list");

    assert_eq!(possible_types.len(), 1);

    assert!(possible_types.contains(&Value::object(vec![
        ("name", Value::string("Root")),
    ].into_iter().collect())));

    let fields = type_info
        .get("fields").expect("fields field missing")
        .as_list_value().expect("fields field not an object value");

    assert_eq!(fields.len(), 1);

    assert!(fields.contains(&Value::object(vec![
        ("name", Value::string("sampleEnum")),
        ("description", Value::string("A sample field in the interface")),
        ("args", Value::list(vec![])),
        ("type", Value::object(vec![
            ("name", Value::null()),
            ("kind", Value::string("NON_NULL")),
            ("ofType", Value::object(vec![
                ("name", Value::string("SampleEnum")),
                ("kind", Value::string("ENUM")),
            ].into_iter().collect())),
        ].into_iter().collect())),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));
}

#[test]
fn object_introspection() {
    let doc = r#"
    {
        __type(name: "Root") {
            name
            kind
            description
            fields {
                name
                description
                args {
                    name
                    description
                    type {
                        name
                        kind
                        ofType {
                            name
                            kind
                            ofType {
                                name
                            }
                        }
                    }
                    defaultValue
                }
                type {
                    name
                    kind
                    ofType {
                        name
                        kind
                    }
                }
                isDeprecated
                deprecationReason
            }
            possibleTypes { name }
            interfaces { name }
            enumValues { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing")
        .as_object_value().expect("__type field not an object value");

    assert_eq!(type_info.get("name"), Some(&Value::string("Root")));
    assert_eq!(type_info.get("kind"), Some(&Value::string("OBJECT")));
    assert_eq!(type_info.get("description"), Some(&Value::string("The root query object in the schema")));
    assert_eq!(
        type_info.get("interfaces"),
        Some(&Value::list(vec![
            Value::object(vec![
                ("name", Value::string("SampleInterface")),
            ].into_iter().collect()),
        ])));
    assert_eq!(type_info.get("enumValues"), Some(&Value::null()));
    assert_eq!(type_info.get("inputFields"), Some(&Value::null()));
    assert_eq!(type_info.get("ofType"), Some(&Value::null()));
    assert_eq!(type_info.get("possibleTypes"), Some(&Value::null()));

    let fields = type_info
        .get("fields").expect("fields field missing")
        .as_list_value().expect("fields field not an object value");

    assert_eq!(fields.len(), 2);

    println!("Fields: {:#?}", fields);

    assert!(fields.contains(&Value::object(vec![
        ("name", Value::string("sampleEnum")),
        ("description", Value::null()),
        ("args", Value::list(vec![])),
        ("type", Value::object(vec![
            ("name", Value::null()),
            ("kind", Value::string("NON_NULL")),
            ("ofType", Value::object(vec![
                ("name", Value::string("SampleEnum")),
                ("kind", Value::string("ENUM")),
            ].into_iter().collect())),
        ].into_iter().collect())),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));

    assert!(fields.contains(&Value::object(vec![
        ("name", Value::string("sampleScalar")),
        ("description", Value::string("A sample scalar field on the object")),
        ("args", Value::list(vec![
            Value::object(vec![
                ("name", Value::string("first")),
                ("description", Value::string("The first number")),
                ("type", Value::object(vec![
                    ("name", Value::null()),
                    ("kind", Value::string("NON_NULL")),
                    ("ofType", Value::object(vec![
                        ("name", Value::string("Int")),
                        ("kind", Value::string("SCALAR")),
                        ("ofType", Value::null()),
                    ].into_iter().collect())),
                ].into_iter().collect())),
                ("defaultValue", Value::null()),
            ].into_iter().collect()),
            Value::object(vec![
                ("name", Value::string("second")),
                ("description", Value::string("The second number")),
                ("type", Value::object(vec![
                    ("name", Value::string("Int")),
                    ("kind", Value::string("SCALAR")),
                    ("ofType", Value::null()),
                ].into_iter().collect())),
                ("defaultValue", Value::string("123")),
            ].into_iter().collect()),
        ])),
        ("type", Value::object(vec![
            ("name", Value::null()),
            ("kind", Value::string("NON_NULL")),
            ("ofType", Value::object(vec![
                ("name", Value::string("SampleScalar")),
                ("kind", Value::string("SCALAR")),
            ].into_iter().collect())),
        ].into_iter().collect())),
        ("isDeprecated", Value::boolean(false)),
        ("deprecationReason", Value::null()),
    ].into_iter().collect())));
}

#[test]
fn scalar_introspection() {
    let doc = r#"
    {
        __type(name: "SampleScalar") {
            name
            kind
            description
            fields { name }
            interfaces { name }
            possibleTypes { name }
            enumValues { name }
            inputFields { name }
            ofType { name }
        }
    }
    "#;
    let schema = RootNode::new(Root {}, EmptyMutation::<()>::new());

    let (result, errs) = ::execute(doc, None, &schema, &Variables::new(), &())
        .expect("Execution failed");

    assert_eq!(errs, []);

    println!("Result: {:?}", result);

    let type_info = result
        .as_object_value().expect("Result is not an object")
        .get("__type").expect("__type field missing");

    assert_eq!(type_info, &Value::object(vec![
        ("name", Value::string("SampleScalar")),
        ("kind", Value::string("SCALAR")),
        ("description", Value::null()),
        ("fields", Value::null()),
        ("interfaces", Value::null()),
        ("possibleTypes", Value::null()),
        ("enumValues", Value::null()),
        ("inputFields", Value::null()),
        ("ofType", Value::null()),
    ].into_iter().collect()));
}
<|endoftext|>