<commit_before>use ra_syntax::{
    ast::{self, AstNode},
    SyntaxKind::WHITESPACE,
    SyntaxNode, TextUnit,
};

use crate::assists::{AssistCtx, Assist};

pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
    let node = ctx.covering_node();
    let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;

    let anchor_stmt = anchor_stmt(expr)?;
    let indent = anchor_stmt.prev_sibling()?;
    if indent.kind() != WHITESPACE {
        return None;
    }
    ctx.build("introduce variable", move |edit| {
        let mut buf = String::new();

        buf.push_str("let var_name = ");
        expr.syntax().text().push_to(&mut buf);
        let is_full_stmt = if let Some(expr_stmt) = ast::ExprStmt::cast(anchor_stmt) {
            Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
        } else {
            false
        };
        if is_full_stmt {
            edit.replace(expr.syntax().range(), buf);
        } else {
            buf.push_str(";");
            indent.text().push_to(&mut buf);
            edit.replace(expr.syntax().range(), "var_name".to_string());
            edit.insert(anchor_stmt.range().start(), buf);
        }
        edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let "));
    })
}

/// Statement or last in the block expression, which will follow
/// the freshly introduced var.
fn anchor_stmt(expr: &ast::Expr) -> Option<&SyntaxNode> {
    expr.syntax().ancestors().find(|&node| {
        if ast::Stmt::cast(node).is_some() {
            return true;
        }
        if let Some(expr) = node
            .parent()
            .and_then(ast::Block::cast)
            .and_then(|it| it.expr())
        {
            if expr.syntax() == node {
                return true;
            }
        }
        false
    })
}

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

    #[test]
    fn test_introduce_var_simple() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    foo(<|>1 + 1<|>);
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    foo(var_name);
}",
        );
    }

    #[test]
    fn test_introduce_var_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1 + 1<|>;
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_part_of_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1<|> + 1;
}",
            "
fn foo() {
    let <|>var_name = 1;
    var_name + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_last_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    bar(<|>1 + 1<|>)
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    bar(var_name)
}",
        );
    }

    #[test]
    fn test_introduce_var_last_full_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>bar(1 + 1)<|>
}",
            "
fn foo() {
    let <|>var_name = bar(1 + 1);
    var_name
}",
        );
    }

    #[test]
    fn test_introduce_var_block_expr_second_to_last() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>{ let x = 0; x }<|>
    something_else();
}",
            "
fn foo() {
    let <|>var_name = { let x = 0; x };
    var_name
    something_else();
}",
        );
    }
}
<commit_msg>we don't need to write var_name after block expr?<commit_after>use ra_syntax::{
    ast::{self, AstNode},
    SyntaxKind::WHITESPACE,
    SyntaxNode, TextUnit,
};

use crate::assists::{AssistCtx, Assist};

pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
    let node = ctx.covering_node();
    let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;

    let anchor_stmt = anchor_stmt(expr)?;
    let indent = anchor_stmt.prev_sibling()?;
    if indent.kind() != WHITESPACE {
        return None;
    }
    ctx.build("introduce variable", move |edit| {
        let mut buf = String::new();

        buf.push_str("let var_name = ");
        expr.syntax().text().push_to(&mut buf);
        let is_full_stmt = if let Some(expr_stmt) = ast::ExprStmt::cast(anchor_stmt) {
            Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
        } else {
            false
        };
        if is_full_stmt {
            edit.replace(expr.syntax().range(), buf);
        } else {
            buf.push_str(";");
            indent.text().push_to(&mut buf);
            edit.replace(expr.syntax().range(), "var_name".to_string());
            edit.insert(anchor_stmt.range().start(), buf);
        }
        edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let "));
    })
}

/// Statement or last in the block expression, which will follow
/// the freshly introduced var.
fn anchor_stmt(expr: &ast::Expr) -> Option<&SyntaxNode> {
    expr.syntax().ancestors().find(|&node| {
        if ast::Stmt::cast(node).is_some() {
            return true;
        }
        if let Some(expr) = node
            .parent()
            .and_then(ast::Block::cast)
            .and_then(|it| it.expr())
        {
            if expr.syntax() == node {
                return true;
            }
        }
        false
    })
}

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

    #[test]
    fn test_introduce_var_simple() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    foo(<|>1 + 1<|>);
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    foo(var_name);
}",
        );
    }

    #[test]
    fn test_introduce_var_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1 + 1<|>;
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_part_of_expr_stmt() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>1<|> + 1;
}",
            "
fn foo() {
    let <|>var_name = 1;
    var_name + 1;
}",
        );
    }

    #[test]
    fn test_introduce_var_last_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    bar(<|>1 + 1<|>)
}",
            "
fn foo() {
    let <|>var_name = 1 + 1;
    bar(var_name)
}",
        );
    }

    #[test]
    fn test_introduce_var_last_full_expr() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>bar(1 + 1)<|>
}",
            "
fn foo() {
    let <|>var_name = bar(1 + 1);
    var_name
}",
        );
    }

    #[test]
    fn test_introduce_var_block_expr_second_to_last() {
        check_assist_range(
            introduce_variable,
            "
fn foo() {
    <|>{ let x = 0; x }<|>
    something_else();
}",
            "
fn foo() {
    let <|>var_name = { let x = 0; x };
    something_else();
}",
        );
    }
}
<|endoftext|>


<commit_before>extern crate quickersort;
extern crate rand;
extern crate itertools;

use quickersort::{sort_by, insertion_sort, heapsort};
use rand::{Rng, weak_rng};
use itertools::Itertools;

macro_rules! do_test_sort(
    ($sortfun:ident) => ({
        let cmp = |a: &usize, b: &usize| a.cmp(b);
        let cmp_rev = |a: &usize, b: &usize| b.cmp(a);
        for len in (4usize .. 250).step(5) {
            for _ in (0isize .. 100) {
                let mut v = weak_rng().gen_iter::<u8>().take(len).map(|x| 10 + (x % 89) as usize)
                                        .collect::<Vec<usize>>();
                let mut v1 = v.clone();

                $sortfun(&mut v[..], &cmp);
                assert!(v.windows(2).all(|w| w[0] <= w[1]));

                $sortfun(&mut v1[..], &cmp);
                assert!(v1.windows(2).all(|w| w[0] <= w[1]));

                $sortfun(&mut v1[..], &cmp_rev);
                assert!(v1.windows(2).all(|w| w[0] >= w[1]));
            }
        }
        // shouldn't fail/crash
        let mut v: [usize; 0] = [];
        $sortfun(&mut v[..], &cmp);

        let mut v = [0xDEADBEEFusize];
        $sortfun(&mut v[..], &cmp);
        assert!(v == [0xDEADBEEF]);
    })
);

#[test]
fn test_introsort() {
    do_test_sort!(sort_by);
}

#[test]
fn test_heapsort() {
    do_test_sort!(heapsort);
}

#[test]
fn test_insertion_sort() {
    do_test_sort!(insertion_sort);
}

<commit_msg>Add a test case for the always-less broken comparator.<commit_after>extern crate quickersort;
extern crate rand;
extern crate itertools;

use quickersort::{sort_by, insertion_sort, heapsort};
use rand::{Rng, weak_rng};
use itertools::Itertools;
use std::cmp::Ordering::{Less, Greater};

macro_rules! do_test_sort(
    ($sortfun:ident) => ({
        let cmp = |a: &usize, b: &usize| a.cmp(b);
        let cmp_rev = |a: &usize, b: &usize| b.cmp(a);
        for len in (4usize .. 250).step(5) {
            for _ in 0isize .. 100 {
                let mut v = weak_rng().gen_iter::<u8>().take(len).map(|x| 10 + (x % 89) as usize)
                                        .collect::<Vec<usize>>();
                let mut v1 = v.clone();

                $sortfun(&mut v[..], &cmp);
                assert!(v.windows(2).all(|w| w[0] <= w[1]));

                $sortfun(&mut v1[..], &cmp);
                assert!(v1.windows(2).all(|w| w[0] <= w[1]));

                $sortfun(&mut v1[..], &cmp_rev);
                assert!(v1.windows(2).all(|w| w[0] >= w[1]));
            }
        }
        // shouldn't fail/crash
        let mut v: [usize; 0] = [];
        $sortfun(&mut v[..], &cmp);

        let mut v = [0xDEADBEEFusize];
        $sortfun(&mut v[..], &cmp);
        assert!(v == [0xDEADBEEF]);
    })
);

#[test]
fn test_introsort() {
    do_test_sort!(sort_by);
}

#[test]
fn test_heapsort() {
    do_test_sort!(heapsort);
}

#[test]
fn test_insertion_sort() {
    do_test_sort!(insertion_sort);
}

#[test]
fn test_always_less() {
    let mut v = vec![];
    for _ in 0 .. 256 {
        v.push(0u8);
    }
    sort_by(&mut v, &|_, _| Less);
}

#[test]
fn test_always_greater() {
    let mut v = vec![];
    for _ in 0 .. 256 {
        v.push(0u8);
    }
    sort_by(&mut v, &|_, _| Greater);
}

<|endoftext|>


<commit_before>extern crate teleborg;

#[cfg(test)]
mod tests {
    use super::*;
    use teleborg::command_handler;
    use teleborg::bot::{Bot, ParseMode};
    use teleborg::objects::update::Update;
    use teleborg::updater;

    #[test]
    fn create_updater() {
        let mut commands = command_handler::CommandHandler::new();
        commands.add("test", test);
        updater::Updater::start(None, None, None, None, commands);
    }

    fn test(bot: &Bot, update: Update) {
        let chat_id = &update.message.unwrap().chat.id;
        let x = bot.send_message(chat_id,
                                 "
Test
",
                                 Some(&ParseMode::Html),
                                 None,
                                 None,
                                 None);
        println!("{:?}", x);
    }
}
<commit_msg>Removing generic test file<commit_after><|endoftext|>


<commit_before>extern crate r2d2;

use std::sync::{Mutex, Arc};
use std::sync::mpsc::{self, SyncSender, Receiver};
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, SeqCst};
use std::default::Default;
use std::thread::Thread;

use r2d2::ErrorHandler;

mod config;

#[derive(Show, PartialEq)]
struct FakeConnection;

struct OkManager;

impl r2d2::PoolManager<FakeConnection, ()> for OkManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        Ok(FakeConnection)
    }

    fn is_valid(&self, _: &mut FakeConnection) -> Result<(), ()> {
        Ok(())
    }

    fn has_broken(&self, _: &mut FakeConnection) -> bool {
        false
    }
}

struct NthConnectFailManager {
    n: Mutex<uint>,
}

impl r2d2::PoolManager<FakeConnection, ()> for NthConnectFailManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        let mut n = self.n.lock().unwrap();
        if *n > 0 {
            *n -= 1;
            Ok(FakeConnection)
        } else {
            Err(())
        }
    }

    fn is_valid(&self, _: &mut FakeConnection) -> Result<(), ()> {
        Ok(())
    }

    fn has_broken(&self, _: &mut FakeConnection) -> bool {
        false
    }
}

#[test]
fn test_pool_size_ok() {
    let config = r2d2::Config {
        pool_size: 5,
        ..Default::default()
    };
    let manager = NthConnectFailManager { n: Mutex::new(5) };
    let pool = r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).unwrap();
    let mut conns = vec![];
    for _ in range(0, config.pool_size) {
        conns.push(pool.get().unwrap());
    }
}

#[test]
fn test_acquire_release() {
    let config = r2d2::Config {
        pool_size: 2,
        ..Default::default()
    };
    let pool = r2d2::Pool::new(config, OkManager, r2d2::NoopErrorHandler).unwrap();

    let conn1 = pool.get().unwrap();
    let conn2 = pool.get().unwrap();
    drop(conn1);
    let conn3 = pool.get().unwrap();
    drop(conn2);
    drop(conn3);
}

#[test]
fn test_is_send_sync() {
    fn is_send_sync<T: Send+Sync>() {}
    is_send_sync::<r2d2::Pool<FakeConnection, (), OkManager, r2d2::NoopErrorHandler>>();
}

#[test]
fn test_issue_2_unlocked_during_is_valid() {
    struct BlockingChecker {
        first: AtomicBool,
        s: Mutex<SyncSender<()>>,
        r: Mutex<Receiver<()>>,
    }

    impl r2d2::PoolManager<FakeConnection, ()> for BlockingChecker {
        fn connect(&self) -> Result<FakeConnection, ()> {
            Ok(FakeConnection)
        }

        fn is_valid(&self, _: &mut FakeConnection) -> Result<(), ()> {
            if self.first.compare_and_swap(true, false, SeqCst) {
                self.s.lock().unwrap().send(()).unwrap();
                self.r.lock().unwrap().recv().unwrap();
            }
            Ok(())
        }

        fn has_broken(&self, _: &mut FakeConnection) -> bool {
            false
        }
    }

    let (s1, r1) = mpsc::sync_channel(0);
    let (s2, r2) = mpsc::sync_channel(0);

    let config = r2d2::Config {
        test_on_check_out: true,
        pool_size: 2,
        ..Default::default()
    };
    let manager = BlockingChecker {
        first: AtomicBool::new(true),
        s: Mutex::new(s1),
        r: Mutex::new(r2),
    };
    let pool = Arc::new(r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).unwrap());

    let p2 = pool.clone();
    let _t = Thread::spawn(move || {
        p2.get().unwrap();
    }).detach();

    r1.recv().unwrap();
    // get call by other task has triggered the health check
    pool.get().unwrap();
    s2.send(()).unwrap();
}

#[test]
fn test_drop_on_broken() {
    static DROPPED: AtomicBool = ATOMIC_BOOL_INIT;
    DROPPED.store(false, SeqCst);

    struct Connection;

    impl Drop for Connection {
        fn drop(&mut self) {
            DROPPED.store(true, SeqCst);
        }
    }

    struct Handler;

    impl r2d2::PoolManager<Connection, ()> for Handler {
        fn connect(&self) -> Result<Connection, ()> {
            Ok(Connection)
        }

        fn is_valid(&self, _: &mut Connection) -> Result<(), ()> {
            Ok(())
        }

        fn has_broken(&self, _: &mut Connection) -> bool {
            true
        }
    }

    let pool = r2d2::Pool::new(Default::default(), Handler, r2d2::NoopErrorHandler).unwrap();

    drop(pool.get().unwrap());

    assert!(DROPPED.load(SeqCst));
}

// Just make sure that a boxed error handler works and doesn't self recurse or anything
#[test]
fn test_boxed_error_handler() {
    let handler: Box<ErrorHandler<()>> = box r2d2::NoopErrorHandler;
    handler.handle_error(());
    r2d2::Pool::new(Default::default(), OkManager, handler).unwrap();
}
<commit_msg>Fix tests<commit_after>extern crate r2d2;

use std::sync::{Mutex, Arc};
use std::sync::mpsc::{self, SyncSender, Receiver};
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use std::default::Default;
use std::thread::Thread;

use r2d2::ErrorHandler;

mod config;

#[derive(Show, PartialEq)]
struct FakeConnection;

struct OkManager;

impl r2d2::PoolManager<FakeConnection, ()> for OkManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        Ok(FakeConnection)
    }

    fn is_valid(&self, _: &mut FakeConnection) -> Result<(), ()> {
        Ok(())
    }

    fn has_broken(&self, _: &mut FakeConnection) -> bool {
        false
    }
}

struct NthConnectFailManager {
    n: Mutex<uint>,
}

impl r2d2::PoolManager<FakeConnection, ()> for NthConnectFailManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        let mut n = self.n.lock().unwrap();
        if *n > 0 {
            *n -= 1;
            Ok(FakeConnection)
        } else {
            Err(())
        }
    }

    fn is_valid(&self, _: &mut FakeConnection) -> Result<(), ()> {
        Ok(())
    }

    fn has_broken(&self, _: &mut FakeConnection) -> bool {
        false
    }
}

#[test]
fn test_pool_size_ok() {
    let config = r2d2::Config {
        pool_size: 5,
        ..Default::default()
    };
    let manager = NthConnectFailManager { n: Mutex::new(5) };
    let pool = r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).unwrap();
    let mut conns = vec![];
    for _ in range(0, config.pool_size) {
        conns.push(pool.get().unwrap());
    }
}

#[test]
fn test_acquire_release() {
    let config = r2d2::Config {
        pool_size: 2,
        ..Default::default()
    };
    let pool = r2d2::Pool::new(config, OkManager, r2d2::NoopErrorHandler).unwrap();

    let conn1 = pool.get().unwrap();
    let conn2 = pool.get().unwrap();
    drop(conn1);
    let conn3 = pool.get().unwrap();
    drop(conn2);
    drop(conn3);
}

#[test]
fn test_is_send_sync() {
    fn is_send_sync<T: Send+Sync>() {}
    is_send_sync::<r2d2::Pool<FakeConnection, (), OkManager, r2d2::NoopErrorHandler>>();
}

#[test]
fn test_issue_2_unlocked_during_is_valid() {
    struct BlockingChecker {
        first: AtomicBool,
        s: Mutex<SyncSender<()>>,
        r: Mutex<Receiver<()>>,
    }

    impl r2d2::PoolManager<FakeConnection, ()> for BlockingChecker {
        fn connect(&self) -> Result<FakeConnection, ()> {
            Ok(FakeConnection)
        }

        fn is_valid(&self, _: &mut FakeConnection) -> Result<(), ()> {
            if self.first.compare_and_swap(true, false, Ordering::SeqCst) {
                self.s.lock().unwrap().send(()).unwrap();
                self.r.lock().unwrap().recv().unwrap();
            }
            Ok(())
        }

        fn has_broken(&self, _: &mut FakeConnection) -> bool {
            false
        }
    }

    let (s1, r1) = mpsc::sync_channel(0);
    let (s2, r2) = mpsc::sync_channel(0);

    let config = r2d2::Config {
        test_on_check_out: true,
        pool_size: 2,
        ..Default::default()
    };
    let manager = BlockingChecker {
        first: AtomicBool::new(true),
        s: Mutex::new(s1),
        r: Mutex::new(r2),
    };
    let pool = Arc::new(r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).unwrap());

    let p2 = pool.clone();
    let _t = Thread::spawn(move || {
        p2.get().unwrap();
    }).detach();

    r1.recv().unwrap();
    // get call by other task has triggered the health check
    pool.get().unwrap();
    s2.send(()).unwrap();
}

#[test]
fn test_drop_on_broken() {
    static DROPPED: AtomicBool = ATOMIC_BOOL_INIT;
    DROPPED.store(false, Ordering::SeqCst);

    struct Connection;

    impl Drop for Connection {
        fn drop(&mut self) {
            DROPPED.store(true, Ordering::SeqCst);
        }
    }

    struct Handler;

    impl r2d2::PoolManager<Connection, ()> for Handler {
        fn connect(&self) -> Result<Connection, ()> {
            Ok(Connection)
        }

        fn is_valid(&self, _: &mut Connection) -> Result<(), ()> {
            Ok(())
        }

        fn has_broken(&self, _: &mut Connection) -> bool {
            true
        }
    }

    let pool = r2d2::Pool::new(Default::default(), Handler, r2d2::NoopErrorHandler).unwrap();

    drop(pool.get().unwrap());

    assert!(DROPPED.load(Ordering::SeqCst));
}

// Just make sure that a boxed error handler works and doesn't self recurse or anything
#[test]
fn test_boxed_error_handler() {
    let handler: Box<ErrorHandler<()>> = box r2d2::NoopErrorHandler;
    handler.handle_error(());
    r2d2::Pool::new(Default::default(), OkManager, handler).unwrap();
}
<|endoftext|>


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

//! Element nodes.

use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode};
use dom::attr:: Attr;
use dom::document;
use dom::namespace;
use dom::namespace::Namespace;
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};
use style;
use servo_util::tree::{TreeNodeRef, ElementLike};

use std::comm;
use std::hashmap::HashMap;
use std::str::{eq, eq_slice};
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node<ScriptView>,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    attrs: HashMap<~str, ~[@mut Attr]>,
    attrs_insert_order: ~[(~str, Namespace)], // store an order of attributes.
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl ElementLike for Element {
    fn get_local_name<'a>(&'a self) -> &'a str {
        self.tag_name.as_slice()
    }

    fn get_attr(&self, name: &str) -> Option<~str> {
        self.get_attribute(None, name).map(|attr| attr.value.clone())
    }

    fn get_link(&self) -> Option<~str>{
        // FIXME: This is HTML only.
        match self.node.type_id {
            // http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-link
            ElementNodeTypeId(HTMLAnchorElementTypeId) |
            ElementNodeTypeId(HTMLAreaElementTypeId) |
            ElementNodeTypeId(HTMLLinkElementTypeId)
            => self.get_attr("href"),
            _ => None,
        }
    }
}

impl<'self> Element {
    pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> Element {
        Element {
            node: Node::new(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            attrs: HashMap::new(),
            attrs_insert_order: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute<'a>(&'a self,
                         namespace_url: Option<DOMString>,
                         name: &str) -> Option<@mut Attr> {
        let namespace = Namespace::from_str(namespace_url);
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.find_equiv(&name).and_then(|attrs| {
            do attrs.iter().find |attr| {
                eq_slice(attr.local_name, name) && attr.namespace == namespace
            }.map(|x| *x)
        })
    }

    pub fn set_attr(&mut self,
                    abstract_self: AbstractNode<ScriptView>,
                    name: DOMString,
                    value: DOMString) -> ErrorResult {
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode<ScriptView>,
                         namespace: Namespace,
                         raw_name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let name = raw_name.to_ascii_lower();
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn_iter(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        // FIXME: reduce the time of `value.clone()`.
        let win = self.node.owner_doc().document().window;
        let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                    name.clone(), namespace.clone(), prefix);
        self.attrs.mangle(local_name.clone(), new_attr,
                          |new_name: &~str, new_value: @mut Attr| {
                              // register to the ordered list.
                              let order_value = (new_name.clone(), new_value.namespace.clone());
                              self.attrs_insert_order.push(order_value);
                              ~[new_value]
                          },
                          |name, old_value: &mut ~[@mut Attr], new_value: @mut Attr| {
                              // update value.
                              let mut found = false;
                              for attr in old_value.mut_iter() {
                                  if eq_slice(attr.local_name, *name) &&
                                     attr.namespace == new_value.namespace {
                                      *attr = new_value;
                                      found = true;
                                      break;
                                  }

                              }
                              if !found {
                                  old_value.push(new_value);
                                  let order_value = (name.clone(), new_value.namespace.clone());
                                  self.attrs_insert_order.push(order_value);
                              }
                          });

        self.after_set_attr(abstract_self, &namespace, local_name, value);
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode<ScriptView>,
                      namespace: &Namespace,
                      local_name: DOMString,
                      value: DOMString) {

        if "style" == local_name && *namespace == namespace::Null {
             self.style_attribute = Some(style::parse_style_attribute(value));
        }

        // TODO: update owner document's id hashmap for `document.getElementById()`
        //       if `name` == "id".

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                do abstract_self.with_mut_image_element |image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                do abstract_self.with_mut_iframe_element |iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let document = self.node.owner_doc();
            document.document().content_changed();
        }
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_owned().to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode<ScriptView>) -> DOMString {
        match self.get_attr(&"id") {
            Some(x) => x,
            None => ~""
        }
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode<ScriptView>, id: DOMString) {
        self.set_attribute(abstract_self, namespace::Null, ~"id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode<ScriptView>) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self,
                        abstract_self: AbstractNode<ScriptView>,
                        name: DOMString,
                        value: DOMString) -> ErrorResult {
        self.set_attr(abstract_self, name, value);
        Ok(())
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode<ScriptView>,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    do rects.map |r| {
                        ClientRect::new(
                            win,
                            r.origin.y.to_f32().unwrap(),
                            (r.origin.y + r.size.height).to_f32().unwrap(),
                            r.origin.x.to_f32().unwrap(),
                            (r.origin.x + r.size.width).to_f32().unwrap())
                    }
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y.to_f32().unwrap(),
                    (rect.origin.y + rect.size.height).to_f32().unwrap(),
                    rect.origin.x.to_f32().unwrap(),
                    (rect.origin.x + rect.size.width).to_f32().unwrap())
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }
}
<commit_msg>Remove an unused lifetime parameter from Element::get_attribute.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Element nodes.

use dom::attrlist::AttrList;
use dom::bindings::utils::{Reflectable, DOMString, ErrorResult, Fallible, Reflector};
use dom::bindings::utils::{null_str_as_empty, NamespaceError};
use dom::bindings::utils::{InvalidCharacter, QName, Name, InvalidXMLName, xml_name_type};
use dom::htmlcollection::HTMLCollection;
use dom::clientrect::ClientRect;
use dom::clientrectlist::ClientRectList;
use dom::document::AbstractDocument;
use dom::node::{ElementNodeTypeId, Node, ScriptView, AbstractNode};
use dom::attr:: Attr;
use dom::document;
use dom::namespace;
use dom::namespace::Namespace;
use layout_interface::{ContentBoxQuery, ContentBoxResponse, ContentBoxesQuery};
use layout_interface::{ContentBoxesResponse};
use style;
use servo_util::tree::{TreeNodeRef, ElementLike};

use std::comm;
use std::hashmap::HashMap;
use std::str::{eq, eq_slice};
use std::ascii::StrAsciiExt;

pub struct Element {
    node: Node<ScriptView>,
    tag_name: ~str,     // TODO: This should be an atom, not a ~str.
    attrs: HashMap<~str, ~[@mut Attr]>,
    attrs_insert_order: ~[(~str, Namespace)], // store an order of attributes.
    style_attribute: Option<style::PropertyDeclarationBlock>,
    attr_list: Option<@mut AttrList>
}

impl Reflectable for Element {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.node.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.node.mut_reflector()
    }
}

#[deriving(Eq)]
pub enum ElementTypeId {
    HTMLElementTypeId,
    HTMLAnchorElementTypeId,
    HTMLAppletElementTypeId,
    HTMLAreaElementTypeId,
    HTMLAudioElementTypeId,
    HTMLBaseElementTypeId,
    HTMLBRElementTypeId,
    HTMLBodyElementTypeId,
    HTMLButtonElementTypeId,
    HTMLCanvasElementTypeId,
    HTMLDataElementTypeId,
    HTMLDataListElementTypeId,
    HTMLDirectoryElementTypeId,
    HTMLDListElementTypeId,
    HTMLDivElementTypeId,
    HTMLEmbedElementTypeId,
    HTMLFieldSetElementTypeId,
    HTMLFontElementTypeId,
    HTMLFormElementTypeId,
    HTMLFrameElementTypeId,
    HTMLFrameSetElementTypeId,
    HTMLHRElementTypeId,
    HTMLHeadElementTypeId,
    HTMLHeadingElementTypeId,
    HTMLHtmlElementTypeId,
    HTMLIframeElementTypeId,
    HTMLImageElementTypeId,
    HTMLInputElementTypeId,
    HTMLLabelElementTypeId,
    HTMLLegendElementTypeId,
    HTMLLinkElementTypeId,
    HTMLLIElementTypeId,
    HTMLMainElementTypeId,
    HTMLMapElementTypeId,
    HTMLMediaElementTypeId,
    HTMLMetaElementTypeId,
    HTMLMeterElementTypeId,
    HTMLModElementTypeId,
    HTMLObjectElementTypeId,
    HTMLOListElementTypeId,
    HTMLOptGroupElementTypeId,
    HTMLOptionElementTypeId,
    HTMLOutputElementTypeId,
    HTMLParagraphElementTypeId,
    HTMLParamElementTypeId,
    HTMLPreElementTypeId,
    HTMLProgressElementTypeId,
    HTMLQuoteElementTypeId,
    HTMLScriptElementTypeId,
    HTMLSelectElementTypeId,
    HTMLSourceElementTypeId,
    HTMLSpanElementTypeId,
    HTMLStyleElementTypeId,
    HTMLTableElementTypeId,
    HTMLTableCaptionElementTypeId,
    HTMLTableCellElementTypeId,
    HTMLTableDataCellElementTypeId,
    HTMLTableHeaderCellElementTypeId,
    HTMLTableColElementTypeId,
    HTMLTableRowElementTypeId,
    HTMLTableSectionElementTypeId,
    HTMLTemplateElementTypeId,
    HTMLTextAreaElementTypeId,
    HTMLTimeElementTypeId,
    HTMLTitleElementTypeId,
    HTMLTrackElementTypeId,
    HTMLUListElementTypeId,
    HTMLVideoElementTypeId,
    HTMLUnknownElementTypeId,
}

//
// Element methods
//

impl ElementLike for Element {
    fn get_local_name<'a>(&'a self) -> &'a str {
        self.tag_name.as_slice()
    }

    fn get_attr(&self, name: &str) -> Option<~str> {
        self.get_attribute(None, name).map(|attr| attr.value.clone())
    }

    fn get_link(&self) -> Option<~str>{
        // FIXME: This is HTML only.
        match self.node.type_id {
            // http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-link
            ElementNodeTypeId(HTMLAnchorElementTypeId) |
            ElementNodeTypeId(HTMLAreaElementTypeId) |
            ElementNodeTypeId(HTMLLinkElementTypeId)
            => self.get_attr("href"),
            _ => None,
        }
    }
}

impl<'self> Element {
    pub fn new(type_id: ElementTypeId, tag_name: ~str, document: AbstractDocument) -> Element {
        Element {
            node: Node::new(ElementNodeTypeId(type_id), document),
            tag_name: tag_name,
            attrs: HashMap::new(),
            attrs_insert_order: ~[],
            attr_list: None,
            style_attribute: None,
        }
    }

    pub fn normalize_attr_name(&self, name: Option<DOMString>) -> ~str {
        //FIXME: Throw for XML-invalid names
        let owner = self.node.owner_doc();
        if owner.document().doctype == document::HTML { // && self.namespace == Namespace::HTML
            null_str_as_empty(&name).to_ascii_lower()
        } else {
            null_str_as_empty(&name)
        }
    }

    pub fn get_attribute(&self,
                         namespace_url: Option<DOMString>,
                         name: &str) -> Option<@mut Attr> {
        let namespace = Namespace::from_str(namespace_url);
        // FIXME: only case-insensitive in the HTML namespace (as opposed to SVG, etc.)
        let name = name.to_ascii_lower();
        self.attrs.find_equiv(&name).and_then(|attrs| {
            do attrs.iter().find |attr| {
                eq_slice(attr.local_name, name) && attr.namespace == namespace
            }.map(|x| *x)
        })
    }

    pub fn set_attr(&mut self,
                    abstract_self: AbstractNode<ScriptView>,
                    name: DOMString,
                    value: DOMString) -> ErrorResult {
        self.set_attribute(abstract_self, namespace::Null, name, value)
    }

    pub fn set_attribute(&mut self,
                         abstract_self: AbstractNode<ScriptView>,
                         namespace: Namespace,
                         raw_name: DOMString,
                         value: DOMString) -> ErrorResult {
        //FIXME: Throw for XML-invalid names
        //FIXME: Throw for XMLNS-invalid names
        let name = raw_name.to_ascii_lower();
        let (prefix, local_name) = if name.contains(":")  {
            let parts: ~[&str] = name.splitn_iter(':', 1).collect();
            (Some(parts[0].to_owned()), parts[1].to_owned())
        } else {
            (None, name.clone())
        };
        match prefix {
            Some(ref prefix_str) => {
                if (namespace == namespace::Null ||
                    (eq(prefix_str, &~"xml") && namespace != namespace::XML) ||
                    (eq(prefix_str, &~"xmlns") && namespace != namespace::XMLNS)) {
                    return Err(NamespaceError);
                }
            },
            None => {}
        }

        // FIXME: reduce the time of `value.clone()`.
        let win = self.node.owner_doc().document().window;
        let new_attr = Attr::new_ns(win, local_name.clone(), value.clone(),
                                    name.clone(), namespace.clone(), prefix);
        self.attrs.mangle(local_name.clone(), new_attr,
                          |new_name: &~str, new_value: @mut Attr| {
                              // register to the ordered list.
                              let order_value = (new_name.clone(), new_value.namespace.clone());
                              self.attrs_insert_order.push(order_value);
                              ~[new_value]
                          },
                          |name, old_value: &mut ~[@mut Attr], new_value: @mut Attr| {
                              // update value.
                              let mut found = false;
                              for attr in old_value.mut_iter() {
                                  if eq_slice(attr.local_name, *name) &&
                                     attr.namespace == new_value.namespace {
                                      *attr = new_value;
                                      found = true;
                                      break;
                                  }

                              }
                              if !found {
                                  old_value.push(new_value);
                                  let order_value = (name.clone(), new_value.namespace.clone());
                                  self.attrs_insert_order.push(order_value);
                              }
                          });

        self.after_set_attr(abstract_self, &namespace, local_name, value);
        Ok(())
    }

    fn after_set_attr(&mut self,
                      abstract_self: AbstractNode<ScriptView>,
                      namespace: &Namespace,
                      local_name: DOMString,
                      value: DOMString) {

        if "style" == local_name && *namespace == namespace::Null {
             self.style_attribute = Some(style::parse_style_attribute(value));
        }

        // TODO: update owner document's id hashmap for `document.getElementById()`
        //       if `name` == "id".

        //XXXjdm We really need something like a vtable so we can call AfterSetAttr.
        //       This hardcoding is awful.
        match abstract_self.type_id() {
            ElementNodeTypeId(HTMLImageElementTypeId) => {
                do abstract_self.with_mut_image_element |image| {
                    image.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            ElementNodeTypeId(HTMLIframeElementTypeId) => {
                do abstract_self.with_mut_iframe_element |iframe| {
                    iframe.AfterSetAttr(local_name.clone(), value.clone());
                }
            }
            _ => ()
        }

        if abstract_self.is_in_doc() {
            let document = self.node.owner_doc();
            document.document().content_changed();
        }
    }
}

impl Element {
    pub fn TagName(&self) -> DOMString {
        self.tag_name.to_owned().to_ascii_upper()
    }

    pub fn Id(&self, _abstract_self: AbstractNode<ScriptView>) -> DOMString {
        match self.get_attr(&"id") {
            Some(x) => x,
            None => ~""
        }
    }

    pub fn SetId(&mut self, abstract_self: AbstractNode<ScriptView>, id: DOMString) {
        self.set_attribute(abstract_self, namespace::Null, ~"id", id);
    }

    pub fn Attributes(&mut self, abstract_self: AbstractNode<ScriptView>) -> @mut AttrList {
        match self.attr_list {
            None => {
                let window = self.node.owner_doc().document().window;
                let list = AttrList::new(window, abstract_self);
                self.attr_list = Some(list);
                list
            }
            Some(list) => list
        }
    }

    pub fn GetAttribute(&self, name: DOMString) -> Option<DOMString> {
        self.get_attr(name).map(|s| s.to_owned())
    }

    pub fn GetAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> Option<DOMString> {
        self.get_attribute(namespace, local_name)
            .map(|attr| attr.value.clone())
    }

    pub fn SetAttribute(&mut self,
                        abstract_self: AbstractNode<ScriptView>,
                        name: DOMString,
                        value: DOMString) -> ErrorResult {
        self.set_attr(abstract_self, name, value);
        Ok(())
    }

    pub fn SetAttributeNS(&mut self,
                          abstract_self: AbstractNode<ScriptView>,
                          namespace_url: Option<DOMString>,
                          name: DOMString,
                          value: DOMString) -> ErrorResult {
        let name_type = xml_name_type(name);
        match name_type {
            InvalidXMLName => return Err(InvalidCharacter),
            Name => return Err(NamespaceError),
            QName => {}
        }

        let namespace = Namespace::from_str(namespace_url);
        self.set_attribute(abstract_self, namespace, name, value)
    }

    pub fn RemoveAttribute(&self, _name: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn RemoveAttributeNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn HasAttribute(&self, name: DOMString) -> bool {
        self.GetAttribute(name).is_some()
    }

    pub fn HasAttributeNS(&self, namespace: Option<DOMString>, local_name: DOMString) -> bool {
        self.GetAttributeNS(namespace, local_name).is_some()
    }

    pub fn GetElementsByTagName(&self, _localname: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn GetElementsByTagNameNS(&self, _namespace: Option<DOMString>, _localname: DOMString) -> Fallible<@mut HTMLCollection> {
        Ok(HTMLCollection::new(self.node.owner_doc().document().window, ~[]))
    }

    pub fn GetElementsByClassName(&self, _names: DOMString) -> @mut HTMLCollection {
        HTMLCollection::new(self.node.owner_doc().document().window, ~[])
    }

    pub fn MozMatchesSelector(&self, _selector: DOMString) -> Fallible<bool> {
        Ok(false)
    }

    pub fn SetCapture(&self, _retargetToElement: bool) {
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozRequestFullScreen(&self) {
    }

    pub fn MozRequestPointerLock(&self) {
    }

    pub fn GetClientRects(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRectList {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        let rects =
            match win.page.query_layout(ContentBoxesQuery(node, chan), port) {
                ContentBoxesResponse(rects) => {
                    do rects.map |r| {
                        ClientRect::new(
                            win,
                            r.origin.y.to_f32().unwrap(),
                            (r.origin.y + r.size.height).to_f32().unwrap(),
                            r.origin.x.to_f32().unwrap(),
                            (r.origin.x + r.size.width).to_f32().unwrap())
                    }
                },
            };

        ClientRectList::new(win, rects)
    }

    pub fn GetBoundingClientRect(&self, abstract_self: AbstractNode<ScriptView>) -> @mut ClientRect {
        let win = self.node.owner_doc().document().window;
        let node = abstract_self;
        assert!(node.is_element());
        let (port, chan) = comm::stream();
        match win.page.query_layout(ContentBoxQuery(node, chan), port) {
            ContentBoxResponse(rect) => {
                ClientRect::new(
                    win,
                    rect.origin.y.to_f32().unwrap(),
                    (rect.origin.y + rect.size.height).to_f32().unwrap(),
                    rect.origin.x.to_f32().unwrap(),
                    (rect.origin.x + rect.size.width).to_f32().unwrap())
            }
        }
    }

    pub fn ScrollIntoView(&self, _top: bool) {
    }

    pub fn ScrollTop(&self) -> i32 {
        0
    }

    pub fn SetScrollTop(&mut self, _scroll_top: i32) {
    }

    pub fn ScrollLeft(&self) -> i32 {
        0
    }

    pub fn SetScrollLeft(&mut self, _scroll_left: i32) {
    }

    pub fn ScrollWidth(&self) -> i32 {
        0
    }

    pub fn ScrollHeight(&self) -> i32 {
        0
    }

    pub fn ClientTop(&self) -> i32 {
        0
    }

    pub fn ClientLeft(&self) -> i32 {
        0
    }

    pub fn ClientWidth(&self) -> i32 {
        0
    }

    pub fn ClientHeight(&self) -> i32 {
        0
    }

    pub fn GetInnerHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetInnerHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn GetOuterHTML(&self) -> Fallible<DOMString> {
        Ok(~"")
    }

    pub fn SetOuterHTML(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn InsertAdjacentHTML(&mut self, _position: DOMString, _text: DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn QuerySelector(&self, _selectors: DOMString) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Lifetime annotation needed because we have no arguments.
fn f() -> &int {    //~ ERROR missing lifetime specifier
    fail!()
}

// Lifetime annotation needed because we have two by-reference parameters.
fn g(_: &int, _: &int) -> &int {    //~ ERROR missing lifetime specifier
    fail!()
}

struct Foo<'a> {
    x: &'a int,
}

// Lifetime annotation needed because we have two lifetime: one as a parameter
// and one on the reference.
fn h(_: &Foo) -> &int { //~ ERROR missing lifetime specifier
    fail!()
}

fn main() {}

<commit_msg>small typo<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Lifetime annotation needed because we have no arguments.
fn f() -> &int {    //~ ERROR missing lifetime specifier
    fail!()
}

// Lifetime annotation needed because we have two by-reference parameters.
fn g(_: &int, _: &int) -> &int {    //~ ERROR missing lifetime specifier
    fail!()
}

struct Foo<'a> {
    x: &'a int,
}

// Lifetime annotation needed because we have two lifetimes: one as a parameter
// and one on the reference.
fn h(_: &Foo) -> &int { //~ ERROR missing lifetime specifier
    fail!()
}

fn main() {}

<|endoftext|>


<commit_before>use socket::Socket;

pub struct Burst {
    socket: Socket,
}

impl Burst {
    pub fn new(socket: Socket) -> Self {
        Burst {
            socket: socket,
        }
    }

    pub fn enable(&mut self, source: u8) {
        self.socket.send(format!("SOUR{}:BURS:STAT ON", source));
    }

    pub fn disable(&mut self, source: u8) {
        self.socket.send(format!("SOUR{}:BURS:STAT OFF", source));
    }

    pub fn set_count(&mut self, source: u8, count: u32) {
        self.socket.send(format!("SOUR{}:BURS:NCYC {}", source, count));
    }

    pub fn set_repetitions(&mut self, source: u8, repetitions: u32) {
        self.socket.send(format!("SOUR{}:BURS:NOR {}", source, repetitions));
    }

    pub fn set_period(&mut self, source: u8, period: u32) {
        self.socket.send(format!("SOUR{}:BURS:INT:PER {}", source, period));
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_enable() {
        let (rx, mut burst) = create_burst();

        burst.enable(1);
        assert_eq!("SOUR1:BURS:STAT ON\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_disable() {
        let (rx, mut burst) = create_burst();

        burst.disable(1);
        assert_eq!("SOUR1:BURS:STAT OFF\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_count() {
        let (rx, mut burst) = create_burst();

        burst.set_count(1, 3);
        assert_eq!("SOUR1:BURS:NCYC 3\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_repetitions() {
        let (rx, mut burst) = create_burst();

        burst.set_repetitions(1, 5);
        assert_eq!("SOUR1:BURS:NOR 5\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_period() {
        let (rx, mut burst) = create_burst();

        burst.set_period(1, 1_000_000);
        assert_eq!("SOUR1:BURS:INT:PER 1000000\r\n", rx.recv().unwrap());
    }

    fn create_burst() -> (::std::sync::mpsc::Receiver<String>, ::burst::Burst) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::burst::Burst::new(socket))
    }
}
<commit_msg>[burst] Add burst::Source enum<commit_after>use socket::Socket;

pub enum Source {
    OUT1,
    OUT2,
}

impl ::std::fmt::Display for Source {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let display = match self {
            &Source::OUT1 => "SOUR1",
            &Source::OUT2 => "SOUR2",
        };

        write!(f, "{}", display)
    }
}

pub struct Burst {
    socket: Socket,
}

impl Burst {
    pub fn new(socket: Socket) -> Self {
        Burst {
            socket: socket,
        }
    }

    pub fn enable(&mut self, source: Source) {
        self.socket.send(format!("{}:BURS:STAT ON", source));
    }

    pub fn disable(&mut self, source: Source) {
        self.socket.send(format!("{}:BURS:STAT OFF", source));
    }

    pub fn set_count(&mut self, source: Source, count: u32) {
        self.socket.send(format!("{}:BURS:NCYC {}", source, count));
    }

    pub fn set_repetitions(&mut self, source: Source, repetitions: u32) {
        self.socket.send(format!("{}:BURS:NOR {}", source, repetitions));
    }

    pub fn set_period(&mut self, source: Source, period: u32) {
        self.socket.send(format!("{}:BURS:INT:PER {}", source, period));
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_enable() {
        let (rx, mut burst) = create_burst();

        burst.enable(::burst::Source::OUT1);
        assert_eq!("SOUR1:BURS:STAT ON\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_disable() {
        let (rx, mut burst) = create_burst();

        burst.disable(::burst::Source::OUT1);
        assert_eq!("SOUR1:BURS:STAT OFF\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_count() {
        let (rx, mut burst) = create_burst();

        burst.set_count(::burst::Source::OUT1, 3);
        assert_eq!("SOUR1:BURS:NCYC 3\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_repetitions() {
        let (rx, mut burst) = create_burst();

        burst.set_repetitions(::burst::Source::OUT1, 5);
        assert_eq!("SOUR1:BURS:NOR 5\r\n", rx.recv().unwrap());
    }

    #[test]
    fn test_set_period() {
        let (rx, mut burst) = create_burst();

        burst.set_period(::burst::Source::OUT2, 1_000_000);
        assert_eq!("SOUR2:BURS:INT:PER 1000000\r\n", rx.recv().unwrap());
    }

    fn create_burst() -> (::std::sync::mpsc::Receiver<String>, ::burst::Burst) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(
            format!("{}", addr.ip()).as_str(),
            addr.port()
        );

        (rx, ::burst::Burst::new(socket))
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::mem;
use std::ops::Add;

use bytes::{alloc, MutByteBuf, ByteBuf, Buf, MutBuf};
use mio::{TryWrite, TryRead};

pub trait Codec<In: ?Sized, Out: ?Sized>
{
    fn decode(&mut self, buf: &mut In) -> Vec<Out>;
    fn encode(&self, a: Out) -> In;
}

pub struct CodecStack<In, Mid, Out> {
    left: Box<Codec<In, Mid>>,
    right: Box<Codec<Mid, Out>>,
}

impl <In, Mid, Out> Codec<In, Out> for CodecStack<In, Mid, Out> {
    fn decode(&mut self, buf: &mut In) -> Vec<Out> {
        self.left.decode(buf).iter_mut().flat_map( |mut d|
            self.right.decode(&mut d)).collect()
    }

    fn encode(&self, out: Out) -> In {
        self.left.encode(self.right.encode(out))
    }
}

pub struct Framed {
    sz_buf: MutByteBuf,
    msg: Option<MutByteBuf>,
}

impl Framed {
    pub fn new() -> Framed {
        Framed {
            sz_buf: ByteBuf::mut_with_capacity(4),
            msg: None,
        }
    }
}

impl Codec<ByteBuf, ByteBuf> for Framed {

    fn decode(&mut self, buf: &mut ByteBuf) -> Vec<ByteBuf> {
        let mut res = vec![];
        loop {
            // read size if we don't have a message yet
            if self.msg.is_none() {
                // TODO(tyler) incrementally build size, or this will explode
                let sz_read = buf.try_read_buf(&mut self.sz_buf);
                debug!("read {} bytes into the sz buffer", sz_read.unwrap().unwrap());
                // if we've read 4 bytes for the size, create a msg
                if self.sz_buf.remaining() != 0 {
                    break;
                }

                let sz_buf = self.sz_buf.bytes();
                let size = array_to_usize([sz_buf[0], sz_buf[1], sz_buf[2], sz_buf[3]]);
                self.msg = unsafe {
                    // manually create bytebuf so we can have exact cap and lim
                    Some(ByteBuf::from_mem_ref(
                        alloc::heap(size.next_power_of_two()),
                        size as u32, // cap
                        0,           // pos
                        size as u32  // lim
                    ).flip())
                };
            }

            if self.msg.is_none() {
                break;
            }

            let mut msg = self.msg.take().unwrap();

            // read actual message
            match buf.try_read_buf(&mut msg) {
                Ok(Some(read)) => {
                    // if we're done, return our Item
                    if msg.remaining() == 0 {
                        // get ready to read a new size
                        self.sz_buf.clear();
                        // return the message
                        res.push(msg.flip())
                    } else {
                        self.msg = Some(msg);
                        break
                    }
                },
                _ => break,
            }
        }
        res
    }

    fn encode(&self, item: ByteBuf) -> ByteBuf {
        let b = item.bytes();
        println!("encoding: {:?}", b);
        let mut res = ByteBuf::mut_with_capacity(4 + b.len());
        assert!(res.write_slice(&usize_to_array(b.len())) == 4);
        assert!(res.write_slice(b) == b.len());
        res.flip()
    }
}

pub fn usize_to_array(u: usize) -> [u8;4] {
    [(u >> 24) as u8, (u >> 16) as u8, (u >> 8) as u8, u as u8]
}

pub fn array_to_usize(ip: [u8;4]) -> usize {
    ((ip[0] as usize) << 24) as usize +
        ((ip[1] as usize) << 16) as usize +
        ((ip[2] as usize) << 8) as usize +
        (ip[3] as usize)
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;
    use rand::{Rng, thread_rng};

    use codec;
    use codec::Codec;
    use bytes::{MutByteBuf, ByteBuf, Buf};

    fn array_prop(u: usize) -> bool {
        codec::array_to_usize(codec::usize_to_array(u)) == u
    }

    #[test]
    fn test_usize_to_array_to_usize() {
        quickcheck::quickcheck(array_prop as fn(usize)->bool);
        let ip = [250,1,2,3];
        assert!(codec::usize_to_array(codec::array_to_usize(ip)) == ip);
    }

    fn framed_prop(sz: usize) -> bool {
        if sz == 0 {
            // TODO(tyler) currently, feeding an empty slice to
            // ByteBuf::from_slice causes a segfault...
            return true;
        }
        let mut rng = thread_rng();
        let mut v: Vec<u8> = rng.gen_iter::<u8>().take(sz).collect();
        let mut c = codec::Framed::new();
        let mut bytes = ByteBuf::from_slice(&*v);
        let mut encoded = codec::Framed::encode(bytes);
        let decoded = c.decode(&mut encoded).unwrap();
        decoded.bytes() == &*v
    }

    #[test]
    fn test_framed_codec() {
        quickcheck::quickcheck(framed_prop as fn(usize)->bool);
    }
}
<commit_msg>cleanup todos<commit_after>use std::io;
use std::mem;
use std::ops::Add;

use bytes::{alloc, MutByteBuf, ByteBuf, Buf, MutBuf};
use mio::{TryWrite, TryRead};

pub trait Codec<In: ?Sized, Out: ?Sized>
{
    fn decode(&mut self, buf: &mut In) -> Vec<Out>;
    fn encode(&self, a: Out) -> In;
}

pub struct CodecStack<In, Mid, Out> {
    left: Box<Codec<In, Mid>>,
    right: Box<Codec<Mid, Out>>,
}

impl <In, Mid, Out> Codec<In, Out> for CodecStack<In, Mid, Out> {
    fn decode(&mut self, buf: &mut In) -> Vec<Out> {
        self.left.decode(buf).iter_mut().flat_map( |mut d|
            self.right.decode(&mut d)).collect()
    }

    fn encode(&self, out: Out) -> In {
        self.left.encode(self.right.encode(out))
    }
}

pub struct Framed {
    sz_buf: MutByteBuf,
    msg: Option<MutByteBuf>,
}

impl Framed {
    pub fn new() -> Framed {
        Framed {
            sz_buf: ByteBuf::mut_with_capacity(4),
            msg: None,
        }
    }
}

impl Codec<ByteBuf, ByteBuf> for Framed {

    fn decode(&mut self, buf: &mut ByteBuf) -> Vec<ByteBuf> {
        let mut res = vec![];
        loop {
            // read size if we don't have a message yet
            if self.msg.is_none() {
                let sz_read = buf.try_read_buf(&mut self.sz_buf);
                debug!("read {} bytes into the sz buffer", sz_read.unwrap().unwrap());
                // if we've read 4 bytes for the size, create a msg
                if self.sz_buf.remaining() != 0 {
                    break;
                }

                let sz_buf = self.sz_buf.bytes();
                let size = array_to_usize([sz_buf[0], sz_buf[1], sz_buf[2], sz_buf[3]]);
                self.msg = unsafe {
                    // manually create bytebuf so we can have exact cap and lim
                    Some(ByteBuf::from_mem_ref(
                        alloc::heap(size.next_power_of_two()),
                        size as u32, // cap
                        0,           // pos
                        size as u32  // lim
                    ).flip())
                };
            }

            if self.msg.is_none() {
                break;
            }

            let mut msg = self.msg.take().unwrap();

            // read actual message
            match buf.try_read_buf(&mut msg) {
                Ok(Some(read)) => {
                    // if we're done, return our Item
                    if msg.remaining() == 0 {
                        // get ready to read a new size
                        self.sz_buf.clear();
                        // return the message
                        res.push(msg.flip())
                    } else {
                        self.msg = Some(msg);
                        break
                    }
                },
                _ => break,
            }
        }
        res
    }

    fn encode(&self, item: ByteBuf) -> ByteBuf {
        let b = item.bytes();
        println!("encoding: {:?}", b);
        let mut res = ByteBuf::mut_with_capacity(4 + b.len());
        assert!(res.write_slice(&usize_to_array(b.len())) == 4);
        assert!(res.write_slice(b) == b.len());
        res.flip()
    }
}

pub fn usize_to_array(u: usize) -> [u8;4] {
    [(u >> 24) as u8, (u >> 16) as u8, (u >> 8) as u8, u as u8]
}

pub fn array_to_usize(ip: [u8;4]) -> usize {
    ((ip[0] as usize) << 24) as usize +
        ((ip[1] as usize) << 16) as usize +
        ((ip[2] as usize) << 8) as usize +
        (ip[3] as usize)
}

#[cfg(test)]
mod tests {
    extern crate quickcheck;
    use rand::{Rng, thread_rng};

    use codec;
    use codec::Codec;
    use bytes::{MutByteBuf, ByteBuf, Buf};

    fn array_prop(u: usize) -> bool {
        codec::array_to_usize(codec::usize_to_array(u)) == u
    }

    #[test]
    fn test_usize_to_array_to_usize() {
        quickcheck::quickcheck(array_prop as fn(usize)->bool);
        let ip = [250,1,2,3];
        assert!(codec::usize_to_array(codec::array_to_usize(ip)) == ip);
    }

    fn framed_prop(sz: usize) -> bool {
        if sz == 0 {
            // TODO(tyler) currently, feeding an empty slice to
            // ByteBuf::from_slice causes a segfault...
            return true;
        }
        let mut rng = thread_rng();
        let mut v: Vec<u8> = rng.gen_iter::<u8>().take(sz).collect();
        let mut c = codec::Framed::new();
        let mut bytes = ByteBuf::from_slice(&*v);
        let mut encoded = codec::Framed::encode(bytes);
        let decoded = c.decode(&mut encoded).unwrap();
        decoded.bytes() == &*v
    }

    #[test]
    fn test_framed_codec() {
        quickcheck::quickcheck(framed_prop as fn(usize)->bool);
    }
}
<|endoftext|>


<commit_before>use rustc::lint::Context;
use rustc::middle::const_eval::lookup_const_by_id;
use syntax::ast::*;
use syntax::ptr::P;

pub enum FloatWidth {
    Fw32,
    Fw64,
    FwAny
}

impl From<FloatTy> for FloatWidth {
    fn from(ty: FloatTy) -> FloatWidth {
        match ty {
            TyF32 => Fw32,
            TyF64 => Fw64,
        }
    }
}

/// a Lit_-like enum to fold constant `Expr`s into
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Constant {
    /// a String "abc"
    ConstantStr(&'static str, StrStyle),
    /// a Binary String b"abc"
    ConstantBinary(Rc<Vec<u8>>),
    /// a single byte b'a'
    ConstantByte(u8),
    /// a single char 'a'
    ConstantChar(char),
    /// an integer
    ConstantInt(u64, LitIntType),
    /// a float with given type
    ConstantFloat(Cow<'static, str>, FloatWidth),
    /// true or false
    ConstantBool(bool),
    /// an array of constants
    ConstantVec(Vec<Constant>),
    /// also an array, but with only one constant, repeated N times
    ConstantRepeat(Constant, usize),
    /// a tuple of constants
    ConstantTuple(Vec<Constant>),
}

/// simple constant folding
pub fn constant(cx: &Context, e: &Expr, follow: bool) -> Option<Constant> {
    match e {
        &ExprParen(ref inner) => constant(cx, inner, follow),
        &ExprPath(_, _) => if follow { fetch_path(cx, e) } else { None },
        &ExprBlock(ref block) => constant_block(cx, inner, follow),
        &ExprIf(ref cond, ref then, ref otherwise) =>
            match constant(cx, cond) {
                Some(ConstantBool(true)) => constant(cx, then, follow),
                Some(ConstantBool(false)) => constant(cx, otherwise, follow),
                _ => None,
            },
        &ExprLit(ref lit) => Some(lit_to_constant(lit)),
        &ExprVec(ref vec) => constant_vec(cx, vec, follow),
        &ExprTup(ref tup) => constant_tup(cx, tup, follow),
        &ExprRepeat(ref value, ref number) =>
            constant_binop_apply(cx, value, number,|v, n| ConstantRepeat(v, n)),
        &ExprUnary(op, ref operand) => constant(cx, operand, follow).and_then(
            |o| match op {
                UnNot =>
                    if let ConstantBool(b) = o {
                        Some(ConstantBool(!b))
                    } else { None },
                UnNeg => constant_negate(o),
                UnUniq | UnDeref => o,
            }),
        &ExprBinary(op, ref left, ref right) =>
            constant_binop(cx, op, left, right, follow),
        //TODO: add other expressions
        _ => None,
    }
}

fn lit_to_constant(lit: &Lit_) -> Constant {
    match lit {
        &LitStr(ref is, style) => ConstantStr(&*is, style),
        &LitBinary(ref blob) => ConstantBinary(blob.clone()),
        &LitByte(b) => ConstantByte(b),
        &LitChar(c) => ConstantChar(c),
        &LitInt(value, ty) => ConstantInt(value, ty),
        &LitFloat(ref is, ty) => ConstantFloat(Cow::Borrowed(&*is), ty.into()),
        &LitFloatUnsuffixed(InternedString) =>
                ConstantFloat(Cow::Borrowed(&*is), FwAny),
        &LitBool(b) => ConstantBool(b),
    }
}

/// create `Some(ConstantVec(..))` of all constants, unless there is any
/// non-constant part
fn constant_vec(cx: &Context, vec: &[&Expr], follow: bool) -> Option<Constant> {
    parts = Vec::new();
    for opt_part in vec {
        match constant(cx, opt_part, follow) {
            Some(ref p) => parts.push(p),
            None => { return None; },
        }
    }
    Some(ConstantVec(parts))
}

fn constant_tup(cx: &Context, tup: &[&Expr], follow: bool) -> Option<Constant> {
    parts = Vec::new();
    for opt_part in vec {
        match constant(cx, opt_part, follow) {
            Some(ref p) => parts.push(p),
            None => { return None; },
        }
    }
    Some(ConstantTuple(parts))
}

/// lookup a possibly constant expression from a ExprPath
fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> {
    if let Some(&PathResolution { base_def: DefConst(id), ..}) =
            cx.tcx.def_map.borrow().get(&e.id) {
        lookup_const_by_id(cx.tcx, id, None).map(|l| constant(cx, l))
    } else { None }
}

/// A block can only yield a constant if it only has one constant expression
fn constant_block(cx: &Context, block: &Block, follow: bool) -> Option<Constant> {
    if block.stmts.is_empty() {
        block.expr.map(|b| constant(cx, b, follow))
    } else { None }
}

fn constant_negate(o: Constant) -> Option<Constant> {
    match o {
        &ConstantInt(value, ty) =>
            Some(ConstantInt(value, match ty {
                SignedIntLit(ity, sign) => SignedIntLit(ity, neg_sign(sign)),
                UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)),
                _ => { return None; },
            })),
        &LitFloat(ref is, ref ty) => Some(ConstantFloat(neg_float_str(is), ty)),
        _ => None,
    }
}

fn neg_sign(s: Sign) -> Sign {
    match s {
        Sign::Plus => Sign::Minus,
        Sign::Minus => Sign::Plus,
    }
}

fn neg_float_str(s: &InternedString) -> Cow<'static, str> {
    if s.startsWith('-') {
        Cow::Borrowed(s[1..])
    } else {
        Cow::Owned(format!("-{}", &*s))
    }
}

fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr,
        follow: bool) -> Option<Constant> {
    match op.node {
        //BiAdd,
        //BiSub,
        //BiMul,
        //BiDiv,
        //BiRem,
        BiAnd => constant_short_circuit(cx, left, right, false, follow),
        BiOr => constant_short_circuit(cx, left, right, true, follow),
        //BiBitXor,
        //BiBitAnd,
        //BiBitOr,
        //BiShl,
        //BiShr,
        //BiEq,
        //BiLt,
        //BiLe,
        //BiNe,
        //BiGe,
        //BiGt,
        _ => None,
    }
}

fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F,
        follow: bool) -> Option<Constant>
where F: FnMut(Constant, Constant) -> Option<Constant> {
    constant(cx, left, follow).and_then(|l| constant(cx, right, follow)
        .and_then(|r| op(l, r)))
}

fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool,
        follow: bool) -> Option<Constant> {
    if let ConstantBool(lbool) = constant(cx, left, follow) {
        if l == b {
            Some(ConstantBool(b))
        } else {
            if let ConstantBool(rbool) = constant(cx, right, follow) {
                Some(ConstantBool(rbool))
            } else { None }
        }
    } else { None }
}
<commit_msg>changed Constant to a struct with 'needed_resolution' bool<commit_after>use rustc::lint::Context;
use rustc::middle::const_eval::lookup_const_by_id;
use syntax::ast::*;
use syntax::ptr::P;

pub enum FloatWidth {
    Fw32,
    Fw64,
    FwAny
}

impl From<FloatTy> for FloatWidth {
    fn from(ty: FloatTy) -> FloatWidth {
        match ty {
            TyF32 => Fw32,
            TyF64 => Fw64,
        }
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Constant {
    constant: ConstantVariant,
    needed_resolution: bool
}

impl Constant {
    fn new(variant: ConstantVariant) -> Constant {
        Constant { constant: variant, needed_resolution: false }
    }

    fn new_resolved(variant: ConstantVariant) -> Constant {
        Constant { constant: variant, needed_resolution: true }
    }
}

/// a Lit_-like enum to fold constant `Expr`s into
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum ConstantVariant {
    /// a String "abc"
    ConstantStr(&'static str, StrStyle),
    /// a Binary String b"abc"
    ConstantBinary(Rc<Vec<u8>>),
    /// a single byte b'a'
    ConstantByte(u8),
    /// a single char 'a'
    ConstantChar(char),
    /// an integer
    ConstantInt(u64, LitIntType),
    /// a float with given type
    ConstantFloat(Cow<'static, str>, FloatWidth),
    /// true or false
    ConstantBool(bool),
    /// an array of constants
    ConstantVec(Vec<Constant>),
    /// also an array, but with only one constant, repeated N times
    ConstantRepeat(Constant, usize),
    /// a tuple of constants
    ConstantTuple(Vec<Constant>),
}

impl ConstantVariant {
    /// convert to u64 if possible
    ///
    /// # panics
    ///
    /// if the constant could not be converted to u64 losslessly
    fn as_u64(&self) -> u64 {
        if let &ConstantInt(val, _) = self {
            val // TODO we may want to check the sign if any
        } else {
            panic!("Could not convert a {:?} to u64");
        }
    }
}

/// simple constant folding: Insert an expression, get a constant or none.
pub fn constant(cx: &Context, e: &Expr) -> Option<Constant> {
    match e {
        &ExprParen(ref inner) => constant(cx, inner),
        &ExprPath(_, _) => fetch_path(cx, e),
        &ExprBlock(ref block) => constant_block(cx, inner),
        &ExprIf(ref cond, ref then, ref otherwise) =>
            constant_if(cx, cond, then, otherwise),
        &ExprLit(ref lit) => Some(lit_to_constant(lit)),
        &ExprVec(ref vec) => constant_vec(cx, vec),
        &ExprTup(ref tup) => constant_tup(cx, tup),
        &ExprRepeat(ref value, ref number) =>
            constant_binop_apply(cx, value, number,|v, n| Constant {
                constant: ConstantRepeat(v, n.constant.as_u64()),
                needed_resolution: v.needed_resolution || n.needed_resolution
            }),
        &ExprUnary(op, ref operand) => constant(cx, operand).and_then(
            |o| match op {
                UnNot =>
                    if let ConstantBool(b) = o.variant {
                        Some(Constant{
                            needed_resolution: o.needed_resolution,
                            constant: ConstantBool(!b),
                        })
                    } else { None },
                UnNeg => constant_negate(o),
                UnUniq | UnDeref => o,
            }),
        &ExprBinary(op, ref left, ref right) =>
            constant_binop(op, left, right),
        //TODO: add other expressions
        _ => None,
    }
}

fn lit_to_constant(lit: &Lit_) -> Constant {
    match lit {
        &LitStr(ref is, style) => Constant::new(ConstantStr(&*is, style)),
        &LitBinary(ref blob) => Constant::new(ConstantBinary(blob.clone())),
        &LitByte(b) => Constant::new(ConstantByte(b)),
        &LitChar(c) => Constant::new(ConstantChar(c)),
        &LitInt(value, ty) => Constant::new(ConstantInt(value, ty)),
        &LitFloat(ref is, ty) =>
            Constant::new(ConstantFloat(Cow::Borrowed(&*is), ty.into())),
        &LitFloatUnsuffixed(InternedString) =>
            Constant::new(ConstantFloat(Cow::Borrowed(&*is), FwAny)),
        &LitBool(b) => Constant::new(ConstantBool(b)),
    }
}

/// create `Some(ConstantVec(..))` of all constants, unless there is any
/// non-constant part
fn constant_vec(cx: &Context, vec: &[&Expr]) -> Option<Constant> {
    let mut parts = Vec::new();
    let mut resolved = false;
    for opt_part in vec {
        match constant(cx, opt_part) {
            Some(ref p) => {
                resolved |= p.needed_resolution;
                parts.push(p)
            },
            None => { return None; },
        }
    }
    Some(Constant {
        constant: ConstantVec(parts),
        needed_resolution: resolved
    })
}

fn constant_tup(cx: &Context, tup: &[&Expr]) -> Option<Constant> {
    let mut parts = Vec::new();
    let mut resolved = false;
    for opt_part in vec {
        match constant(cx, opt_part) {
            Some(ref p) => {
                resolved |= p.needed_resolution;
                parts.push(p)
            },
            None => { return None; },
        }
    }
    Some(Constant {
        constant: ConstantTuple(parts),
        needed_resolution: resolved
    })
}

/// lookup a possibly constant expression from a ExprPath
fn fetch_path(cx: &Context, e: &Expr) -> Option<Constant> {
    if let Some(&PathResolution { base_def: DefConst(id), ..}) =
            cx.tcx.def_map.borrow().get(&e.id) {
        lookup_const_by_id(cx.tcx, id, None).map(
            |l| Constant::new_resolved(constant(cx, l).constant))
    } else { None }
}

/// A block can only yield a constant if it only has one constant expression
fn constant_block(cx: &Context, block: &Block) -> Option<Constant> {
    if block.stmts.is_empty() {
        block.expr.map(|b| constant(cx, b))
    } else { None }
}

fn constant_if(cx: &Context, cond: &Expr, then: &Expr, otherwise: &Expr) ->
        Option<Constant> {
    if let Some(Constant{ constant: ConstantBool(b), needed_resolution: res }) =
            constant(cx, cond) {
        let part = constant(cx, if b { then } else { otherwise });
        Some(Constant {
            constant: part.constant,
            needed_resolution: res || part.needed_resolution,
        })
    } else { None }
}

fn constant_negate(o: Constant) -> Option<Constant> {
    Some(Constant{
        needed_resolution: o.needed_resolution,
        constant: match o.constant {
            &ConstantInt(value, ty) =>
                ConstantInt(value, match ty {
                    SignedIntLit(ity, sign) =>
                        SignedIntLit(ity, neg_sign(sign)),
                    UnsuffixedIntLit(sign) => UnsuffixedIntLit(neg_sign(sign)),
                    _ => { return None; },
                }),
            &LitFloat(ref is, ref ty) => ConstantFloat(neg_float_str(is), ty),
            _ => { return None; },
        }
    })
}

fn neg_sign(s: Sign) -> Sign {
    match s {
        Sign::Plus => Sign::Minus,
        Sign::Minus => Sign::Plus,
    }
}

fn neg_float_str(s: &InternedString) -> Cow<'static, str> {
    if s.startsWith('-') {
        Cow::Borrowed(s[1..])
    } else {
        Cow::Owned(format!("-{}", &*s))
    }
}

fn constant_binop(cx: &Context, op: BinOp, left: &Expr, right: &Expr)
        -> Option<Constant> {
    match op.node {
        //BiAdd,
        //BiSub,
        //BiMul,
        //BiDiv,
        //BiRem,
        BiAnd => constant_short_circuit(cx, left, right, false),
        BiOr => constant_short_circuit(cx, left, right, true),
        //BiBitXor,
        //BiBitAnd,
        //BiBitOr,
        //BiShl,
        //BiShr,
        //BiEq,
        //BiLt,
        //BiLe,
        //BiNe,
        //BiGe,
        //BiGt,
        _ => None,
    }
}

fn constant_binop_apply<F>(cx: &Context, left: &Expr, right: &Expr, op: F)
        -> Option<Constant>
where F: FnMut(ConstantVariant, ConstantVariant) -> Option<ConstantVariant> {
    constant(cx, left).and_then(|l| constant(cx, right).and_then(
        |r| Constant {
            needed_resolution: l.needed_resolution || r.needed_resolution,
            constant: op(l.constant, r.constant)
        }))
}

fn constant_short_circuit(cx: &Context, left: &Expr, right: &Expr, b: bool) ->
        Option<Constant> {
    let leftconst = constant(cx, left);
    if let ConstantBool(lbool) = leftconst.constant {
        if l == b {
            Some(leftconst)
        } else {
            let rightconst = constant(cx, right);
            if let ConstantBool(rbool) = rightconst.constant {
                Some(Constant {
                    constant: rightconst.constant,
                    needed_resolution: leftconst.needed_resolution ||
                                       rightconst.needed_resolution,
                })
            } else { None }
        }
    } else { None }
}
<|endoftext|>


<commit_before>/*!

*/

use backend::Facade;
use context::Context;
use ContextExt;
use version::Api;
use version::Version;
use gl;
use std::rc::Rc;
use std::mem;

/// Severity of a debug message.
#[derive(Clone, Copy, Debug, FromPrimitive, PartialEq, Eq)]
#[repr(u32)]
pub enum Severity {
    /// Anything that isn't an error or performance issue.
    Notification = gl::DEBUG_SEVERITY_NOTIFICATION,

    /// Redundant state-change performance warning, or unimportant undefined behavior.
    Low = gl::DEBUG_SEVERITY_LOW,

    /// Major performance warnings, shader compilation/linking warnings,
    /// or the use of deprecated functionality.
    Medium = gl::DEBUG_SEVERITY_MEDIUM,

    /// All OpenGL Errors, shader compilation/linking errors,
    /// or highly-dangerous undefined behavior.
    High = gl::DEBUG_SEVERITY_HIGH,
}

/// Source of a debug message.
#[derive(Clone, Copy, Debug, FromPrimitive)]
#[repr(u32)]
pub enum Source {
    /// Calls to the OpenGL API.
    Api = gl::DEBUG_SOURCE_API,

    /// Calls to a window-system API.
    WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM,

    /// A compiler for a shading language.
    ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER,

    /// An application associated with Openctxt.gl.
    ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY,

    /// Explicitly generated by Glium or the application.
    ///
    /// This should never happen, but is included here for completeness.
    Application = gl::DEBUG_SOURCE_APPLICATION,

    ///
    OtherSource = gl::DEBUG_SOURCE_OTHER,
}

/// Type of a debug message.
#[derive(Clone, Copy, Debug, FromPrimitive)]
#[repr(u32)]
pub enum MessageType {
    /// An error, typically from the API
    Error = gl::DEBUG_TYPE_ERROR,
    /// Some behavior marked deprecated has been used
    DeprecatedBehavior = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR,
    /// Something has invoked undefined behavior
    UndefinedBehavior = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR,
    /// Some functionality the user relies upon is not portable
    Portability = gl::DEBUG_TYPE_PORTABILITY,
    /// Code has triggered possible performance issues
    Performance = gl::DEBUG_TYPE_PERFORMANCE,
    /// Command stream annotation
    Marker = gl::DEBUG_TYPE_MARKER,
    /// Entering a debug group
    PushGroup = gl::DEBUG_TYPE_PUSH_GROUP,
    /// Leaving a debug group
    PopGroup = gl::DEBUG_TYPE_POP_GROUP,
    /// Any other event
    Other = gl::DEBUG_TYPE_OTHER,
}

/// Allows you to obtain the timestamp inside the OpenGL commands queue.
///
/// When you call functions in glium, they are not instantly executed. Instead they are
/// added in a commands queue that the backend executes asynchronously.
///
/// When you call `TimestampQuery::new`, a command is added to this list asking the
/// backend to send us the current timestamp. Thanks to this, you can know how much time
/// it takes to execute commands.
///
/// ## Example
///
/// ```no_run
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// let before = glium::debug::TimestampQuery::new(&display);
/// // do some stuff here
/// let after = glium::debug::TimestampQuery::new(&display);
///
/// match (after, before) {
///     (Some(after), Some(before)) => {
///         let elapsed = after.get() - before.get();
///         println!("Time it took to do stuff: {}", elapsed);
///     },
///     _ => ()
/// }
/// ```
///
pub struct TimestampQuery {
    context: Rc<Context>,
    id: gl::types::GLuint,
}

impl TimestampQuery {
    /// Creates a new `TimestampQuery`. Returns `None` if the backend doesn't support it.
    pub fn new<F>(facade: &F) -> Option<TimestampQuery> where F: Facade {
        let ctxt = facade.get_context().make_current();

        let id = if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut id = mem::uninitialized();
                ctxt.gl.GenQueries(1, &mut id);

                ctxt.gl.QueryCounter(id, gl::TIMESTAMP);

                Some(id)
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut id = mem::uninitialized();
                ctxt.gl.GenQueriesEXT(1, &mut id);

                ctxt.gl.QueryCounterEXT(id, gl::TIMESTAMP);

                Some(id)
            }

        } else {
            None
        };

        id.map(|q| TimestampQuery {
            context: facade.get_context().clone(),
            id: q
        })
    }

    /// Queries the counter to see if the timestamp is already available.
    ///
    /// It takes some time to retreive the value, during which you can execute other
    /// functions.
    pub fn is_ready(&self) -> bool {
        use std::mem;

        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectiv(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
                value != 0
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectivEXT(self.id, gl::QUERY_RESULT_AVAILABLE_EXT, &mut value);
                value != 0
            }

        } else {
            unreachable!();
        }
    }

    /// Returns the value of the timestamp. Blocks until it is available.
    ///
    /// This function doesn't block if `is_ready` returns true.
    pub fn get(self) -> u64 {
        use std::mem;

        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectui64v(self.id, gl::QUERY_RESULT, &mut value);
                ctxt.gl.DeleteQueries(1, [self.id].as_ptr());
                value
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectui64vEXT(self.id, gl::QUERY_RESULT_EXT, &mut value);
                ctxt.gl.DeleteQueriesEXT(1, [self.id].as_ptr());
                value
            }

        } else {
            unreachable!();
        }
    }
}
<commit_msg>Fix compilation on rust nightly<commit_after>/*!

*/

use backend::Facade;
use context::Context;
use ContextExt;
use version::Api;
use version::Version;
use gl;
use std::rc::Rc;
use std::mem;

/// Severity of a debug message.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum Severity {
    /// Anything that isn't an error or performance issue.
    Notification = gl::DEBUG_SEVERITY_NOTIFICATION,

    /// Redundant state-change performance warning, or unimportant undefined behavior.
    Low = gl::DEBUG_SEVERITY_LOW,

    /// Major performance warnings, shader compilation/linking warnings,
    /// or the use of deprecated functionality.
    Medium = gl::DEBUG_SEVERITY_MEDIUM,

    /// All OpenGL Errors, shader compilation/linking errors,
    /// or highly-dangerous undefined behavior.
    High = gl::DEBUG_SEVERITY_HIGH,
}

/// Source of a debug message.
#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum Source {
    /// Calls to the OpenGL API.
    Api = gl::DEBUG_SOURCE_API,

    /// Calls to a window-system API.
    WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM,

    /// A compiler for a shading language.
    ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER,

    /// An application associated with Openctxt.gl.
    ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY,

    /// Explicitly generated by Glium or the application.
    ///
    /// This should never happen, but is included here for completeness.
    Application = gl::DEBUG_SOURCE_APPLICATION,

    ///
    OtherSource = gl::DEBUG_SOURCE_OTHER,
}

/// Type of a debug message.
#[derive(Clone, Copy, Debug)]
#[repr(u32)]
pub enum MessageType {
    /// An error, typically from the API
    Error = gl::DEBUG_TYPE_ERROR,
    /// Some behavior marked deprecated has been used
    DeprecatedBehavior = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR,
    /// Something has invoked undefined behavior
    UndefinedBehavior = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR,
    /// Some functionality the user relies upon is not portable
    Portability = gl::DEBUG_TYPE_PORTABILITY,
    /// Code has triggered possible performance issues
    Performance = gl::DEBUG_TYPE_PERFORMANCE,
    /// Command stream annotation
    Marker = gl::DEBUG_TYPE_MARKER,
    /// Entering a debug group
    PushGroup = gl::DEBUG_TYPE_PUSH_GROUP,
    /// Leaving a debug group
    PopGroup = gl::DEBUG_TYPE_POP_GROUP,
    /// Any other event
    Other = gl::DEBUG_TYPE_OTHER,
}

/// Allows you to obtain the timestamp inside the OpenGL commands queue.
///
/// When you call functions in glium, they are not instantly executed. Instead they are
/// added in a commands queue that the backend executes asynchronously.
///
/// When you call `TimestampQuery::new`, a command is added to this list asking the
/// backend to send us the current timestamp. Thanks to this, you can know how much time
/// it takes to execute commands.
///
/// ## Example
///
/// ```no_run
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// let before = glium::debug::TimestampQuery::new(&display);
/// // do some stuff here
/// let after = glium::debug::TimestampQuery::new(&display);
///
/// match (after, before) {
///     (Some(after), Some(before)) => {
///         let elapsed = after.get() - before.get();
///         println!("Time it took to do stuff: {}", elapsed);
///     },
///     _ => ()
/// }
/// ```
///
pub struct TimestampQuery {
    context: Rc<Context>,
    id: gl::types::GLuint,
}

impl TimestampQuery {
    /// Creates a new `TimestampQuery`. Returns `None` if the backend doesn't support it.
    pub fn new<F>(facade: &F) -> Option<TimestampQuery> where F: Facade {
        let ctxt = facade.get_context().make_current();

        let id = if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut id = mem::uninitialized();
                ctxt.gl.GenQueries(1, &mut id);

                ctxt.gl.QueryCounter(id, gl::TIMESTAMP);

                Some(id)
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut id = mem::uninitialized();
                ctxt.gl.GenQueriesEXT(1, &mut id);

                ctxt.gl.QueryCounterEXT(id, gl::TIMESTAMP);

                Some(id)
            }

        } else {
            None
        };

        id.map(|q| TimestampQuery {
            context: facade.get_context().clone(),
            id: q
        })
    }

    /// Queries the counter to see if the timestamp is already available.
    ///
    /// It takes some time to retreive the value, during which you can execute other
    /// functions.
    pub fn is_ready(&self) -> bool {
        use std::mem;

        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectiv(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
                value != 0
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectivEXT(self.id, gl::QUERY_RESULT_AVAILABLE_EXT, &mut value);
                value != 0
            }

        } else {
            unreachable!();
        }
    }

    /// Returns the value of the timestamp. Blocks until it is available.
    ///
    /// This function doesn't block if `is_ready` returns true.
    pub fn get(self) -> u64 {
        use std::mem;

        let ctxt = self.context.make_current();

        if ctxt.version >= &Version(Api::Gl, 3, 2) {    // TODO: extension
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectui64v(self.id, gl::QUERY_RESULT, &mut value);
                ctxt.gl.DeleteQueries(1, [self.id].as_ptr());
                value
            }

        } else if ctxt.extensions.gl_ext_disjoint_timer_query {
            unsafe {
                let mut value = mem::uninitialized();
                ctxt.gl.GetQueryObjectui64vEXT(self.id, gl::QUERY_RESULT_EXT, &mut value);
                ctxt.gl.DeleteQueriesEXT(1, [self.id].as_ptr());
                value
            }

        } else {
            unreachable!();
        }
    }
}
<|endoftext|>