<commit_before>//! Syslog drain for slog-rs
//!
//! WARNING: This crate needs some improvements.
//!
//! ```norust
//! #[macro_use]
//! extern crate slog;
//! extern crate slog_syslog;
//!
//! use slog::*;
//! use slog_syslog::Facility;
//!
//! fn main() {
//!     let root = Logger::new_root(o!("build-id" => "8dfljdf"));
//!     root.set_drain(
//!             slog_syslog::unix_3164(
//!                 Facility::LOG_USER,
//!                 )
//!             );
//! }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_stream;
extern crate syslog;
extern crate nix;

use slog_stream::Format;
use slog::{Drain, Level, Record, OwnedKeyValueList};
use slog::ser::Serializer;
use std::{io, fmt};
use std::sync::Mutex;
use std::cell::RefCell;

use slog::ser;

pub use syslog::Facility;

thread_local! {
    static TL_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(128))
}

fn level_to_severity(level: slog::Level) -> syslog::Severity {
    match level {
        Level::Critical => syslog::Severity::LOG_CRIT,
        Level::Error => syslog::Severity::LOG_ERR,
        Level::Warning => syslog::Severity::LOG_WARNING,
        Level::Info => syslog::Severity::LOG_NOTICE,
        Level::Debug => syslog::Severity::LOG_INFO,
        Level::Trace => syslog::Severity::LOG_DEBUG,
    }

}

/// Drain formatting records and writing them to a syslog ``Logger`
///
/// Uses mutex to serialize writes.
/// TODO: Add one that does not serialize?
pub struct Streamer3164 {
    io: Mutex<Box<syslog::Logger>>,
    format: Format3164,
}

impl Streamer3164 {
    /// Create new syslog ``Streamer` using given `format`
    pub fn new(logger: Box<syslog::Logger>) -> Self {
        Streamer3164 {
            io: Mutex::new(logger),
            format: Format3164::new(),
        }
    }
}

impl Drain for Streamer3164 {
    type Error = io::Error;

    fn log(&self, info: &Record, logger_values: &OwnedKeyValueList) -> io::Result<()> {

        TL_BUF.with(|buf| {
            let mut buf = buf.borrow_mut();
            let res = {
                || {
                    try!(self.format.format(&mut *buf, info, logger_values));
                    let sever = level_to_severity(info.level());
                    {
                        let io = try!(self.io
                            .lock()
                            .map_err(|_| io::Error::new(io::ErrorKind::Other, "locking error")));
                        try!(io.send(sever, &String::from_utf8_lossy(&buf)));
                    }

                    Ok(())

                }
            }();
            res
        })
    }
}

/// Formatter to format defined in RFC 3164
pub struct Format3164;

impl Format3164 {
    /// Create new `Format3164`
    pub fn new() -> Self {
        Format3164
    }
}

impl slog_stream::Format for Format3164 {
    fn format(&self,
              io: &mut io::Write,
              rinfo: &Record,
              logger_values: &OwnedKeyValueList)
              -> io::Result<()> {
        let mut ser = KSV::new(io, "=".into());
        {
            for &(ref k, ref v) in logger_values.iter() {
                try!(v.serialize(rinfo, k, &mut ser));
                let _ = try!(ser.io().write_all(" ".as_bytes()));
            }

            for &(ref k, ref v) in rinfo.values().iter() {
                try!(v.serialize(rinfo, k, &mut ser));
                let _ = try!(ser.io().write_all(" ".as_bytes()));
            }
        }
        Ok(())
    }
}

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

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

    fn io(&mut self) -> &mut W {
        &mut self.io
    }
}

impl<W: io::Write> Serializer for KSV<W> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}", key));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
}

/// `Streamer` to Unix syslog using RFC 3164 format
pub fn unix_3164(facility: syslog::Facility) -> Streamer3164 {
    Streamer3164::new(syslog::unix(facility).unwrap())
}
<commit_msg>fix(syslog): #53: clear buffer after logging, behave like write_all<commit_after>//! Syslog drain for slog-rs
//!
//! WARNING: This crate needs some improvements.
//!
//! ```norust
//! #[macro_use]
//! extern crate slog;
//! extern crate slog_syslog;
//!
//! use slog::*;
//! use slog_syslog::Facility;
//!
//! fn main() {
//!     let root = Logger::new_root(o!("build-id" => "8dfljdf"));
//!     root.set_drain(
//!             slog_syslog::unix_3164(
//!                 Facility::LOG_USER,
//!                 )
//!             );
//! }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_stream;
extern crate syslog;
extern crate nix;

use slog_stream::Format;
use slog::{Drain, Level, Record, OwnedKeyValueList};
use slog::ser::Serializer;
use std::{io, fmt};
use std::sync::Mutex;
use std::cell::RefCell;

use slog::ser;

pub use syslog::Facility;

thread_local! {
    static TL_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(128))
}

fn level_to_severity(level: slog::Level) -> syslog::Severity {
    match level {
        Level::Critical => syslog::Severity::LOG_CRIT,
        Level::Error => syslog::Severity::LOG_ERR,
        Level::Warning => syslog::Severity::LOG_WARNING,
        Level::Info => syslog::Severity::LOG_NOTICE,
        Level::Debug => syslog::Severity::LOG_INFO,
        Level::Trace => syslog::Severity::LOG_DEBUG,
    }

}

/// Drain formatting records and writing them to a syslog ``Logger`
///
/// Uses mutex to serialize writes.
/// TODO: Add one that does not serialize?
pub struct Streamer3164 {
    io: Mutex<Box<syslog::Logger>>,
    format: Format3164,
}

impl Streamer3164 {
    /// Create new syslog ``Streamer` using given `format`
    pub fn new(logger: Box<syslog::Logger>) -> Self {
        Streamer3164 {
            io: Mutex::new(logger),
            format: Format3164::new(),
        }
    }
}

impl Drain for Streamer3164 {
    type Error = io::Error;

    fn log(&self, info: &Record, logger_values: &OwnedKeyValueList) -> io::Result<()> {

        TL_BUF.with(|buf| {
            let mut buf = buf.borrow_mut();
            let res = {
                || {
                    try!(self.format.format(&mut *buf, info, logger_values));
                    let sever = level_to_severity(info.level());
                    {
                        let io = try!(self.io
                            .lock()
                            .map_err(|_| io::Error::new(io::ErrorKind::Other, "locking error")));

                        let buf = String::from_utf8_lossy(&buf);
                        let buf = io.format_3164(sever, &buf).into_bytes();

                        let mut pos = 0;
                        while pos < buf.len() {
                            let n = try!(io.send_raw(&buf[pos..]));
                            if n == 0 {
                                break
                            }

                            pos += n;
                        }
                    }

                    Ok(())
                }
            }();
            buf.clear();
            res
        })
    }
}

/// Formatter to format defined in RFC 3164
pub struct Format3164;

impl Format3164 {
    /// Create new `Format3164`
    pub fn new() -> Self {
        Format3164
    }
}

impl slog_stream::Format for Format3164 {
    fn format(&self,
              io: &mut io::Write,
              rinfo: &Record,
              logger_values: &OwnedKeyValueList)
              -> io::Result<()> {
        let mut ser = KSV::new(io, "=".into());
        {
            for &(ref k, ref v) in logger_values.iter() {
                try!(v.serialize(rinfo, k, &mut ser));
                let _ = try!(ser.io().write_all(" ".as_bytes()));
            }

            for &(ref k, ref v) in rinfo.values().iter() {
                try!(v.serialize(rinfo, k, &mut ser));
                let _ = try!(ser.io().write_all(" ".as_bytes()));
            }
        }
        Ok(())
    }
}

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

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

    fn io(&mut self) -> &mut W {
        &mut self.io
    }
}

impl<W: io::Write> Serializer for KSV<W> {
    fn emit_none(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
        Ok(())
    }
    fn emit_unit(&mut self, key: &str) -> ser::Result {
        try!(write!(self.io, "{}", key));
        Ok(())
    }

    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }

    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
        try!(write!(self.io, "{}{}{}", key, self.separator, val));
        Ok(())
    }
}

/// `Streamer` to Unix syslog using RFC 3164 format
pub fn unix_3164(facility: syslog::Facility) -> Streamer3164 {
    Streamer3164::new(syslog::unix(facility).unwrap())
}
<|endoftext|>


<commit_before>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

#[macro_export]
macro_rules! cubeb_log_internal {
    ($level: expr, $msg: expr) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                if let Some(log_callback) = $crate::ffi::g_cubeb_log_callback {
                    let cstr = ::std::ffi::CString::new(concat!("%s:%d: ", $msg, "\n")).unwrap();
                    log_callback(cstr.as_ptr(), file!(), line!());
                }
            }
        }
    };
    ($level: expr, $fmt: expr, $($arg:tt)+) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                if let Some(log_callback) = $crate::ffi::g_cubeb_log_callback {
                    let cstr = ::std::ffi::CString::new(concat!("%s:%d: ", $fmt, "\n")).unwrap();
                    log_callback(cstr.as_ptr(), file!(), line!(), $($arg)+);
                }
            }
        }
    }
}

#[macro_export]
macro_rules! cubeb_logv {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Verbose, $msg));
    ($fmt: expr, $($arg: tt)+) => (cubeb_log_internal!($crate::LogLevel::Verbose, $fmt, $($arg)*));
}

#[macro_export]
macro_rules! cubeb_log {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Normal, $msg));
    ($fmt: expr, $($arg: tt)+) => (cubeb_log_internal!($crate::LogLevel::Normal, $fmt, $($arg)*));
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_normal_logging() {
        cubeb_log!("This is log at normal level");
        cubeb_log!("Formatted log %d", 1);
    }

    #[test]
    fn test_verbose_logging() {
        cubeb_logv!("This is a log at verbose level");
        cubeb_logv!("Formatted log %d", 1);
    }
}
<commit_msg>cubeb-api: Fix cubeb_log! and cubeb_logv!<commit_after>// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

#[macro_export]
macro_rules! cubeb_log_internal {
    ($level: expr, $msg: expr) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                cubeb_log_internal!(__INTERNAL__ $msg);
            }
        }
    };
    ($level: expr, $fmt: expr, $($arg: expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            if $level <= $crate::ffi::g_cubeb_log_level.into() {
                cubeb_log_internal!(__INTERNAL__ format!($fmt, $($arg),*));
            }
        }
    };
    (__INTERNAL__ $msg: expr) => {
        if let Some(log_callback) = $crate::ffi::g_cubeb_log_callback {
            let cstr = ::std::ffi::CString::new(format!("{}:{}: {}\n", file!(), line!(), $msg)).unwrap();
            log_callback(cstr.as_ptr());
        }
    }
}

#[macro_export]
macro_rules! cubeb_logv {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Verbose, $msg));
    ($fmt: expr, $($arg: expr),+) => (cubeb_log_internal!($crate::LogLevel::Verbose, $fmt, $($arg),*));
}

#[macro_export]
macro_rules! cubeb_log {
    ($msg: expr) => (cubeb_log_internal!($crate::LogLevel::Normal, $msg));
    ($fmt: expr, $($arg: expr),+) => (cubeb_log_internal!($crate::LogLevel::Normal, $fmt, $($arg),*));
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_normal_logging() {
        cubeb_log!("This is log at normal level");
        cubeb_log!("{} Formatted log", 1);
        cubeb_log!("{} Formatted {} log {}", 1, 2, 3);
    }

    #[test]
    fn test_verbose_logging() {
        cubeb_logv!("This is a log at verbose level");
        cubeb_logv!("{} Formatted log", 1);
        cubeb_logv!("{} Formatted {} log {}", 1, 2, 3);
    }
}
<|endoftext|>


<commit_before>use std::default::Default;

use ast::Expr;
use ast::ExprType::*;
use ast::Function;
use ast::Statement;
use ast::StatementType::*;
use ast::visit::Visitor;
use ast::visit::walk_expr;

use error::ErrorCode;
use error::ParseError;

use lexer::position::Position;
use self::leave::{Leave, ReturnState};
use self::init::InitVars;

mod init;
mod leave;

pub struct ReturnCheck<'a> {
    errors: Vec<ParseError>,

    initialized_vars: InitVars<usize>,
    fct: Option<&'a Function>,
}

impl<'a> ReturnCheck<'a> {
    pub fn new() -> ReturnCheck<'a> {
        ReturnCheck {
            errors: Vec::new(),
            initialized_vars: InitVars::new(),
            fct: None,
        }
    }

    pub fn errors(self) -> Vec<ParseError> {
        self.errors
    }

    fn reset_fct(&mut self, fct: &Function) {
        // reset initialized vars with each function
        self.initialized_vars.reset();

        // parameters are always initialized
        for i in &fct.params {
            self.initialized_vars.insert(*i);
        }
    }

    fn check_block(&mut self, stmts: &Vec<Box<Statement>>) -> ReturnState {
        let mut leave = ReturnState::new();

        if stmts.len() == 0 {
            return leave;
        }

        for stmt in stmts {
            if leave.stops {
                self.errors.push(ParseError {
                    position: stmt.position,
                    code: ErrorCode::UnreachableCode,
                    message: format!("statement unreachable")
                });

                return leave;
            }

            leave.seq(self.visit_stmt(stmt));
        }

        leave
    }

    fn check_while(&mut self, cond: &Expr, block: &Statement) -> ReturnState {
        self.visit_expr(cond);

        self.initialized_vars.push();
        let ret = self.visit_stmt(block);
        self.initialized_vars.pop();

        ReturnState::for_while(ret)
    }

    fn check_if(&mut self, cond: &Expr, tblock: &Statement, eblock: &Statement) -> ReturnState {
        self.visit_expr(cond);

        self.initialized_vars.push();
        let tblock = self.visit_stmt(tblock);
        let vars_then = self.initialized_vars.pop();

        self.initialized_vars.push();
        let eblock = if let Some(eblock) = eblock.as_ref() {
            self.visit_stmt(eblock)
        } else {
            ReturnState::new()
        };
        let vars_else = self.initialized_vars.pop();

        let union = vars_then.intersection(&vars_else).cloned().collect();
        self.initialized_vars.push_hash(union);
        tblock.merge(eblock)
    }

    fn check_var(&mut self, varind: usize, expr: &Expr) -> ReturnState {
        if let Some(expr) = expr.as_ref() {
            self.visit_expr(expr);
            self.initialized_vars.insert(varind);
        }

        ReturnState::new()
    }
}

fn end_position(s: &Statement) -> Position {
    match s.stmt {
        Block(ref stmts) if stmts.len() > 0 => {
            stmts[stmts.len()-1].position
        }

        _ => s.position
    }
}

impl<'a> Visitor<'a> for ReturnCheck<'a> {
    type Returns = ReturnState;

    fn visit_fct(&mut self, fct: &'a Function) -> ReturnState {
        self.fct = Some(fct);

        // reset initialized variables for each function
        self.reset_fct(fct);

        let leave = self.visit_stmt(&fct.block);

        if !fct.return_type.is_unit() && leave.returns != Leave::Fix {
            self.errors.push(ParseError {
                position: end_position(&fct.block),
                code: ErrorCode::NoReturnValue,
                message: format!("function `{}` does not return a value in all code paths", fct.name)
            })
        }

        leave
    }

    fn visit_stmt(&mut self, s: &Statement) -> ReturnState {
        match s.stmt {
            Var(varind, _, ref expr) => self.check_var(varind, expr),

            If(ref cond, ref tblock, ref eblock) => self.check_state(cond, tblock, eblock),
            Block(ref stmts) => self.check_block(stmts),

            While(ref cond, ref block) => self.check_while(cond, block),
            Loop(ref block) => ReturnState::for_loop(self.visit_stmt(block)),

            Return(ref expr) => {
                if let Some(expr) = expr.as_ref() {
                    self.visit_expr(expr);
                }

                ReturnState::returns()
            }

            ExprStmt(ref expr) => {
                self.visit_expr(expr);

                ReturnState::new()
            }

            Break => ReturnState::breaks(),
            Continue => ReturnState::continues(),

            _ => ReturnState::new()
        }
    }

    fn visit_expr(&mut self, e: &Expr) -> ReturnState {
        match e.expr {
            Assign(ref var, ref expr) => {
                self.visit_expr(expr);

                match var.expr {
                    Ident(varind) => {
                        self.initialized_vars.insert(varind);
                    }

                    _ => unreachable!()
                }

                Default::default()
            }

            Ident(varind) => {
                if !self.initialized_vars.contains(&varind) {
                    let fct = self.fct.unwrap();
                    let var = &fct.vars[varind];

                    self.errors.push(ParseError {
                        position: e.position,
                        code: ErrorCode::UninitializedVar,
                        message: format!("variable `{}` might not be initialized", var.name)
                    });
                }

                Default::default()
            }

            _ => walk_expr(self, e)
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::Function;

    use error::ErrorCode;
    use parser::Parser;

    fn parse(code: &'static str) -> Function {
        let mut prog = match Parser::from_str(code).parse() {
            Ok(prog) => prog,
            Err(err) => panic!("`{}` throws `{}` but no error expected", code, err),
        };

        prog.functions.swap_remove(0)
    }

    fn err(code: &'static str, error_code: ErrorCode, line: u32, col: u32) {
        let err = match Parser::from_str(code).parse() {
            Ok(_) => panic!("no error found in `{}`, expected {:?} at {}:{}",
                            code, error_code, line, col),
            Err(err) => err,
        };

        assert_eq!(error_code, err.code);
        assert_eq!(line, err.position.line);
        assert_eq!(col, err.position.column);
    }

    #[test]
    fn check_initialized() {
        parse("fn f(a: int) { a; }");
        parse("fn f { var a = 3; a; }");
        parse("fn f { var a : int; a = 3; a; }");

        err("fn f { var a : int; a; }", ErrorCode::UninitializedVar, 1, 21);
        err("fn f -> int { var a : int; return a; }", ErrorCode::UninitializedVar, 1, 35);

        parse("fn f { var a : int; if true { a = 1; } else { a = 2; } a; }");
        err("fn f { var a : int; if true {} else { a = 2; } a; }", ErrorCode::UninitializedVar, 1, 48);
        err("fn f { var a : int; if true { a = 1; } else {} a; }", ErrorCode::UninitializedVar, 1, 48);

        err("fn f { var a : bool; while a {} }", ErrorCode::UninitializedVar, 1, 28);
        err("fn f { var a : int; while true { a = 1; } a; }", ErrorCode::UninitializedVar, 1, 43);
    }

    #[test]
    fn check_return() {
        err("fn f -> int { 1; }", ErrorCode::NoReturnValue, 1, 15);
        err("fn f -> int {}", ErrorCode::NoReturnValue, 1, 13);
        err("fn f -> int { return 1; 1; }", ErrorCode::UnreachableCode, 1, 25);
        err("fn f { return; 1; }", ErrorCode::UnreachableCode, 1, 16);

        parse("fn f -> int { return 1; }");
        parse("fn f { return; }");
        parse("fn f { 1; }");
        parse("fn f {}");

        parse("fn f -> int { while true { return 1; } }");
        err("fn f -> int { while true { return 1; } return 1; }", ErrorCode::UnreachableCode, 1, 40);

        parse("fn f { while true { break; } return; }");
        parse("fn f { while true { continue; } return; }");

        parse("fn f->int {\
               if true { return 1; }\
               else { return 2; } }");
        err("fn f->int {\
             if true { return 1; } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { return 2; }\
             return 3; }",
           ErrorCode::UnreachableCode, 1, 52);
    }

    #[test]
    fn check_break() {
        parse("fn x { while true { break; } return; }");
        parse("fn x { loop { break; } return; }");

        parse("fn x { loop { loop { break; } break; } }");
        parse("fn x { while true { while true { break; } break; } }");

        parse("fn x { loop { if true { break; } break; } }");
        parse("fn x { while true { if true { break; } break; } }");

        err("fn x { loop { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 50);
        err("fn x { while true { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 56);

        err("fn x { while true { break; return; } }", ErrorCode::UnreachableCode, 1, 28);
        err("fn x { loop { break; return; } }", ErrorCode::UnreachableCode, 1, 22);

        err("fn x { break; }", ErrorCode::MisplacedBreak, 1, 8);
        err("fn x { if true { break; } }", ErrorCode::MisplacedBreak, 1, 18);
        err("fn x { loop { if true { break; } else { return; } break; } }",
            ErrorCode::UnreachableCode, 1, 51);
    }

    #[test]
    fn check_continue() {
        parse("fn x { while true { continue; } return; }");
        err("fn x { loop { continue; } return; }",
           ErrorCode::UnreachableCode, 1, 27);

        parse("fn x { while true { while true { continue; } continue; } }");
        err("fn x { loop { loop { continue; } continue; } }",
           ErrorCode::UnreachableCode, 1, 34);

        parse("fn x { while true { if true { continue; } continue; } }");
        parse("fn x { loop { if true { continue; } continue; } }");

        err("fn x { loop { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 56);
        err("fn x { while true { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 62);

        err("fn x { while true { continue; return; } }", ErrorCode::UnreachableCode, 1, 31);
        err("fn x { loop { continue; return; } }", ErrorCode::UnreachableCode, 1, 25);

        err("fn x { continue; }", ErrorCode::MisplacedContinue, 1, 8);
        err("fn x { if true { continue; } }", ErrorCode::MisplacedContinue, 1, 18);
        err("fn x { loop { if true { continue; } else { return; } continue; } }",
            ErrorCode::UnreachableCode, 1, 54);
    }
}
<commit_msg>fixed syntax errors<commit_after>use std::default::Default;

use ast::Expr;
use ast::ExprType::*;
use ast::Function;
use ast::Statement;
use ast::StatementType::*;
use ast::visit::Visitor;
use ast::visit::walk_expr;

use error::ErrorCode;
use error::ParseError;

use lexer::position::Position;
use self::leave::{Leave, ReturnState};
use self::init::InitVars;

mod init;
mod leave;

pub struct ReturnCheck<'a> {
    errors: Vec<ParseError>,

    initialized_vars: InitVars<usize>,
    fct: Option<&'a Function>,
}

impl<'a> ReturnCheck<'a> {
    pub fn new() -> ReturnCheck<'a> {
        ReturnCheck {
            errors: Vec::new(),
            initialized_vars: InitVars::new(),
            fct: None,
        }
    }

    pub fn errors(self) -> Vec<ParseError> {
        self.errors
    }

    fn reset_fct(&mut self, fct: &Function) {
        // reset initialized vars with each function
        self.initialized_vars.reset();

        // parameters are always initialized
        for i in &fct.params {
            self.initialized_vars.insert(*i);
        }
    }

    fn check_block(&mut self, stmts: &Vec<Box<Statement>>) -> ReturnState {
        let mut leave = ReturnState::new();

        if stmts.len() == 0 {
            return leave;
        }

        for stmt in stmts {
            if leave.stops {
                self.errors.push(ParseError {
                    position: stmt.position,
                    code: ErrorCode::UnreachableCode,
                    message: format!("statement unreachable")
                });

                return leave;
            }

            leave.seq(self.visit_stmt(stmt));
        }

        leave
    }

    fn check_while(&mut self, cond: &Expr, block: &Statement) -> ReturnState {
        self.visit_expr(cond);

        self.initialized_vars.push();
        let ret = self.visit_stmt(block);
        self.initialized_vars.pop();

        ReturnState::for_while(ret)
    }

    fn check_if(&mut self, cond: &Expr, tblock: &Statement, eblock: &Option<Box<Statement>>) -> ReturnState {
        self.visit_expr(cond);

        self.initialized_vars.push();
        let tblock = self.visit_stmt(tblock);
        let vars_then = self.initialized_vars.pop();

        self.initialized_vars.push();
        let eblock = if let Some(eblock) = eblock.as_ref() {
            self.visit_stmt(eblock)
        } else {
            ReturnState::new()
        };
        let vars_else = self.initialized_vars.pop();

        let union = vars_then.intersection(&vars_else).cloned().collect();
        self.initialized_vars.push_hash(union);
        tblock.merge(eblock)
    }

    fn check_var(&mut self, varind: usize, expr: &Option<Box<Expr>>) -> ReturnState {
        if let Some(expr) = expr.as_ref() {
            self.visit_expr(expr);
            self.initialized_vars.insert(varind);
        }

        ReturnState::new()
    }
}

fn end_position(s: &Statement) -> Position {
    match s.stmt {
        Block(ref stmts) if stmts.len() > 0 => {
            stmts[stmts.len()-1].position
        }

        _ => s.position
    }
}

impl<'a> Visitor<'a> for ReturnCheck<'a> {
    type Returns = ReturnState;

    fn visit_fct(&mut self, fct: &'a Function) -> ReturnState {
        self.fct = Some(fct);

        // reset initialized variables for each function
        self.reset_fct(fct);

        let leave = self.visit_stmt(&fct.block);

        if !fct.return_type.is_unit() && leave.returns != Leave::Fix {
            self.errors.push(ParseError {
                position: end_position(&fct.block),
                code: ErrorCode::NoReturnValue,
                message: format!("function `{}` does not return a value in all code paths", fct.name)
            })
        }

        leave
    }

    fn visit_stmt(&mut self, s: &Statement) -> ReturnState {
        match s.stmt {
            Var(varind, _, ref expr) => self.check_var(varind, expr),

            If(ref cond, ref tblock, ref eblock) => self.check_if(cond, tblock, eblock),
            Block(ref stmts) => self.check_block(stmts),

            While(ref cond, ref block) => self.check_while(cond, block),
            Loop(ref block) => ReturnState::for_loop(self.visit_stmt(block)),

            Return(ref expr) => {
                if let Some(expr) = expr.as_ref() {
                    self.visit_expr(expr);
                }

                ReturnState::returns()
            }

            ExprStmt(ref expr) => {
                self.visit_expr(expr);

                ReturnState::new()
            }

            Break => ReturnState::breaks(),
            Continue => ReturnState::continues(),

            _ => ReturnState::new()
        }
    }

    fn visit_expr(&mut self, e: &Expr) -> ReturnState {
        match e.expr {
            Assign(ref var, ref expr) => {
                self.visit_expr(expr);

                match var.expr {
                    Ident(varind) => {
                        self.initialized_vars.insert(varind);
                    }

                    _ => unreachable!()
                }

                Default::default()
            }

            Ident(varind) => {
                if !self.initialized_vars.contains(&varind) {
                    let fct = self.fct.unwrap();
                    let var = &fct.vars[varind];

                    self.errors.push(ParseError {
                        position: e.position,
                        code: ErrorCode::UninitializedVar,
                        message: format!("variable `{}` might not be initialized", var.name)
                    });
                }

                Default::default()
            }

            _ => walk_expr(self, e)
        }
    }
}

#[cfg(test)]
mod tests {
    use ast::Function;

    use error::ErrorCode;
    use parser::Parser;

    fn parse(code: &'static str) -> Function {
        let mut prog = match Parser::from_str(code).parse() {
            Ok(prog) => prog,
            Err(err) => panic!("`{}` throws `{}` but no error expected", code, err),
        };

        prog.functions.swap_remove(0)
    }

    fn err(code: &'static str, error_code: ErrorCode, line: u32, col: u32) {
        let err = match Parser::from_str(code).parse() {
            Ok(_) => panic!("no error found in `{}`, expected {:?} at {}:{}",
                            code, error_code, line, col),
            Err(err) => err,
        };

        assert_eq!(error_code, err.code);
        assert_eq!(line, err.position.line);
        assert_eq!(col, err.position.column);
    }

    #[test]
    fn check_initialized() {
        parse("fn f(a: int) { a; }");
        parse("fn f { var a = 3; a; }");
        parse("fn f { var a : int; a = 3; a; }");

        err("fn f { var a : int; a; }", ErrorCode::UninitializedVar, 1, 21);
        err("fn f -> int { var a : int; return a; }", ErrorCode::UninitializedVar, 1, 35);

        parse("fn f { var a : int; if true { a = 1; } else { a = 2; } a; }");
        err("fn f { var a : int; if true {} else { a = 2; } a; }", ErrorCode::UninitializedVar, 1, 48);
        err("fn f { var a : int; if true { a = 1; } else {} a; }", ErrorCode::UninitializedVar, 1, 48);

        err("fn f { var a : bool; while a {} }", ErrorCode::UninitializedVar, 1, 28);
        err("fn f { var a : int; while true { a = 1; } a; }", ErrorCode::UninitializedVar, 1, 43);
    }

    #[test]
    fn check_return() {
        err("fn f -> int { 1; }", ErrorCode::NoReturnValue, 1, 15);
        err("fn f -> int {}", ErrorCode::NoReturnValue, 1, 13);
        err("fn f -> int { return 1; 1; }", ErrorCode::UnreachableCode, 1, 25);
        err("fn f { return; 1; }", ErrorCode::UnreachableCode, 1, 16);

        parse("fn f -> int { return 1; }");
        parse("fn f { return; }");
        parse("fn f { 1; }");
        parse("fn f {}");

        parse("fn f -> int { while true { return 1; } }");
        err("fn f -> int { while true { return 1; } return 1; }", ErrorCode::UnreachableCode, 1, 40);

        parse("fn f { while true { break; } return; }");
        parse("fn f { while true { continue; } return; }");

        parse("fn f->int {\
               if true { return 1; }\
               else { return 2; } }");
        err("fn f->int {\
             if true { return 1; } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { } }", ErrorCode::NoReturnValue, 1, 12);
        err("fn f->int {\
             if true { return 1; } else { return 2; }\
             return 3; }",
           ErrorCode::UnreachableCode, 1, 52);
    }

    #[test]
    fn check_break() {
        parse("fn x { while true { break; } return; }");
        parse("fn x { loop { break; } return; }");

        parse("fn x { loop { loop { break; } break; } }");
        parse("fn x { while true { while true { break; } break; } }");

        parse("fn x { loop { if true { break; } break; } }");
        parse("fn x { while true { if true { break; } break; } }");

        err("fn x { loop { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 50);
        err("fn x { while true { if true { break; } else { break; } break; } }",
            ErrorCode::UnreachableCode, 1, 56);

        err("fn x { while true { break; return; } }", ErrorCode::UnreachableCode, 1, 28);
        err("fn x { loop { break; return; } }", ErrorCode::UnreachableCode, 1, 22);

        err("fn x { break; }", ErrorCode::MisplacedBreak, 1, 8);
        err("fn x { if true { break; } }", ErrorCode::MisplacedBreak, 1, 18);
        err("fn x { loop { if true { break; } else { return; } break; } }",
            ErrorCode::UnreachableCode, 1, 51);
    }

    #[test]
    fn check_continue() {
        parse("fn x { while true { continue; } return; }");
        err("fn x { loop { continue; } return; }",
           ErrorCode::UnreachableCode, 1, 27);

        parse("fn x { while true { while true { continue; } continue; } }");
        err("fn x { loop { loop { continue; } continue; } }",
           ErrorCode::UnreachableCode, 1, 34);

        parse("fn x { while true { if true { continue; } continue; } }");
        parse("fn x { loop { if true { continue; } continue; } }");

        err("fn x { loop { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 56);
        err("fn x { while true { if true { continue; } else { continue; } continue; } }",
            ErrorCode::UnreachableCode, 1, 62);

        err("fn x { while true { continue; return; } }", ErrorCode::UnreachableCode, 1, 31);
        err("fn x { loop { continue; return; } }", ErrorCode::UnreachableCode, 1, 25);

        err("fn x { continue; }", ErrorCode::MisplacedContinue, 1, 8);
        err("fn x { if true { continue; } }", ErrorCode::MisplacedContinue, 1, 18);
        err("fn x { loop { if true { continue; } else { return; } continue; } }",
            ErrorCode::UnreachableCode, 1, 54);
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<commit_msg>commented out debugging<commit_after>#![feature(test)]
#![feature(alloc)]
#![feature(heap_api)]
#[macro_use]
extern crate adapton ;

// mod AAAzip {
//     fn doit() {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fib, x:x );
//             }
//             memo!(st, fib, x:x )
//     }
//     #[bench]
//     fn bench(b:&mut Bencher) {
//         b.iter(||doit());
//     }
// }

// mod fib {
//     const INPUT_SIZE:u64 = 20;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod rust {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fib (x:u64) -> u64 { test::black_box (
//             match x {
//                 0 => 0,
//                 1 => 1,
//                 x => fib(x-1) + fib(x-2)
//             })
//         }

//         pub fn fib_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fib(x));
//             }
//             test::black_box(fib(x))
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(5 as u64, fib(5));
//         }

//         #[bench]
//         fn bench_fib(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fib_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod adapton {
//         mod fs {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             //use adapton::adapton_state::* ;
//             use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonFromScratch::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }

//         }

//         mod state {
//             extern crate test;
//             use self::test::Bencher;

//             extern crate alloc;
//             use std::rc::Rc;
//             use adapton::adapton_syntax::* ;
//             use adapton::adapton_sigs::* ;
//             use adapton::adapton_state::* ;
//             //use adapton::adapton_fromscratch::* ;
//             use super::super::INPUT_SIZE;
//             use super::super::REPEAT_COUNT;

//             pub fn fib<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//                 match x {
//                     0 => 0,
//                     1 => 1,
//                     x => { memo!(st, fib, x:x-1)
//                            +
//                            memo!(st, fib, x:x-2) }}
//             }

//             pub fn run_fib (x:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 memo!(st, fib, x:x )
//             }

//             pub fn run_fib_repeat (x:u64, n:u64) -> u64 {
//                 let mut st = &mut AdaptonState::new() ;
//                 for _ in 1..(n-1) {
//                     memo!(st, fib, x:x );
//                 }
//                 memo!(st, fib, x:x )
//             }

//             #[test]
//             fn it_works() {
//                 assert_eq!(5 as u64, run_fib(5));
//             }

//             #[bench]
//             fn bench_fib(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib(INPUT_SIZE)));
//             }

//             #[bench]
//             fn bench_fib_repeat(b: &mut Bencher) {
//                 b.iter(|| test::black_box(run_fib_repeat(INPUT_SIZE, REPEAT_COUNT)));
//             }
//         }
//     }
// }

// mod fact {
//     const INPUT_SIZE:u64 = 100;
//     const REPEAT_COUNT:u64 = 100;

//     #[cfg(test)]
//     mod no_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         pub fn fact (x:u64) -> u64 {
//             if x == 0 { 1 } else { test::black_box(x) * fact(x-1) }
//         }

//         pub fn fact_repeat (x:u64, n:u64) -> u64 {
//             for _ in 1..(n-1) {
//                 test::black_box(fact(x));
//             }
//             fact(x)
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }

//     #[cfg(test)]
//     mod pure_caching {
//         use super::INPUT_SIZE;
//         use super::REPEAT_COUNT;

//         extern crate test;
//         use self::test::Bencher;

//         use std::rc::Rc;

//         use adapton::adapton_syntax::* ;
//         use adapton::adapton_sigs::* ;
//         use adapton::adapton_state::* ;

//         pub fn fact<A:Adapton> (st:&mut A, x:u64 ) -> u64 {
//             if x == 0 { 1 } else { x * (memo!(st, fact, x:x-1 )) }
//         }

//         pub fn run_fact (x:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             memo!(st, fact, x:x )
//         }

//         pub fn run_fact_repeat (x:u64, n:u64) -> u64 {
//             let mut st = &mut (AdaptonState::new()) ;
//             for _ in 1..(n-1) {
//                 memo!(st, fact, x:x );
//             }
//             memo!(st, fact, x:x )
//         }

//         #[test]
//         fn it_works() {
//             assert_eq!(120 as u64, run_fact(5));
//         }

//         #[bench]
//         fn bench_fact(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact(INPUT_SIZE)));
//         }

//         #[bench]
//         fn bench_fact_repeat(b: &mut Bencher) {
//             b.iter(|| test::black_box(run_fact_repeat(INPUT_SIZE, REPEAT_COUNT)));
//         }
//     }
// }

mod hourglass {
    //const INPUT_ARRAY:Vec<u64> = vec![2; 64];
    const REPEAT_COUNT:u64 = 100;

    #[cfg(test)]
    mod eager_ids {
        //use super::INPUT_ARRAY;
        use super::REPEAT_COUNT;

        extern crate test;
        use self::test::Bencher;

        use std::rc::Rc;

        use adapton::adapton_syntax::* ;
        use adapton::adapton_sigs::* ;
        use adapton::adapton_fromscratch::* ;

        fn ident<A:Adapton,T>(st:&mut A, x:T) -> T {x}

        fn depend_mult<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) * st.force(y)
        }

        fn depend_add<A:Adapton>(st:&mut A, x: &Art<u64,A::Loc>,y: &Art<u64,A::Loc>) -> u64 {
            st.force(x) + st.force(y)
        }

        pub fn hourglass<A:Adapton> (st:&mut A) -> u64 {
            let cells = vec![2;64];
            let mut nodes = vec![];
            for i in 0..64 {
                nodes.push(thunk!(st, ident, x:cells[i]));
            }
            let mut item_num = 0;
            loop {
                if nodes.len() == 126 { break; }
                let first = nodes[item_num].clone();
                let second = nodes[item_num+1].clone();
                //println!("{} --> {}, {}", nodes.len()-1, item_num, item_num+1);
                //why don't we have lifetime issues here?
                nodes.push(thunk!(st, depend_add, x:&first, y:&second));
                if item_num < 122 { item_num += 2 } else { item_num += 1 }
            }
            let thk = &nodes[nodes.len()-1];
            println!("past checkpoint");
            st.force(thk)
        }

        pub fn run_hourglass () -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            hourglass(st)
        }

        pub fn run_hourglass_repeat (n:u64) -> u64 {
            let mut st = &mut (AdaptonFromScratch::new());
            for _ in 1..(n-1) {
                test::black_box(hourglass(st));
            }
            hourglass(st)
        }

        #[test]
        fn it_works() {
            assert_eq!(2 as u64, run_hourglass());
        }

        #[bench]
        fn bench_hourglass(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass()));
        }

        #[bench]
        fn bench_hourglass_repeat(b: &mut Bencher) {
            b.iter(|| test::black_box(run_hourglass_repeat(REPEAT_COUNT)));
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>owner<commit_after><|endoftext|>


<commit_before>//! Abstractions for segment registers.

use super::model_specific::Msr;
use crate::{PrivilegeLevel, VirtAddr};
use bit_field::BitField;
use core::fmt;
// imports for intra doc links
#[cfg(doc)]
use crate::registers::control::Cr4Flags;

/// An x86 segment
///
/// Segment registers on x86 are 16-bit [`SegmentSelector`]s, which index into
/// the [`GlobalDescriptorTable`](crate::structures::gdt::GlobalDescriptorTable). The
/// corresponding GDT entry is used to
/// configure the segment itself. Note that most segmentation functionality is
/// disabled in 64-bit mode. See the individual segments for more information.
pub trait Segment {
    /// Returns the current value of the segment register.
    fn get_reg() -> SegmentSelector;
    /// Reload the segment register. Depending on the segment, this may also
    /// reconfigure the corresponding segment.
    ///
    /// ## Safety
    ///
    /// This function is unsafe because the caller must ensure that `sel`
    /// is a valid segment descriptor, and that reconfiguring the segment will
    /// not cause undefined behavior.
    unsafe fn set_reg(sel: SegmentSelector);
}

/// An x86 segment which is actually used in 64-bit mode
///
/// While most segments are unused in 64-bit mode, the FS and GS segments are
/// still partially used. Only the 64-bit segment base address is used, and this
/// address can be set via the GDT, or by using the `FSGSBASE` instructions.
pub trait Segment64: Segment {
    /// MSR containing the segment base. This MSR can be used to set the base
    /// when [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is **not** set.
    const BASE: Msr;
    /// Reads the segment base address
    ///
    /// ## Exceptions
    ///
    /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is not set, this instruction will throw a `#UD`.
    fn read_base() -> VirtAddr;
    /// Writes the segment base address
    ///
    /// ## Exceptions
    ///
    /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is not set, this instruction will throw a `#UD`.
    ///
    /// ## Safety
    ///
    /// The caller must ensure that this write operation has no unsafe side
    /// effects, as the segment base address might be in use.
    unsafe fn write_base(base: VirtAddr);
}

/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct SegmentSelector(pub u16);

impl SegmentSelector {
    /// Creates a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index`: index in GDT or LDT array (not the offset)
    ///  * `rpl`: the requested privilege level
    #[inline]
    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
        SegmentSelector(index << 3 | (rpl as u16))
    }

    /// Returns the GDT index.
    #[inline]
    pub fn index(self) -> u16 {
        self.0 >> 3
    }

    /// Returns the requested privilege level.
    #[inline]
    pub fn rpl(self) -> PrivilegeLevel {
        PrivilegeLevel::from_u16(self.0.get_bits(0..2))
    }

    /// Set the privilege level for this Segment selector.
    #[inline]
    pub fn set_rpl(&mut self, rpl: PrivilegeLevel) {
        self.0.set_bits(0..2, rpl as u16);
    }
}

impl fmt::Debug for SegmentSelector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("SegmentSelector");
        s.field("index", &self.index());
        s.field("rpl", &self.rpl());
        s.finish()
    }
}

/// Code Segment
///
/// Most fields like the segment base and limit are unused in 64-bit mode.
/// Only the LONG_MODE, PRESENT, USER_SEGMENT, EXECUTABLE, DEFAULT_SIZE (default operand size)
/// and DPL_RING_3 (descriptor privilege-level) fields of the
/// descriptor are recognized by the CPU. Some of them (e.g. DEFAULT_SIZE) are required to hold
/// a specific value and can't be changed. Others like the DPL_RING_3 and LONG_MODE
/// can be used to change privilege level or enable/disable long mode.
#[derive(Debug)]
pub struct CS;

/// Stack Segment
///
/// Entirely unused in 64-bit mode; setting the segment register does nothing.
/// However, in ring 3, the SS register still has to point to a valid
/// [`Descriptor`](crate::structures::gdt::Descriptor) (it cannot be zero). This
/// means a user-mode read/write segment descriptor must be present in the GDT.
///
/// This register is also set by the `syscall`/`sysret` and
/// `sysenter`/`sysexit` instructions (even on 64-bit transitions). This is to
/// maintain symmetry with 32-bit transitions where setting SS actually will
/// actually have an effect.
#[derive(Debug)]
pub struct SS;

/// Data Segment
///
/// Entirely unused in 64-bit mode; setting the segment register does nothing.
#[derive(Debug)]
pub struct DS;

/// ES Segment
///
/// Entirely unused in 64-bit mode; setting the segment register does nothing.
#[derive(Debug)]
pub struct ES;

/// FS Segment
///
/// Only base is used in 64-bit mode, see [`Segment64`]. This is often used in
/// user-mode for Thread-Local Storage (TLS).
#[derive(Debug)]
pub struct FS;

/// GS Segment
///
/// Only base is used in 64-bit mode, see [`Segment64`]. In kernel-mode, the GS
/// base often points to a per-cpu kernel data structure.
#[derive(Debug)]
pub struct GS;
<commit_msg>Update comment and cleanup doc links<commit_after>//! Abstractions for segment registers.

use super::model_specific::Msr;
use crate::{PrivilegeLevel, VirtAddr};
use bit_field::BitField;
use core::fmt;
// imports for intra doc links
#[cfg(doc)]
use crate::{
    registers::control::Cr4Flags,
    structures::gdt::{Descriptor, DescriptorFlags, GlobalDescriptorTable},
};

/// An x86 segment
///
/// Segment registers on x86 are 16-bit [`SegmentSelector`]s, which index into
/// the [`GlobalDescriptorTable`]. The corresponding GDT entry is used to
/// configure the segment itself. Note that most segmentation functionality is
/// disabled in 64-bit mode. See the individual segments for more information.
pub trait Segment {
    /// Returns the current value of the segment register.
    fn get_reg() -> SegmentSelector;
    /// Reload the segment register. Depending on the segment, this may also
    /// reconfigure the corresponding segment.
    ///
    /// ## Safety
    ///
    /// This function is unsafe because the caller must ensure that `sel`
    /// is a valid segment descriptor, and that reconfiguring the segment will
    /// not cause undefined behavior.
    unsafe fn set_reg(sel: SegmentSelector);
}

/// An x86 segment which is actually used in 64-bit mode
///
/// While most segments are unused in 64-bit mode, the FS and GS segments are
/// still partially used. Only the 64-bit segment base address is used, and this
/// address can be set via the GDT, or by using the `FSGSBASE` instructions.
pub trait Segment64: Segment {
    /// MSR containing the segment base. This MSR can be used to set the base
    /// when [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is **not** set.
    const BASE: Msr;
    /// Reads the segment base address
    ///
    /// ## Exceptions
    ///
    /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is not set, this instruction will throw a `#UD`.
    fn read_base() -> VirtAddr;
    /// Writes the segment base address
    ///
    /// ## Exceptions
    ///
    /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is not set, this instruction will throw a `#UD`.
    ///
    /// ## Safety
    ///
    /// The caller must ensure that this write operation has no unsafe side
    /// effects, as the segment base address might be in use.
    unsafe fn write_base(base: VirtAddr);
}

/// Specifies which element to load into a segment from
/// descriptor tables (i.e., is a index to LDT or GDT table
/// with some additional flags).
///
/// See Intel 3a, Section 3.4.2 "Segment Selectors"
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct SegmentSelector(pub u16);

impl SegmentSelector {
    /// Creates a new SegmentSelector
    ///
    /// # Arguments
    ///  * `index`: index in GDT or LDT array (not the offset)
    ///  * `rpl`: the requested privilege level
    #[inline]
    pub const fn new(index: u16, rpl: PrivilegeLevel) -> SegmentSelector {
        SegmentSelector(index << 3 | (rpl as u16))
    }

    /// Returns the GDT index.
    #[inline]
    pub fn index(self) -> u16 {
        self.0 >> 3
    }

    /// Returns the requested privilege level.
    #[inline]
    pub fn rpl(self) -> PrivilegeLevel {
        PrivilegeLevel::from_u16(self.0.get_bits(0..2))
    }

    /// Set the privilege level for this Segment selector.
    #[inline]
    pub fn set_rpl(&mut self, rpl: PrivilegeLevel) {
        self.0.set_bits(0..2, rpl as u16);
    }
}

impl fmt::Debug for SegmentSelector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = f.debug_struct("SegmentSelector");
        s.field("index", &self.index());
        s.field("rpl", &self.rpl());
        s.finish()
    }
}

/// Code Segment
///
/// While most fields in the Code-Segment [`Descriptor`] are unused in 64-bit
/// long mode, some of them must be set to a specific value. The
/// [`EXECUTABLE`](DescriptorFlags::EXECUTABLE),
/// [`USER_SEGMENT`](DescriptorFlags::USER_SEGMENT), and
/// [`LONG_MODE`](DescriptorFlags::LONG_MODE) bits must be set, while the
/// [`DEFAULT_SIZE`](DescriptorFlags::DEFAULT_SIZE) bit must be unset.
///
/// The [`DPL_RING_3`](DescriptorFlags::DPL_RING_3) field can be used to change
/// privilege level. The [`PRESENT`](DescriptorFlags::PRESENT) bit can be used
/// to make a segment present or not present.
///
/// All other fields (like the segment base and limit) are ignored by the
/// processor and setting them has no effect.
#[derive(Debug)]
pub struct CS;

/// Stack Segment
///
/// Entirely unused in 64-bit mode; setting the segment register does nothing.
/// However, in ring 3, the SS register still has to point to a valid
/// [`Descriptor`] (it cannot be zero). This
/// means a user-mode read/write segment descriptor must be present in the GDT.
///
/// This register is also set by the `syscall`/`sysret` and
/// `sysenter`/`sysexit` instructions (even on 64-bit transitions). This is to
/// maintain symmetry with 32-bit transitions where setting SS actually will
/// actually have an effect.
#[derive(Debug)]
pub struct SS;

/// Data Segment
///
/// Entirely unused in 64-bit mode; setting the segment register does nothing.
#[derive(Debug)]
pub struct DS;

/// ES Segment
///
/// Entirely unused in 64-bit mode; setting the segment register does nothing.
#[derive(Debug)]
pub struct ES;

/// FS Segment
///
/// Only base is used in 64-bit mode, see [`Segment64`]. This is often used in
/// user-mode for Thread-Local Storage (TLS).
#[derive(Debug)]
pub struct FS;

/// GS Segment
///
/// Only base is used in 64-bit mode, see [`Segment64`]. In kernel-mode, the GS
/// base often points to a per-cpu kernel data structure.
#[derive(Debug)]
pub struct GS;
<|endoftext|>


<commit_before>extern crate raw_window_handle;

use self::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use crate::{sys::SDL_Window, video::Window};

unsafe impl HasRawWindowHandle for Window {
    #[doc(alias = "SDL_GetVersion")]
    fn raw_window_handle(&self) -> RawWindowHandle {
        use self::SDL_SYSWM_TYPE::*;

        let mut wm_info: SDL_SysWMinfo = unsafe { std::mem::zeroed() };

        // Make certain to retrieve version before querying `SDL_GetWindowWMInfo`
        // as that gives an error on certain systems
        unsafe {
            sys::SDL_GetVersion(&mut wm_info.version);
            if SDL_GetWindowWMInfo(self.raw(), &mut wm_info) == SDL_bool::SDL_FALSE {
                panic!("Couldn't get SDL window info: {}", crate::get_error());
            }
        }

        match wm_info.subsystem {
            #[cfg(target_os = "windows")]
            SDL_SYSWM_WINDOWS => {
                use self::raw_window_handle::Win32Handle;

                let mut handle = Win32Handle::empty();
                handle.hwnd = unsafe { wm_info.info.win }.window as *mut libc::c_void;

                RawWindowHandle::Win32(handle)
            }
            #[cfg(any(
                target_os = "linux",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd",
            ))]
            SDL_SYSWM_WAYLAND => {
                use self::raw_window_handle::WaylandHandle;

                let mut handle = WaylandHandle::empty();
                handle.surface = unsafe { wm_info.info.wl }.surface as *mut libc::c_void;
                handle.display = unsafe { wm_info.info.wl }.display as *mut libc::c_void;

                RawWindowHandle::Wayland(handle)
            }
            #[cfg(any(
                target_os = "linux",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd",
            ))]
            SDL_SYSWM_X11 => {
                use self::raw_window_handle::XlibHandle;

                let mut handle = XlibHandle::empty();
                handle.window = unsafe { wm_info.info.x11 }.window;
                handle.display = unsafe { wm_info.info.x11 }.display as *mut libc::c_void;

                RawWindowHandle::Xlib(handle)
            }
            #[cfg(target_os = "macos")]
            SDL_SYSWM_COCOA => {
                use self::raw_window_handle::AppKitHandle;

                let mut handle = AppKitHandle::empty();
                handle.ns_window = unsafe { wm_info.info.cocoa }.window as *mut libc::c_void;
                handle.ns_view = 0 as *mut libc::c_void; // consumer of RawWindowHandle should determine this

                RawWindowHandle::AppKit(handle)
            }
            #[cfg(any(target_os = "ios"))]
            SDL_SYSWM_UIKIT => {
                use self::raw_window_handle::UiKitHandle;

                let mut handle = UiKitHandle::empty();
                handle.ui_window = unsafe { wm_info.info.uikit }.window as *mut libc::c_void;
                handle.ui_view = 0 as *mut libc::c_void; // consumer of RawWindowHandle should determine this

                RawWindowHandle::UiKit(handle)
            }
            #[cfg(any(target_os = "android"))]
            SDL_SYSWM_ANDROID => {
                use self::raw_window_handle::AndroidNdkHandle;

                let mut handle = AndroidNdkHandle::empty();
                handle.a_native_window =
                    unsafe { wm_info.info.android }.window as *mut libc::c_void;

                RawWindowHandle::AndroidNdk(handle)
            }
            x => {
                let window_system = match x {
                    SDL_SYSWM_DIRECTFB => "DirectFB",
                    SDL_SYSWM_MIR => "Mir",
                    SDL_SYSWM_WINRT => "WinRT",
                    SDL_SYSWM_VIVANTE => "Vivante",
                    _ => unreachable!(),
                };
                panic!("{} window system is not supported, please file issue with raw-window-handle: https://github.com/rust-windowing/raw-window-handle/issues/new", window_system);
            }
        }
    }
}

extern "C" {
    fn SDL_GetWindowWMInfo(window: *mut SDL_Window, info: *mut SDL_SysWMinfo) -> SDL_bool;
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_bool {
    SDL_FALSE = 0,
    SDL_TRUE = 1,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_SYSWM_TYPE {
    SDL_SYSWM_UNKNOWN = 0,
    SDL_SYSWM_WINDOWS = 1,
    SDL_SYSWM_X11 = 2,
    SDL_SYSWM_DIRECTFB = 3,
    SDL_SYSWM_COCOA = 4,
    SDL_SYSWM_UIKIT = 5,
    SDL_SYSWM_WAYLAND = 6,
    SDL_SYSWM_MIR = 7,
    SDL_SYSWM_WINRT = 8,
    SDL_SYSWM_ANDROID = 9,
    SDL_SYSWM_VIVANTE = 10,
    SDL_SYSWM_OS2 = 11,
}

impl Default for SDL_SYSWM_TYPE {
    fn default() -> Self {
        SDL_SYSWM_TYPE::SDL_SYSWM_UNKNOWN
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct SDL_SysWMinfo {
    pub version: sys::SDL_version,
    pub subsystem: SDL_SYSWM_TYPE,

    #[cfg(target_os = "windows")]
    pub info: windows::WindowsSysWMinfo,

    #[cfg(any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    ))]
    pub info: linux::LinuxSysWMinfo,

    #[cfg(target_os = "macos")]
    pub info: macos::MacOSSysWMinfo,

    #[cfg(target_os = "ios")]
    pub info: ios::IOSSysWMinfo,

    #[cfg(target_os = "android")]
    pub info: android::AndroidSysWMinfo,
}

#[cfg(target_os = "windows")]
pub mod windows {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union WindowsSysWMinfo {
        pub win: Handles,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for WindowsSysWMinfo {
        fn default() -> Self {
            WindowsSysWMinfo {
                win: Handles::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct Handles {
        pub window: *mut HWND,
        pub hdc: *mut HDC,
        pub hinstance: *mut HINSTANCE,
    }

    impl Default for Handles {
        fn default() -> Self {
            Handles {
                window: 0 as *mut HWND,
                hdc: 0 as *mut HDC,
                hinstance: 0 as *mut HINSTANCE,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HWND {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HDC {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HINSTANCE {
        pub unused: libc::c_int,
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
))]
pub mod linux {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union LinuxSysWMinfo {
        pub x11: X11Info,
        pub wl: WaylandInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u32; 16usize],
    }

    impl Default for LinuxSysWMinfo {
        fn default() -> Self {
            LinuxSysWMinfo {
                wl: WaylandInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct X11Info {
        pub display: *mut Display,
        pub window: Window,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct WaylandInfo {
        pub display: *mut WLDisplay,
        pub surface: *mut WLSurface,
        pub shell_surface: *mut WLShellSurface,
    }

    impl Default for WaylandInfo {
        fn default() -> Self {
            WaylandInfo {
                display: 0 as *mut WLDisplay,
                surface: 0 as *mut WLSurface,
                shell_surface: 0 as *mut WLShellSurface,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLDisplay {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLShellSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct Display {
        _unused: [u8; 0],
    }

    pub type Window = libc::c_ulong;
}

#[cfg(target_os = "macos")]
pub mod macos {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union MacOSSysWMinfo {
        pub cocoa: CocoaInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for MacOSSysWMinfo {
        fn default() -> Self {
            MacOSSysWMinfo {
                cocoa: CocoaInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct CocoaInfo {
        pub window: *mut NSWindow,
    }

    impl Default for CocoaInfo {
        fn default() -> Self {
            CocoaInfo {
                window: 0 as *mut NSWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct NSWindow {
        _unused: [u8; 0],
    }
}

#[cfg(target_os = "ios")]
pub mod ios {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union IOSSysWMinfo {
        pub uikit: UiKitInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for IOSSysWMinfo {
        fn default() -> Self {
            IOSSysWMinfo {
                uikit: UiKitInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct UiKitInfo {
        pub window: *mut UIWindow,
    }

    impl Default for UiKitInfo {
        fn default() -> Self {
            UiKitInfo {
                window: 0 as *mut UIWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct UIWindow {
        _unused: [u8; 0],
    }
}

#[cfg(target_os = "android")]
pub mod android {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union AndroidSysWMinfo {
        pub android: AndroidInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for AndroidSysWMinfo {
        fn default() -> Self {
            AndroidSysWMinfo {
                android: AndroidInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct AndroidInfo {
        pub window: *mut ANativeWindow,
    }

    impl Default for AndroidInfo {
        fn default() -> Self {
            AndroidInfo {
                window: 0 as *mut ANativeWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct ANativeWindow {
        _unused: [u8; 0],
    }
}
<commit_msg>Implement WinRT support in raw-window-handle<commit_after>extern crate raw_window_handle;

use self::raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use crate::{sys::SDL_Window, video::Window};

unsafe impl HasRawWindowHandle for Window {
    #[doc(alias = "SDL_GetVersion")]
    fn raw_window_handle(&self) -> RawWindowHandle {
        use self::SDL_SYSWM_TYPE::*;

        let mut wm_info: SDL_SysWMinfo = unsafe { std::mem::zeroed() };

        // Make certain to retrieve version before querying `SDL_GetWindowWMInfo`
        // as that gives an error on certain systems
        unsafe {
            sys::SDL_GetVersion(&mut wm_info.version);
            if SDL_GetWindowWMInfo(self.raw(), &mut wm_info) == SDL_bool::SDL_FALSE {
                panic!("Couldn't get SDL window info: {}", crate::get_error());
            }
        }

        match wm_info.subsystem {
            #[cfg(target_os = "windows")]
            SDL_SYSWM_WINDOWS => {
                use self::raw_window_handle::Win32Handle;

                let mut handle = Win32Handle::empty();
                handle.hwnd = unsafe { wm_info.info.win }.window as *mut libc::c_void;

                RawWindowHandle::Win32(handle)
            }
            #[cfg(target_os = "windows")]
            SDL_SYSWM_WINRT => {
                use self::raw_window_handle::WinRtHandle;

                let mut handle = WinRtHandle::empty();
                handle.core_window = unsafe { wm_info.info.winrt }.core_window;

                RawWindowHandle::WinRt(handle)
            }
            #[cfg(any(
                target_os = "linux",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd",
            ))]
            SDL_SYSWM_WAYLAND => {
                use self::raw_window_handle::WaylandHandle;

                let mut handle = WaylandHandle::empty();
                handle.surface = unsafe { wm_info.info.wl }.surface as *mut libc::c_void;
                handle.display = unsafe { wm_info.info.wl }.display as *mut libc::c_void;

                RawWindowHandle::Wayland(handle)
            }
            #[cfg(any(
                target_os = "linux",
                target_os = "dragonfly",
                target_os = "freebsd",
                target_os = "netbsd",
                target_os = "openbsd",
            ))]
            SDL_SYSWM_X11 => {
                use self::raw_window_handle::XlibHandle;

                let mut handle = XlibHandle::empty();
                handle.window = unsafe { wm_info.info.x11 }.window;
                handle.display = unsafe { wm_info.info.x11 }.display as *mut libc::c_void;

                RawWindowHandle::Xlib(handle)
            }
            #[cfg(target_os = "macos")]
            SDL_SYSWM_COCOA => {
                use self::raw_window_handle::AppKitHandle;

                let mut handle = AppKitHandle::empty();
                handle.ns_window = unsafe { wm_info.info.cocoa }.window as *mut libc::c_void;
                handle.ns_view = 0 as *mut libc::c_void; // consumer of RawWindowHandle should determine this

                RawWindowHandle::AppKit(handle)
            }
            #[cfg(any(target_os = "ios"))]
            SDL_SYSWM_UIKIT => {
                use self::raw_window_handle::UiKitHandle;

                let mut handle = UiKitHandle::empty();
                handle.ui_window = unsafe { wm_info.info.uikit }.window as *mut libc::c_void;
                handle.ui_view = 0 as *mut libc::c_void; // consumer of RawWindowHandle should determine this

                RawWindowHandle::UiKit(handle)
            }
            #[cfg(any(target_os = "android"))]
            SDL_SYSWM_ANDROID => {
                use self::raw_window_handle::AndroidNdkHandle;

                let mut handle = AndroidNdkHandle::empty();
                handle.a_native_window =
                    unsafe { wm_info.info.android }.window as *mut libc::c_void;

                RawWindowHandle::AndroidNdk(handle)
            }
            x => {
                let window_system = match x {
                    SDL_SYSWM_DIRECTFB => "DirectFB",
                    SDL_SYSWM_MIR => "Mir",
                    SDL_SYSWM_VIVANTE => "Vivante",
                    _ => unreachable!(),
                };
                panic!("{} window system is not supported, please file issue with raw-window-handle: https://github.com/rust-windowing/raw-window-handle/issues/new", window_system);
            }
        }
    }
}

extern "C" {
    fn SDL_GetWindowWMInfo(window: *mut SDL_Window, info: *mut SDL_SysWMinfo) -> SDL_bool;
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_bool {
    SDL_FALSE = 0,
    SDL_TRUE = 1,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[allow(non_camel_case_types, dead_code)]
pub enum SDL_SYSWM_TYPE {
    SDL_SYSWM_UNKNOWN = 0,
    SDL_SYSWM_WINDOWS = 1,
    SDL_SYSWM_X11 = 2,
    SDL_SYSWM_DIRECTFB = 3,
    SDL_SYSWM_COCOA = 4,
    SDL_SYSWM_UIKIT = 5,
    SDL_SYSWM_WAYLAND = 6,
    SDL_SYSWM_MIR = 7,
    SDL_SYSWM_WINRT = 8,
    SDL_SYSWM_ANDROID = 9,
    SDL_SYSWM_VIVANTE = 10,
    SDL_SYSWM_OS2 = 11,
}

impl Default for SDL_SYSWM_TYPE {
    fn default() -> Self {
        SDL_SYSWM_TYPE::SDL_SYSWM_UNKNOWN
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub struct SDL_SysWMinfo {
    pub version: sys::SDL_version,
    pub subsystem: SDL_SYSWM_TYPE,

    #[cfg(target_os = "windows")]
    pub info: windows::WindowsSysWMinfo,

    #[cfg(any(
        target_os = "linux",
        target_os = "dragonfly",
        target_os = "freebsd",
        target_os = "netbsd",
        target_os = "openbsd",
    ))]
    pub info: linux::LinuxSysWMinfo,

    #[cfg(target_os = "macos")]
    pub info: macos::MacOSSysWMinfo,

    #[cfg(target_os = "ios")]
    pub info: ios::IOSSysWMinfo,

    #[cfg(target_os = "android")]
    pub info: android::AndroidSysWMinfo,
}

#[cfg(target_os = "windows")]
pub mod windows {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union WindowsSysWMinfo {
        pub win: Win32Handles,
        pub winrt: WinRtHandles,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for WindowsSysWMinfo {
        fn default() -> Self {
            WindowsSysWMinfo {
                win: Win32Handles::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct Win32Handles {
        pub window: *mut HWND,
        pub hdc: *mut HDC,
        pub hinstance: *mut HINSTANCE,
    }

    impl Default for Win32Handles {
        fn default() -> Self {
            Win32Handles {
                window: 0 as *mut HWND,
                hdc: 0 as *mut HDC,
                hinstance: 0 as *mut HINSTANCE,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HWND {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HDC {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct HINSTANCE {
        pub unused: libc::c_int,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct WinRtHandles {
        pub core_window: *mut core::ffi::c_void,
    }

    impl Default for WinRtHandles {
        fn default() -> Self {
            WinRtHandles {
                core_window: core::ptr::null_mut(),
            }
        }
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "dragonfly",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
))]
pub mod linux {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union LinuxSysWMinfo {
        pub x11: X11Info,
        pub wl: WaylandInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u32; 16usize],
    }

    impl Default for LinuxSysWMinfo {
        fn default() -> Self {
            LinuxSysWMinfo {
                wl: WaylandInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct X11Info {
        pub display: *mut Display,
        pub window: Window,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct WaylandInfo {
        pub display: *mut WLDisplay,
        pub surface: *mut WLSurface,
        pub shell_surface: *mut WLShellSurface,
    }

    impl Default for WaylandInfo {
        fn default() -> Self {
            WaylandInfo {
                display: 0 as *mut WLDisplay,
                surface: 0 as *mut WLSurface,
                shell_surface: 0 as *mut WLShellSurface,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLDisplay {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone, PartialEq)]
    pub struct WLShellSurface {
        pub _address: u8,
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct Display {
        _unused: [u8; 0],
    }

    pub type Window = libc::c_ulong;
}

#[cfg(target_os = "macos")]
pub mod macos {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union MacOSSysWMinfo {
        pub cocoa: CocoaInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for MacOSSysWMinfo {
        fn default() -> Self {
            MacOSSysWMinfo {
                cocoa: CocoaInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct CocoaInfo {
        pub window: *mut NSWindow,
    }

    impl Default for CocoaInfo {
        fn default() -> Self {
            CocoaInfo {
                window: 0 as *mut NSWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct NSWindow {
        _unused: [u8; 0],
    }
}

#[cfg(target_os = "ios")]
pub mod ios {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union IOSSysWMinfo {
        pub uikit: UiKitInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for IOSSysWMinfo {
        fn default() -> Self {
            IOSSysWMinfo {
                uikit: UiKitInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct UiKitInfo {
        pub window: *mut UIWindow,
    }

    impl Default for UiKitInfo {
        fn default() -> Self {
            UiKitInfo {
                window: 0 as *mut UIWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct UIWindow {
        _unused: [u8; 0],
    }
}

#[cfg(target_os = "android")]
pub mod android {
    #[repr(C)]
    #[derive(Copy, Clone)]
    pub union AndroidSysWMinfo {
        pub android: AndroidInfo,
        pub dummy: [u8; 64usize],
        _bindgen_union_align: [u64; 8usize],
    }

    impl Default for AndroidSysWMinfo {
        fn default() -> Self {
            AndroidSysWMinfo {
                android: AndroidInfo::default(),
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone, PartialEq)]
    pub struct AndroidInfo {
        pub window: *mut ANativeWindow,
    }

    impl Default for AndroidInfo {
        fn default() -> Self {
            AndroidInfo {
                window: 0 as *mut ANativeWindow,
            }
        }
    }

    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct ANativeWindow {
        _unused: [u8; 0],
    }
}
<|endoftext|>