<commit_before>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    w.1.refresh();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();
    let mut current_pid : Option<String> = None;

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);
    let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    let mut kill_button = gtk::Button::new_with_label("End task").unwrap();

    left_tree.connect_cursor_changed(move |tree_view| {
        /*let mut path = gtk::TreePath::new().unwrap();
        tree_view.get_cursor(Some(&mut path), None);
        let mut iter = gtk::TreeIter::new();
        let model = tree_view.get_model().unwrap();

        if model.get_iter(&mut iter, &path) {
            current_pid = Some(model.get_value(&iter, 0).get_string().unwrap());
        }*/
        println!("current pid : {:?}", current_pid);
    });
    kill_button.set_sensitive(false);
    timeout::add(1500, update_window, &mut (&mut list_store, &mut sys));

    vertical_layout.add(&scroll);
    vertical_layout.add(&kill_button);
    window.add(&vertical_layout);
    window.show_all();
    gtk::main();
}
<commit_msg>Add closure working out variable modification<commit_after>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;
use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use std::ops::DerefMut;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    w.1.refresh();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();
    let mut current_pid : Rc<RefCell<Option<String>>> = Rc::new(RefCell::new(None));
    let mut current_pid1 = current_pid.clone();

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);
    let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    let mut kill_button = gtk::Button::new_with_label("End task").unwrap();

    left_tree.connect_cursor_changed(move |tree_view| {
        let mut path = gtk::TreePath::new().unwrap();
        tree_view.get_cursor(Some(&mut path), None);
        let mut iter = gtk::TreeIter::new();
        let model = tree_view.get_model().unwrap();

        if model.get_iter(&mut iter, &path) {
            let mut tmp = current_pid1.borrow_mut();
            *tmp = Some(model.get_value(&iter, 0).get_string().unwrap());
        }
        println!("current pid : {:?}", current_pid);
    });
    kill_button.set_sensitive(false);
    timeout::add(1500, update_window, &mut (&mut list_store, &mut sys));

    vertical_layout.add(&scroll);
    vertical_layout.add(&kill_button);
    window.add(&vertical_layout);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>//! A reader that manages namespace declarations found in the input and able
//! to resolve [qualified names] to [expanded names].
//!
//! [qualified names]: https://www.w3.org/TR/xml-names11/#dt-qualname
//! [expanded names]: https://www.w3.org/TR/xml-names11/#dt-expname

use std::io::BufRead;
use std::ops::{Deref, DerefMut};

use crate::errors::Result;
use crate::events::Event;
use crate::name::{LocalName, NamespaceResolver, QName, ResolveResult};
use crate::reader::{Reader, XmlSource};

/// A low level encoding-agnostic XML event reader that performs namespace resolution.
///
/// Consumes a [`BufRead`] and streams XML `Event`s.
pub struct NsReader<R> {
    /// An XML reader
    reader: Reader<R>,
    /// Buffer that contains names of namespace prefixes (the part between `xmlns:`
    /// and an `=`) and namespace values.
    buffer: Vec<u8>,
    /// A buffer to manage namespaces
    ns_resolver: NamespaceResolver,
    /// We cannot pop data from the namespace stack until returned `Empty` or `End`
    /// event will be processed by the user, so we only mark that we should that
    /// in the next [`Self::read_event_impl()`] call.
    pending_pop: bool,
}

impl<R> NsReader<R> {
    #[inline]
    fn new(reader: Reader<R>) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
            ns_resolver: NamespaceResolver::default(),
            pending_pop: false,
        }
    }
}

/// Getters
impl<R> NsReader<R> {
    /// Resolves a potentially qualified **event name** into (namespace name, local name).
    ///
    /// *Qualified* attribute names have the form `prefix:local-name` where the`prefix` is defined
    /// on any containing XML element via `xmlns:prefix="the:namespace:uri"`. The namespace prefix
    /// can be defined on the same element as the attribute in question.
    ///
    /// *Unqualified* event inherits the current *default namespace*.
    ///
    /// # Lifetimes
    ///
    /// - `'n`: lifetime of an element name
    #[inline]
    pub fn event_namespace<'n>(&self, name: QName<'n>) -> (ResolveResult, LocalName<'n>) {
        self.ns_resolver.resolve(name, &self.buffer, true)
    }

    /// Resolves a potentially qualified **attribute name** into (namespace name, local name).
    ///
    /// *Qualified* attribute names have the form `prefix:local-name` where the`prefix` is defined
    /// on any containing XML element via `xmlns:prefix="the:namespace:uri"`. The namespace prefix
    /// can be defined on the same element as the attribute in question.
    ///
    /// *Unqualified* attribute names do *not* inherit the current *default namespace*.
    ///
    /// # Lifetimes
    ///
    /// - `'n`: lifetime of an attribute
    #[inline]
    pub fn attribute_namespace<'n>(&self, name: QName<'n>) -> (ResolveResult, LocalName<'n>) {
        self.ns_resolver.resolve(name, &self.buffer, false)
    }
}

impl<R: BufRead> NsReader<R> {
    /// Reads the next event and resolves its namespace (if applicable).
    ///
    /// # Examples
    ///
    /// ```
    /// use std::str::from_utf8;
    /// use quick_xml::NsReader;
    /// use quick_xml::events::Event;
    /// use quick_xml::name::ResolveResult::*;
    ///
    /// let xml = r#"<x:tag1 xmlns:x="www.xxxx" xmlns:y="www.yyyy" att1 = "test">
    ///                 <y:tag2><!--Test comment-->Test</y:tag2>
    ///                 <y:tag2>Test 2</y:tag2>
    ///             </x:tag1>"#;
    /// let mut reader = NsReader::from_str(xml);
    /// reader.trim_text(true);
    /// let mut count = 0;
    /// let mut buf = Vec::new();
    /// let mut txt = Vec::new();
    /// loop {
    ///     match reader.read_namespaced_event(&mut buf) {
    ///         Ok((Bound(ns), Event::Start(e))) => {
    ///             count += 1;
    ///             match (ns.as_ref(), e.local_name().as_ref()) {
    ///                 (b"www.xxxx", b"tag1") => (),
    ///                 (b"www.yyyy", b"tag2") => (),
    ///                 (ns, n) => panic!("Namespace and local name mismatch"),
    ///             }
    ///             println!("Resolved namespace: {:?}", ns);
    ///         }
    ///         Ok((Unbound, Event::Start(_))) => {
    ///             panic!("Element not in any namespace")
    ///         },
    ///         Ok((Unknown(p), Event::Start(_))) => {
    ///             panic!("Undeclared namespace prefix {:?}", String::from_utf8(p))
    ///         }
    ///         Ok((_, Event::Text(e))) => {
    ///             txt.push(e.decode_and_unescape(&reader).unwrap().into_owned())
    ///         },
    ///         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
    ///         Ok((_, Event::Eof)) => break,
    ///         _ => (),
    ///     }
    ///     buf.clear();
    /// }
    /// println!("Found {} start events", count);
    /// println!("Text events: {:?}", txt);
    /// ```
    pub fn read_namespaced_event<'b>(
        &mut self,
        buf: &'b mut Vec<u8>,
    ) -> Result<(ResolveResult, Event<'b>)> {
        self.read_event_impl(buf)
    }
}

/// Private methods
impl<R> NsReader<R> {
    fn read_event_impl<'i, B>(&mut self, buf: B) -> Result<(ResolveResult, Event<'i>)>
    where
        R: XmlSource<'i, B>,
    {
        if self.pending_pop {
            self.ns_resolver.pop(&mut self.buffer);
            self.pending_pop = false;
        }
        match self.reader.read_event_impl(buf) {
            Ok(Event::Start(e)) => {
                self.ns_resolver.push(&e, &mut self.buffer);
                Ok((
                    self.ns_resolver.find(e.name(), &mut self.buffer),
                    Event::Start(e),
                ))
            }
            Ok(Event::Empty(e)) => {
                self.ns_resolver.push(&e, &mut self.buffer);
                // notify next `read_event_impl()` invocation that it needs to pop this
                // namespace scope
                self.pending_pop = true;
                Ok((
                    self.ns_resolver.find(e.name(), &mut self.buffer),
                    Event::Empty(e),
                ))
            }
            Ok(Event::End(e)) => {
                // notify next `read_event_impl()` invocation that it needs to pop this
                // namespace scope
                self.pending_pop = true;
                Ok((
                    self.ns_resolver.find(e.name(), &mut self.buffer),
                    Event::End(e),
                ))
            }
            Ok(e) => Ok((ResolveResult::Unbound, e)),
            Err(e) => Err(e),
        }
    }
}

impl<'i> NsReader<&'i [u8]> {
    /// Creates an XML reader from a string slice.
    #[inline]
    pub fn from_str(s: &'i str) -> Self {
        Self::new(Reader::from_str(s))
    }

    /// Creates an XML reader from a slice of bytes.
    #[inline]
    pub fn from_bytes(bytes: &'i [u8]) -> Self {
        Self::new(Reader::from_bytes(bytes))
    }
}

impl<R> Deref for NsReader<R> {
    type Target = Reader<R>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.reader
    }
}

impl<R> DerefMut for NsReader<R> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.reader
    }
}
<commit_msg>ns: Group unbounded impl blocks<commit_after>//! A reader that manages namespace declarations found in the input and able
//! to resolve [qualified names] to [expanded names].
//!
//! [qualified names]: https://www.w3.org/TR/xml-names11/#dt-qualname
//! [expanded names]: https://www.w3.org/TR/xml-names11/#dt-expname

use std::io::BufRead;
use std::ops::{Deref, DerefMut};

use crate::errors::Result;
use crate::events::Event;
use crate::name::{LocalName, NamespaceResolver, QName, ResolveResult};
use crate::reader::{Reader, XmlSource};

/// A low level encoding-agnostic XML event reader that performs namespace resolution.
///
/// Consumes a [`BufRead`] and streams XML `Event`s.
pub struct NsReader<R> {
    /// An XML reader
    reader: Reader<R>,
    /// Buffer that contains names of namespace prefixes (the part between `xmlns:`
    /// and an `=`) and namespace values.
    buffer: Vec<u8>,
    /// A buffer to manage namespaces
    ns_resolver: NamespaceResolver,
    /// We cannot pop data from the namespace stack until returned `Empty` or `End`
    /// event will be processed by the user, so we only mark that we should that
    /// in the next [`Self::read_event_impl()`] call.
    pending_pop: bool,
}

/// Private methods
impl<R> NsReader<R> {
    #[inline]
    fn new(reader: Reader<R>) -> Self {
        Self {
            reader,
            buffer: Vec::new(),
            ns_resolver: NamespaceResolver::default(),
            pending_pop: false,
        }
    }

    fn read_event_impl<'i, B>(&mut self, buf: B) -> Result<(ResolveResult, Event<'i>)>
    where
        R: XmlSource<'i, B>,
    {
        if self.pending_pop {
            self.ns_resolver.pop(&mut self.buffer);
            self.pending_pop = false;
        }
        match self.reader.read_event_impl(buf) {
            Ok(Event::Start(e)) => {
                self.ns_resolver.push(&e, &mut self.buffer);
                Ok((
                    self.ns_resolver.find(e.name(), &mut self.buffer),
                    Event::Start(e),
                ))
            }
            Ok(Event::Empty(e)) => {
                self.ns_resolver.push(&e, &mut self.buffer);
                // notify next `read_event_impl()` invocation that it needs to pop this
                // namespace scope
                self.pending_pop = true;
                Ok((
                    self.ns_resolver.find(e.name(), &mut self.buffer),
                    Event::Empty(e),
                ))
            }
            Ok(Event::End(e)) => {
                // notify next `read_event_impl()` invocation that it needs to pop this
                // namespace scope
                self.pending_pop = true;
                Ok((
                    self.ns_resolver.find(e.name(), &mut self.buffer),
                    Event::End(e),
                ))
            }
            Ok(e) => Ok((ResolveResult::Unbound, e)),
            Err(e) => Err(e),
        }
    }
}

/// Getters
impl<R> NsReader<R> {
    /// Resolves a potentially qualified **event name** into (namespace name, local name).
    ///
    /// *Qualified* attribute names have the form `prefix:local-name` where the`prefix` is defined
    /// on any containing XML element via `xmlns:prefix="the:namespace:uri"`. The namespace prefix
    /// can be defined on the same element as the attribute in question.
    ///
    /// *Unqualified* event inherits the current *default namespace*.
    ///
    /// # Lifetimes
    ///
    /// - `'n`: lifetime of an element name
    #[inline]
    pub fn event_namespace<'n>(&self, name: QName<'n>) -> (ResolveResult, LocalName<'n>) {
        self.ns_resolver.resolve(name, &self.buffer, true)
    }

    /// Resolves a potentially qualified **attribute name** into (namespace name, local name).
    ///
    /// *Qualified* attribute names have the form `prefix:local-name` where the`prefix` is defined
    /// on any containing XML element via `xmlns:prefix="the:namespace:uri"`. The namespace prefix
    /// can be defined on the same element as the attribute in question.
    ///
    /// *Unqualified* attribute names do *not* inherit the current *default namespace*.
    ///
    /// # Lifetimes
    ///
    /// - `'n`: lifetime of an attribute
    #[inline]
    pub fn attribute_namespace<'n>(&self, name: QName<'n>) -> (ResolveResult, LocalName<'n>) {
        self.ns_resolver.resolve(name, &self.buffer, false)
    }
}

impl<R: BufRead> NsReader<R> {
    /// Reads the next event and resolves its namespace (if applicable).
    ///
    /// # Examples
    ///
    /// ```
    /// use std::str::from_utf8;
    /// use quick_xml::NsReader;
    /// use quick_xml::events::Event;
    /// use quick_xml::name::ResolveResult::*;
    ///
    /// let xml = r#"<x:tag1 xmlns:x="www.xxxx" xmlns:y="www.yyyy" att1 = "test">
    ///                 <y:tag2><!--Test comment-->Test</y:tag2>
    ///                 <y:tag2>Test 2</y:tag2>
    ///             </x:tag1>"#;
    /// let mut reader = NsReader::from_str(xml);
    /// reader.trim_text(true);
    /// let mut count = 0;
    /// let mut buf = Vec::new();
    /// let mut txt = Vec::new();
    /// loop {
    ///     match reader.read_namespaced_event(&mut buf) {
    ///         Ok((Bound(ns), Event::Start(e))) => {
    ///             count += 1;
    ///             match (ns.as_ref(), e.local_name().as_ref()) {
    ///                 (b"www.xxxx", b"tag1") => (),
    ///                 (b"www.yyyy", b"tag2") => (),
    ///                 (ns, n) => panic!("Namespace and local name mismatch"),
    ///             }
    ///             println!("Resolved namespace: {:?}", ns);
    ///         }
    ///         Ok((Unbound, Event::Start(_))) => {
    ///             panic!("Element not in any namespace")
    ///         },
    ///         Ok((Unknown(p), Event::Start(_))) => {
    ///             panic!("Undeclared namespace prefix {:?}", String::from_utf8(p))
    ///         }
    ///         Ok((_, Event::Text(e))) => {
    ///             txt.push(e.decode_and_unescape(&reader).unwrap().into_owned())
    ///         },
    ///         Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
    ///         Ok((_, Event::Eof)) => break,
    ///         _ => (),
    ///     }
    ///     buf.clear();
    /// }
    /// println!("Found {} start events", count);
    /// println!("Text events: {:?}", txt);
    /// ```
    pub fn read_namespaced_event<'b>(
        &mut self,
        buf: &'b mut Vec<u8>,
    ) -> Result<(ResolveResult, Event<'b>)> {
        self.read_event_impl(buf)
    }
}

impl<'i> NsReader<&'i [u8]> {
    /// Creates an XML reader from a string slice.
    #[inline]
    pub fn from_str(s: &'i str) -> Self {
        Self::new(Reader::from_str(s))
    }

    /// Creates an XML reader from a slice of bytes.
    #[inline]
    pub fn from_bytes(bytes: &'i [u8]) -> Self {
        Self::new(Reader::from_bytes(bytes))
    }
}

impl<R> Deref for NsReader<R> {
    type Target = Reader<R>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.reader
    }
}

impl<R> DerefMut for NsReader<R> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.reader
    }
}
<|endoftext|>


<commit_before>use crate::config::Config;
use crate::errors::RunError;
use crate::traces::{CoverageStat, TraceMap};
use coveralls_api::*;
use log::{info, warn};
use std::collections::HashMap;
use std::path::Path;

fn get_git_info(manifest_path: &Path) -> Result<GitInfo, String> {
    let dir_path = manifest_path
        .parent()
        .ok_or_else(|| format!("failed to get parent for path: {}", manifest_path.display()))?;
    let repo = git2::Repository::discover(dir_path).map_err(|err| {
        format!(
            "failed to open git repository: {}: {}",
            dir_path.display(),
            err
        )
    })?;

    let head = repo
        .head()
        .map_err(|err| format!("failed to get repository head: {}", err))?;
    let branch = git2::Branch::wrap(head);
    let branch_name = branch
        .name()
        .map_err(|err| format!("failed to get branch name: {}", err))?;
    let get_string = |data: Option<&str>| match data {
        Some(str) => Ok(str.to_string()),
        None => Err("string is not valid utf-8".to_string()),
    };
    let branch_name = get_string(branch_name)?;
    let commit = repo
        .head()
        .unwrap()
        .peel_to_commit()
        .map_err(|err| format!("failed to get commit: {}", err))?;

    let author = commit.author();
    let committer = commit.committer();
    Ok(GitInfo {
        head: Head {
            id: commit.id().to_string(),
            author_name: get_string(author.name())?,
            author_email: get_string(author.email())?,
            committer_name: get_string(committer.name())?,
            committer_email: get_string(committer.email())?,
            message: get_string(commit.message())?,
        },
        branch: branch_name,
        remotes: Vec::new(),
    })
}

pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
    if let Some(ref key) = config.coveralls {
        let id = match config.ci_tool {
            Some(ref service) => Some(Identity::ServiceToken(Service {
                name: service.clone(),
                job_id: Some(key.clone()),
                branch: None,
                build_url: None,
                number: None,
                pull_request: None,
            })),
            _ => Identity::best_match(),
        };

        let id = match id {
            Some(i) => i,
            None => Identity::RepoToken(key.clone()),
        };

        let mut report = CoverallsReport::new(id);
        for file in &coverage_data.files() {
            let rel_path = config.strip_project_path(file);
            let mut lines: HashMap<usize, usize> = HashMap::new();
            let fcov = coverage_data.get_child_traces(file);

            for c in &fcov {
                match c.stats {
                    CoverageStat::Line(hits) => {
                        lines.insert(c.line as usize, hits as usize);
                    }
                    _ => {
                        info!("Support for coverage statistic not implemented or supported for coveralls.io");
                    }
                }
            }
            if let Ok(source) = Source::new(&rel_path, file, &lines, &None, false) {
                report.add_source(source);
            }
        }

        match get_git_info(&config.manifest) {
            Ok(git_info) => {
                report.set_detailed_git_info(git_info);
                info!("Git info collected");
            }
            Err(err) => warn!("Failed to collect git info: {}", err),
        }

        let res = match config.report_uri {
            Some(ref uri) => {
                info!("Sending report to endpoint: {}", uri);
                report.send_to_endpoint(uri)
            }
            None => {
                info!("Sending coverage data to coveralls.io");
                report.send_to_coveralls()
            }
        };

        match res {
            Ok(_) => Ok(()),
            Err(e) => Err(RunError::CovReport(format!("Coveralls send failed. {}", e))),
        }
    } else {
        Err(RunError::CovReport(
            "No coveralls key specified.".to_string(),
        ))
    }
}
<commit_msg>Added debug coveralls report file save.<commit_after>use crate::config::Config;
use crate::errors::RunError;
use crate::traces::{CoverageStat, TraceMap};
use coveralls_api::*;
use log::{info, warn};
use std::collections::HashMap;
use std::path::Path;
use std::fs;

fn get_git_info(manifest_path: &Path) -> Result<GitInfo, String> {
    let dir_path = manifest_path
        .parent()
        .ok_or_else(|| format!("failed to get parent for path: {}", manifest_path.display()))?;
    let repo = git2::Repository::discover(dir_path).map_err(|err| {
        format!(
            "failed to open git repository: {}: {}",
            dir_path.display(),
            err
        )
    })?;

    let head = repo
        .head()
        .map_err(|err| format!("failed to get repository head: {}", err))?;
    let branch = git2::Branch::wrap(head);
    let branch_name = branch
        .name()
        .map_err(|err| format!("failed to get branch name: {}", err))?;
    let get_string = |data: Option<&str>| match data {
        Some(str) => Ok(str.to_string()),
        None => Err("string is not valid utf-8".to_string()),
    };
    let branch_name = get_string(branch_name)?;
    let commit = repo
        .head()
        .unwrap()
        .peel_to_commit()
        .map_err(|err| format!("failed to get commit: {}", err))?;

    let author = commit.author();
    let committer = commit.committer();
    Ok(GitInfo {
        head: Head {
            id: commit.id().to_string(),
            author_name: get_string(author.name())?,
            author_email: get_string(author.email())?,
            committer_name: get_string(committer.name())?,
            committer_email: get_string(committer.email())?,
            message: get_string(commit.message())?,
        },
        branch: branch_name,
        remotes: Vec::new(),
    })
}

pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
    if let Some(ref key) = config.coveralls {
        let id = match config.ci_tool {
            Some(ref service) => Some(Identity::ServiceToken(Service {
                name: service.clone(),
                job_id: Some(key.clone()),
                branch: None,
                build_url: None,
                number: None,
                pull_request: None,
            })),
            _ => Identity::best_match(),
        };

        let id = match id {
            Some(i) => i,
            None => Identity::RepoToken(key.clone()),
        };

        let mut report = CoverallsReport::new(id);
        for file in &coverage_data.files() {
            let rel_path = config.strip_project_path(file);
            let mut lines: HashMap<usize, usize> = HashMap::new();
            let fcov = coverage_data.get_child_traces(file);

            for c in &fcov {
                match c.stats {
                    CoverageStat::Line(hits) => {
                        lines.insert(c.line as usize, hits as usize);
                    }
                    _ => {
                        info!("Support for coverage statistic not implemented or supported for coveralls.io");
                    }
                }
            }
            if let Ok(source) = Source::new(&rel_path, file, &lines, &None, false) {
                report.add_source(source);
            }
        }

        match get_git_info(&config.manifest) {
            Ok(git_info) => {
                report.set_detailed_git_info(git_info);
                info!("Git info collected");
            }
            Err(err) => warn!("Failed to collect git info: {}", err),
        }

        let res = match config.report_uri {
            Some(ref uri) => {
                info!("Sending report to endpoint: {}", uri);
                report.send_to_endpoint(uri)
            }
            None => {
                info!("Sending coverage data to coveralls.io");
                report.send_to_coveralls()
            }
        };
        if config.debug {
            if let Ok(text) = serde_json::to_string(&report) {
                info!("Attempting to write coveralls report to coveralls.json");
                let _ = fs::write("coveralls.json", text);
            } else {
                warn!("Failed to serialise coverage report");
            }
        }
        match res {
            Ok(_) => Ok(()),
            Err(e) => Err(RunError::CovReport(format!("Coveralls send failed. {}", e))),
        }
    } else {
        Err(RunError::CovReport(
            "No coveralls key specified.".to_string(),
        ))
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}
        }
    ) => {
        ordered_passes_renderpass!{
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: []
                }
            ]
        }
    }
}

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:ty,
                    $(initial_layout: $init_layout:expr,)*
                    $(final_layout: $final_layout:expr,)*
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]
                }
            ),*
        ]
    ) => {
        use std::sync::Arc;
        use $crate::device::Device;
        use $crate::format::ClearValue;
        use $crate::framebuffer::UnsafeRenderPass;
        use $crate::framebuffer::RenderPass;
        use $crate::framebuffer::RenderPassDesc;
        use $crate::framebuffer::RenderPassClearValues;
        use $crate::framebuffer::RenderPassAttachmentsList;
        use $crate::framebuffer::LayoutAttachmentDescription;
        use $crate::framebuffer::LayoutPassDescription;
        use $crate::framebuffer::LayoutPassDependencyDescription;
        use $crate::framebuffer::FramebufferCreationError;
        use $crate::framebuffer::RenderPassCreationError;
        use $crate::framebuffer::framebuffer::IntoAttachmentsList;
        use $crate::image::Layout;
        use $crate::image::traits::ImageView;
        use $crate::image::traits::ImageView;
        use $crate::sync::AccessFlagBits;
        use $crate::sync::PipelineStages;

        #[derive(Debug, Clone)]
        pub struct Formats {
            $(
                pub $atch_name: ($format, u32),
            )*
        }

        pub struct CustomRenderPass {
            render_pass: UnsafeRenderPass,
            formats: Formats,
        }

        impl CustomRenderPass {
            pub fn raw(device: &Arc<Device>, formats: &Formats)
                       -> Result<CustomRenderPass, RenderPassCreationError>
            {
                #![allow(unsafe_code)]

                let rp = try!(unsafe {
                    let atch = (0 .. num_attachments()).map(|p| attachment(formats, p).unwrap());
                    let subpasses = (0 .. num_subpasses()).map(|p| subpass(p).unwrap());
                    let deps = (0 .. num_dependencies()).map(|p| dependency(p).unwrap());
                    // TODO: shouldn't collect
                    UnsafeRenderPass::new(device, atch.collect::<Vec<_>>().into_iter(),
                                          subpasses.collect::<Vec<_>>().into_iter(),
                                          deps.collect::<Vec<_>>().into_iter())
                });

                Ok(CustomRenderPass {
                    render_pass: rp,
                    formats: formats.clone(),
                })
            }

            #[inline]
            pub fn new(device: &Arc<Device>, formats: &Formats)
                       -> Result<Arc<CustomRenderPass>, RenderPassCreationError>
            {
                Ok(Arc::new(try!(CustomRenderPass::raw(device, formats))))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl RenderPass for CustomRenderPass {
            #[inline]
            fn inner(&self) -> &UnsafeRenderPass {
                &self.render_pass
            }
        }

        #[allow(unsafe_code)]
        unsafe impl RenderPassDesc for CustomRenderPass {
            #[inline]
            fn num_attachments(&self) -> usize {
                num_attachments()
            }

            #[inline]
            fn attachment(&self, id: usize) -> Option<LayoutAttachmentDescription> {
                attachment(&self.formats, id)
            }

            #[inline]
            fn num_subpasses(&self) -> usize {
                num_subpasses()
            }

            #[inline]
            fn subpass(&self, id: usize) -> Option<LayoutPassDescription> {
                subpass(id)
            }

            #[inline]
            fn num_dependencies(&self) -> usize {
                num_dependencies()
            }

            #[inline]
            fn dependency(&self, id: usize) -> Option<LayoutPassDependencyDescription> {
                dependency(id)
            }
        }

        #[inline]
        fn num_attachments() -> usize {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]
            let mut num = 0;
            $(let $atch_name = num; num += 1;)*
            num
        }

        #[inline]
        fn attachment(formats: &Formats, id: usize) -> Option<LayoutAttachmentDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            let mut num = 0;

            $({
                if id == num {
                    let (initial_layout, final_layout) = attachment_layouts(num);

                    return Some($crate::framebuffer::LayoutAttachmentDescription {
                        format: $crate::format::FormatDesc::format(&formats.$atch_name.0),
                        samples: formats.$atch_name.1,
                        load: $crate::framebuffer::LoadOp::$load,
                        store: $crate::framebuffer::StoreOp::$store,
                        initial_layout: initial_layout,
                        final_layout: final_layout,
                    });
                }

                num += 1;
            })*

            None
        }

        #[inline]
        fn num_subpasses() -> usize {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]
            let mut num = 0;
            $($(let $color_atch = num;)* num += 1;)*
            num
        }

        #[inline]
        fn subpass(id: usize) -> Option<LayoutPassDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            let mut cur_pass_num = 0;

            $({
                if id == cur_pass_num {
                    let mut depth = None;
                    $(
                        depth = Some(($depth_atch, Layout::DepthStencilAttachmentOptimal));
                    )*

                    return Some(LayoutPassDescription {
                        color_attachments: vec![
                            $(
                                ($color_atch, Layout::ColorAttachmentOptimal)
                            ),*
                        ],
                        depth_stencil: depth,
                        input_attachments: vec![
                            $(
                                ($input_atch, Layout::ShaderReadOnlyOptimal)
                            ),*
                        ],
                        resolve_attachments: vec![],
                        preserve_attachments: (0 .. attachment_num).filter(|&a| {
                            $(if a == $color_atch { return false; })*
                            $(if a == $depth_atch { return false; })*
                            $(if a == $input_atch { return false; })*
                            true
                        }).collect()
                    });
                }

                cur_pass_num += 1;
            })*

            None
        }

        #[inline]
        fn num_dependencies() -> usize {
            num_subpasses().saturating_sub(1)
        }

        #[inline]
        fn dependency(id: usize) -> Option<LayoutPassDependencyDescription> {
            let num_passes = num_subpasses();

            if id + 1 >= num_passes {
                return None;
            }

            Some(LayoutPassDependencyDescription {
                source_subpass: id,
                destination_subpass: id + 1,
                src_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                dst_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                src_access: AccessFlagBits::all(),         // TODO: correct values
                dst_access: AccessFlagBits::all(),         // TODO: correct values
                by_region: true,            // TODO: correct values
            })
        }

        /// Returns the initial and final layout of an attachment, given its num.
        ///
        /// The value always correspond to the first and last usages of an attachment.
        fn attachment_layouts(num: usize) -> (Layout, Layout) {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            let mut initial_layout = None;
            let mut final_layout = None;

            $({
                $(
                    if $depth_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::DepthStencilAttachmentOptimal);
                        }
                        final_layout = Some(Layout::DepthStencilAttachmentOptimal);
                    }
                )*

                $(
                    if $color_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ColorAttachmentOptimal);
                        }
                        final_layout = Some(Layout::ColorAttachmentOptimal);
                    }
                )*

                $(
                    if $input_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ShaderReadOnlyOptimal);
                        }
                        final_layout = Some(Layout::ShaderReadOnlyOptimal);
                    }
                )*
            })*

            $(if $atch_name == num {
                $(initial_layout = Some($init_layout);)*
                $(final_layout = Some($final_layout);)*
            })*

            (initial_layout.unwrap(), final_layout.unwrap())
        }

        #[allow(non_camel_case_types)]
        pub struct AList<$($atch_name),*> {
            $(
                pub $atch_name: $atch_name,
            )*
        }

        impl<$($atch_name: ImageView),*> IntoAttachmentsList for AList<$($atch_name),*> {
            type List = <($($atch_name,)*) as IntoAttachmentsList>::List;

            fn into_attachments_list(self) -> Self::List {
                IntoAttachmentsList::into_attachments_list(($(self.$atch_name,)*))
            }
        }

        #[allow(non_camel_case_types)]
        #[allow(unsafe_code)]
        unsafe impl<$($atch_name: ImageView),*> RenderPassAttachmentsList<AList<$($atch_name),*>> for CustomRenderPass {
            #[inline]
            fn check_attachments_list(&self, l: &AList<$($atch_name),*>) -> Result<(), FramebufferCreationError> {
                #![allow(unused_assignments)]

                $({
                    if !l.$atch_name.identity_swizzle() {
                        return Err(FramebufferCreationError::AttachmentNotIdentitySwizzled);
                    }
                })*

                Ok(())
            }
        }

        ordered_passes_renderpass!{__impl_clear_values__ [0] [] [$($atch_name $format, $load,)*] }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, Clear, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)* $atch_name [$num] $format,] [$($rest)*] }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, $misc:ident, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)*] [$($rest)*] }
    };

    (__impl_clear_values__ [$total:expr] [$($atch:ident [$num:expr] $format:ty,)+] []) => {
        #[allow(non_camel_case_types)]
        pub struct ClearValues<$($atch),+> {
            $(
                pub $atch: $atch,
            )+
        }

        #[allow(non_camel_case_types)]
        #[allow(unsafe_code)]
        unsafe impl<$($atch: Clone + Into<<$format as $crate::format::FormatDesc>::ClearValue>),*>
            RenderPassClearValues<ClearValues<$($atch),*>> for CustomRenderPass
        {
            type ClearValuesIter = ClearValuesIter<$($atch),+>;

            #[inline]
            fn convert_clear_values(&self, val: ClearValues<$($atch),+>)
                                    -> ClearValuesIter<$($atch),+>
            {
                ClearValuesIter(self.formats.clone(), val, 0)
            }
        }

        #[allow(non_camel_case_types)]
        pub struct ClearValuesIter<$($atch),*>(Formats, ClearValues<$($atch),+>, usize);

        #[allow(non_camel_case_types)]
        impl<$($atch: Clone + Into<<$format as $crate::format::FormatDesc>::ClearValue>),+>
            Iterator for ClearValuesIter<$($atch),+>
        {
            type Item = $crate::format::ClearValue;

            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                use $crate::format::FormatDesc;

                $(
                    if self.2 == $num {
                        self.2 += 1;
                        return Some((self.0).$atch.0.decode_clear_value((self.1).$atch.clone().into()));
                    }
                )+

                if self.2 >= $total {
                    None
                } else {
                    Some(ClearValue::None)
                }
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                let len = $total - self.2;
                (len, Some(len))
            }
        }

        #[allow(non_camel_case_types)]
        impl<$($atch: Clone + Into<<$format as $crate::format::FormatDesc>::ClearValue>),+>
            ExactSizeIterator for ClearValuesIter<$($atch),+> {}
    };

    (__impl_clear_values__ [$total:expr] [] []) => {
        pub type ClearValues = ();

        #[allow(unsafe_code)]
        unsafe impl RenderPassClearValues<()> for CustomRenderPass {
            type ClearValuesIter = ClearValuesIter;

            #[inline]
            fn convert_clear_values(&self, val: ()) -> ClearValuesIter {
                ClearValuesIter
            }
        }

        pub struct ClearValuesIter;

        impl Iterator for ClearValuesIter {
            type Item = $crate::format::ClearValue;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> { None }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) { (0, Some(0)) }
        }

        impl ExactSizeIterator for ClearValuesIter {}
    };
}
<commit_msg>Fix buggy render pass macro<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! single_pass_renderpass {
    (
        attachments: { $($a:tt)* },
        pass: {
            color: [$($color_atch:ident),*],
            depth_stencil: {$($depth_atch:ident)*}
        }
    ) => {
        ordered_passes_renderpass!{
            attachments: { $($a)* },
            passes: [
                {
                    color: [$($color_atch),*],
                    depth_stencil: {$($depth_atch)*},
                    input: []
                }
            ]
        }
    }
}

/// Builds a `CustomRenderPass` object that provides a safe wrapper around `UnsafeRenderPass`.
#[macro_export]
macro_rules! ordered_passes_renderpass {
    (
        attachments: {
            $(
                $atch_name:ident: {
                    load: $load:ident,
                    store: $store:ident,
                    format: $format:ty,
                    $(initial_layout: $init_layout:expr,)*
                    $(final_layout: $final_layout:expr,)*
                }
            ),*
        },
        passes: [
            $(
                {
                    color: [$($color_atch:ident),*],
                    depth_stencil: {$($depth_atch:ident)*},
                    input: [$($input_atch:ident),*]
                }
            ),*
        ]
    ) => {
        use std::sync::Arc;
        use $crate::device::Device;
        use $crate::format::ClearValue;
        use $crate::framebuffer::UnsafeRenderPass;
        use $crate::framebuffer::RenderPass;
        use $crate::framebuffer::RenderPassDesc;
        use $crate::framebuffer::RenderPassClearValues;
        use $crate::framebuffer::RenderPassAttachmentsList;
        use $crate::framebuffer::LayoutAttachmentDescription;
        use $crate::framebuffer::LayoutPassDescription;
        use $crate::framebuffer::LayoutPassDependencyDescription;
        use $crate::framebuffer::FramebufferCreationError;
        use $crate::framebuffer::RenderPassCreationError;
        use $crate::framebuffer::framebuffer::IntoAttachmentsList;
        use $crate::image::Layout;
        use $crate::image::traits::ImageView;
        use $crate::sync::AccessFlagBits;
        use $crate::sync::PipelineStages;

        #[derive(Debug, Clone)]
        pub struct Formats {
            $(
                pub $atch_name: ($format, u32),
            )*
        }

        pub struct CustomRenderPass {
            render_pass: UnsafeRenderPass,
            formats: Formats,
        }

        impl CustomRenderPass {
            pub fn raw(device: &Arc<Device>, formats: &Formats)
                       -> Result<CustomRenderPass, RenderPassCreationError>
            {
                #![allow(unsafe_code)]

                let rp = try!(unsafe {
                    let atch = (0 .. num_attachments()).map(|p| attachment(formats, p).unwrap());
                    let subpasses = (0 .. num_subpasses()).map(|p| subpass(p).unwrap());
                    let deps = (0 .. num_dependencies()).map(|p| dependency(p).unwrap());
                    // TODO: shouldn't collect
                    UnsafeRenderPass::new(device, atch.collect::<Vec<_>>().into_iter(),
                                          subpasses.collect::<Vec<_>>().into_iter(),
                                          deps.collect::<Vec<_>>().into_iter())
                });

                Ok(CustomRenderPass {
                    render_pass: rp,
                    formats: formats.clone(),
                })
            }

            #[inline]
            pub fn new(device: &Arc<Device>, formats: &Formats)
                       -> Result<Arc<CustomRenderPass>, RenderPassCreationError>
            {
                Ok(Arc::new(try!(CustomRenderPass::raw(device, formats))))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl RenderPass for CustomRenderPass {
            #[inline]
            fn inner(&self) -> &UnsafeRenderPass {
                &self.render_pass
            }
        }

        #[allow(unsafe_code)]
        unsafe impl RenderPassDesc for CustomRenderPass {
            #[inline]
            fn num_attachments(&self) -> usize {
                num_attachments()
            }

            #[inline]
            fn attachment(&self, id: usize) -> Option<LayoutAttachmentDescription> {
                attachment(&self.formats, id)
            }

            #[inline]
            fn num_subpasses(&self) -> usize {
                num_subpasses()
            }

            #[inline]
            fn subpass(&self, id: usize) -> Option<LayoutPassDescription> {
                subpass(id)
            }

            #[inline]
            fn num_dependencies(&self) -> usize {
                num_dependencies()
            }

            #[inline]
            fn dependency(&self, id: usize) -> Option<LayoutPassDependencyDescription> {
                dependency(id)
            }
        }

        #[inline]
        fn num_attachments() -> usize {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]
            let mut num = 0;
            $(let $atch_name = num; num += 1;)*
            num
        }

        #[inline]
        fn attachment(formats: &Formats, id: usize) -> Option<LayoutAttachmentDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]

            let mut num = 0;

            $({
                if id == num {
                    let (initial_layout, final_layout) = attachment_layouts(num);

                    return Some($crate::framebuffer::LayoutAttachmentDescription {
                        format: $crate::format::FormatDesc::format(&formats.$atch_name.0),
                        samples: formats.$atch_name.1,
                        load: $crate::framebuffer::LoadOp::$load,
                        store: $crate::framebuffer::StoreOp::$store,
                        initial_layout: initial_layout,
                        final_layout: final_layout,
                    });
                }

                num += 1;
            })*

            None
        }

        #[inline]
        fn num_subpasses() -> usize {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]
            let mut num = 0;
            $($(let $color_atch = num;)* num += 1;)*
            num
        }

        #[inline]
        fn subpass(id: usize) -> Option<LayoutPassDescription> {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            let mut cur_pass_num = 0;

            $({
                if id == cur_pass_num {
                    let mut depth = None;
                    $(
                        depth = Some(($depth_atch, Layout::DepthStencilAttachmentOptimal));
                    )*

                    return Some(LayoutPassDescription {
                        color_attachments: vec![
                            $(
                                ($color_atch, Layout::ColorAttachmentOptimal)
                            ),*
                        ],
                        depth_stencil: depth,
                        input_attachments: vec![
                            $(
                                ($input_atch, Layout::ShaderReadOnlyOptimal)
                            ),*
                        ],
                        resolve_attachments: vec![],
                        preserve_attachments: (0 .. attachment_num).filter(|&a| {
                            $(if a == $color_atch { return false; })*
                            $(if a == $depth_atch { return false; })*
                            $(if a == $input_atch { return false; })*
                            true
                        }).collect()
                    });
                }

                cur_pass_num += 1;
            })*

            None
        }

        #[inline]
        fn num_dependencies() -> usize {
            num_subpasses().saturating_sub(1)
        }

        #[inline]
        fn dependency(id: usize) -> Option<LayoutPassDependencyDescription> {
            let num_passes = num_subpasses();

            if id + 1 >= num_passes {
                return None;
            }

            Some(LayoutPassDependencyDescription {
                source_subpass: id,
                destination_subpass: id + 1,
                src_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                dst_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() },         // TODO: correct values
                src_access: AccessFlagBits::all(),         // TODO: correct values
                dst_access: AccessFlagBits::all(),         // TODO: correct values
                by_region: true,            // TODO: correct values
            })
        }

        /// Returns the initial and final layout of an attachment, given its num.
        ///
        /// The value always correspond to the first and last usages of an attachment.
        fn attachment_layouts(num: usize) -> (Layout, Layout) {
            #![allow(unused_assignments)]
            #![allow(unused_mut)]
            #![allow(unused_variables)]

            let mut attachment_num = 0;
            $(
                let $atch_name = attachment_num;
                attachment_num += 1;
            )*

            let mut initial_layout = None;
            let mut final_layout = None;

            $({
                $(
                    if $depth_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::DepthStencilAttachmentOptimal);
                        }
                        final_layout = Some(Layout::DepthStencilAttachmentOptimal);
                    }
                )*

                $(
                    if $color_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ColorAttachmentOptimal);
                        }
                        final_layout = Some(Layout::ColorAttachmentOptimal);
                    }
                )*

                $(
                    if $input_atch == num {
                        if initial_layout.is_none() {
                            initial_layout = Some(Layout::ShaderReadOnlyOptimal);
                        }
                        final_layout = Some(Layout::ShaderReadOnlyOptimal);
                    }
                )*
            })*

            $(if $atch_name == num {
                $(initial_layout = Some($init_layout);)*
                $(final_layout = Some($final_layout);)*
            })*

            (initial_layout.unwrap(), final_layout.unwrap())
        }

        #[allow(non_camel_case_types)]
        pub struct AList<$($atch_name),*> {
            $(
                pub $atch_name: $atch_name,
            )*
        }

        impl<$($atch_name: ImageView),*> IntoAttachmentsList for AList<$($atch_name),*> {
            type List = <($($atch_name,)*) as IntoAttachmentsList>::List;

            fn into_attachments_list(self) -> Self::List {
                IntoAttachmentsList::into_attachments_list(($(self.$atch_name,)*))
            }
        }

        #[allow(non_camel_case_types)]
        #[allow(unsafe_code)]
        unsafe impl<$($atch_name: ImageView),*> RenderPassAttachmentsList<AList<$($atch_name),*>> for CustomRenderPass {
            #[inline]
            fn check_attachments_list(&self, l: &AList<$($atch_name),*>) -> Result<(), FramebufferCreationError> {
                #![allow(unused_assignments)]

                $({
                    if !l.$atch_name.identity_swizzle() {
                        return Err(FramebufferCreationError::AttachmentNotIdentitySwizzled);
                    }
                })*

                Ok(())
            }
        }

        ordered_passes_renderpass!{__impl_clear_values__ [0] [] [$($atch_name $format, $load,)*] }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, Clear, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)* $atch_name [$num] $format,] [$($rest)*] }
    };

    (__impl_clear_values__ [$num:expr] [$($s:tt)*] [$atch_name:ident $format:ty, $misc:ident, $($rest:tt)*]) => {
        ordered_passes_renderpass!{__impl_clear_values__ [$num+1] [$($s)*] [$($rest)*] }
    };

    (__impl_clear_values__ [$total:expr] [$($atch:ident [$num:expr] $format:ty,)+] []) => {
        #[allow(non_camel_case_types)]
        pub struct ClearValues<$($atch),+> {
            $(
                pub $atch: $atch,
            )+
        }

        #[allow(non_camel_case_types)]
        #[allow(unsafe_code)]
        unsafe impl<$($atch: Clone + Into<<$format as $crate::format::FormatDesc>::ClearValue>),*>
            RenderPassClearValues<ClearValues<$($atch),*>> for CustomRenderPass
        {
            type ClearValuesIter = ClearValuesIter<$($atch),+>;

            #[inline]
            fn convert_clear_values(&self, val: ClearValues<$($atch),+>)
                                    -> ClearValuesIter<$($atch),+>
            {
                ClearValuesIter(self.formats.clone(), val, 0)
            }
        }

        #[allow(non_camel_case_types)]
        pub struct ClearValuesIter<$($atch),*>(Formats, ClearValues<$($atch),+>, usize);

        #[allow(non_camel_case_types)]
        impl<$($atch: Clone + Into<<$format as $crate::format::FormatDesc>::ClearValue>),+>
            Iterator for ClearValuesIter<$($atch),+>
        {
            type Item = $crate::format::ClearValue;

            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                use $crate::format::FormatDesc;

                $(
                    if self.2 == $num {
                        self.2 += 1;
                        return Some((self.0).$atch.0.decode_clear_value((self.1).$atch.clone().into()));
                    }
                )+

                if self.2 >= $total {
                    None
                } else {
                    Some(ClearValue::None)
                }
            }

            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                let len = $total - self.2;
                (len, Some(len))
            }
        }

        #[allow(non_camel_case_types)]
        impl<$($atch: Clone + Into<<$format as $crate::format::FormatDesc>::ClearValue>),+>
            ExactSizeIterator for ClearValuesIter<$($atch),+> {}
    };

    (__impl_clear_values__ [$total:expr] [] []) => {
        pub type ClearValues = ();

        #[allow(unsafe_code)]
        unsafe impl RenderPassClearValues<()> for CustomRenderPass {
            type ClearValuesIter = ClearValuesIter;

            #[inline]
            fn convert_clear_values(&self, val: ()) -> ClearValuesIter {
                ClearValuesIter
            }
        }

        pub struct ClearValuesIter;

        impl Iterator for ClearValuesIter {
            type Item = $crate::format::ClearValue;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> { None }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) { (0, Some(0)) }
        }

        impl ExactSizeIterator for ClearValuesIter {}
    };
}
<|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/. */

use canvas_traits::webgl::WebGLError::*;
use dom::bindings::root::DomRoot;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom::webgltexture::WebGLTexture;
use std::{self, fmt};
use super::WebGLValidator;
use super::types::{TexImageTarget, TexDataType, TexFormat};

/// The errors that the texImage* family of functions can generate.
#[derive(Debug)]
pub enum TexImageValidationError {
    /// An invalid texture target was passed, it contains the invalid target.
    InvalidTextureTarget(u32),
    /// The passed texture target was not bound.
    TextureTargetNotBound(u32),
    /// Invalid texture dimensions were given.
    InvalidCubicTextureDimensions,
    /// A negative level was passed.
    NegativeLevel,
    /// A level too high to be allowed by the implementation was passed.
    LevelTooHigh,
    /// A negative width and height was passed.
    NegativeDimension,
    /// A bigger with and height were passed than what the implementation
    /// allows.
    TextureTooBig,
    /// An invalid data type was passed.
    InvalidDataType,
    /// An invalid texture format was passed.
    InvalidTextureFormat,
    /// Format did not match internal_format.
    TextureFormatMismatch,
    /// Invalid data type for the given format.
    InvalidTypeForFormat,
    /// Invalid border
    InvalidBorder,
    /// Expected a power of two texture.
    NonPotTexture,
}

impl std::error::Error for TexImageValidationError {
    fn description(&self) -> &str {
        use self::TexImageValidationError::*;
        match *self {
            InvalidTextureTarget(_)
                => "Invalid texture target",
            TextureTargetNotBound(_)
                => "Texture was not bound",
            InvalidCubicTextureDimensions
                => "Invalid dimensions were given for a cubic texture target",
            NegativeLevel
                => "A negative level was passed",
            LevelTooHigh
                => "Level too high",
            NegativeDimension
                => "Negative dimensions were passed",
            TextureTooBig
                => "Dimensions given are too big",
            InvalidDataType
                => "Invalid data type",
            InvalidTextureFormat
                => "Invalid texture format",
            TextureFormatMismatch
                => "Texture format mismatch",
            InvalidTypeForFormat
                => "Invalid type for the given format",
            InvalidBorder
                => "Invalid border",
            NonPotTexture
                => "Expected a power of two texture",
        }
    }
}

impl fmt::Display for TexImageValidationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TexImageValidationError({})", std::error::Error::description(self))
    }
}

fn log2(n: u32) -> u32 {
    31 - n.leading_zeros()
}

pub struct CommonTexImage2DValidator<'a> {
    context: &'a WebGLRenderingContext,
    target: u32,
    level: i32,
    internal_format: u32,
    width: i32,
    height: i32,
    border: i32,
}

pub struct CommonTexImage2DValidatorResult {
    pub texture: DomRoot<WebGLTexture>,
    pub target: TexImageTarget,
    pub level: u32,
    pub internal_format: TexFormat,
    pub width: u32,
    pub height: u32,
    pub border: u32,
}

impl<'a> WebGLValidator for CommonTexImage2DValidator<'a> {
    type Error = TexImageValidationError;
    type ValidatedOutput = CommonTexImage2DValidatorResult;
    fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
        // GL_INVALID_ENUM is generated if target is not GL_TEXTURE_2D,
        // GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
        // GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        // GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
        let target = match TexImageTarget::from_gl_constant(self.target) {
            Some(target) => target,
            None => {
                self.context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidTextureTarget(self.target));
            }
        };

        let texture = self.context.bound_texture_for_target(&target);
        let limits = self.context.limits();

        let max_size = if target.is_cubic() {
             limits.max_cube_map_tex_size
        } else {
             limits.max_tex_size
        };

        //  If an attempt is made to call this function with no WebGLTexture
        //  bound, an INVALID_OPERATION error is generated.
        let texture = match texture {
            Some(texture) => texture,
            None => {
                self.context.webgl_error(InvalidOperation);
                return Err(TexImageValidationError::TextureTargetNotBound(self.target));
            }
        };

        // GL_INVALID_ENUM is generated if internal_format is not an accepted
        // format.
        let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
            Some(format) => format,
            None => {
                self.context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidTextureFormat);
            }
        };

        // GL_INVALID_VALUE is generated if level is less than 0.
        if self.level < 0 {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::NegativeLevel);
        }

        // GL_INVALID_VALUE is generated if width or height is less than 0
        if self.width < 0 || self.height < 0 {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::NegativeDimension);
        }

        let width = self.width as u32;
        let height = self.height as u32;
        let level = self.level as u32;

        // GL_INVALID_VALUE is generated if width or height is greater than
        // GL_MAX_TEXTURE_SIZE when target is GL_TEXTURE_2D or
        // GL_MAX_CUBE_MAP_TEXTURE_SIZE when target is not GL_TEXTURE_2D.
        if width > max_size >> level || height > max_size >> level {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::TextureTooBig);
        }

        // GL_INVALID_VALUE is generated if level is greater than zero and the
        // texture is not power of two.
        if level > 0 && (!width.is_power_of_two() || !height.is_power_of_two()) {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::NonPotTexture);
        }

        // GL_INVALID_VALUE may be generated if level is greater than
        // log_2(max), where max is the returned value of GL_MAX_TEXTURE_SIZE
        // when target is GL_TEXTURE_2D or GL_MAX_CUBE_MAP_TEXTURE_SIZE when
        // target is not GL_TEXTURE_2D.
        if level > log2(max_size) {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::LevelTooHigh);
        }

        // GL_INVALID_VALUE is generated if border is not 0.
        if self.border != 0 {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::InvalidBorder);
        }

        Ok(CommonTexImage2DValidatorResult {
            texture: texture,
            target: target,
            level: level,
            internal_format: internal_format,
            width: width,
            height: height,
            border: self.border as u32,
        })
    }
}

impl<'a> CommonTexImage2DValidator<'a> {
    pub fn new(context: &'a WebGLRenderingContext,
               target: u32, level: i32,
               internal_format: u32,
               width: i32, height: i32,
               border: i32) -> Self {
        CommonTexImage2DValidator {
            context: context,
            target: target,
            level: level,
            internal_format: internal_format,
            width: width,
            height: height,
            border: border
        }
    }
}

pub struct TexImage2DValidator<'a> {
    common_validator: CommonTexImage2DValidator<'a>,
    format: u32,
    data_type: u32,
}

impl<'a> TexImage2DValidator<'a> {
    // TODO: Move data validation logic here.
    pub fn new(context: &'a WebGLRenderingContext,
               target: u32,
               level: i32,
               internal_format: u32,
               width: i32,
               height: i32,
               border: i32,
               format: u32,
               data_type: u32) -> Self {
        TexImage2DValidator {
            common_validator: CommonTexImage2DValidator::new(context, target,
                                                             level,
                                                             internal_format,
                                                             width, height,
                                                             border),
            format: format,
            data_type: data_type,
        }
    }
}

/// The validated result of a TexImage2DValidator-validated call.
pub struct TexImage2DValidatorResult {
    /// NB: width, height and level are already unsigned after validation.
    pub width: u32,
    pub height: u32,
    pub level: u32,
    pub border: u32,
    pub texture: DomRoot<WebGLTexture>,
    pub target: TexImageTarget,
    pub format: TexFormat,
    pub data_type: TexDataType,
}

/// TexImage2d validator as per
/// <https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml>
impl<'a> WebGLValidator for TexImage2DValidator<'a> {
    type ValidatedOutput = TexImage2DValidatorResult;
    type Error = TexImageValidationError;

    fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
        let context = self.common_validator.context;
        let CommonTexImage2DValidatorResult {
            texture,
            target,
            level,
            internal_format,
            width,
            height,
            border,
        } = self.common_validator.validate()?;

        // GL_INVALID_VALUE is generated if target is one of the six cube map 2D
        // image targets and the width and height parameters are not equal.
        if target.is_cubic() && width != height {
            context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::InvalidCubicTextureDimensions);
        }

        // GL_INVALID_ENUM is generated if format or data_type is not an
        // accepted value.
        let data_type = match TexDataType::from_gl_constant(self.data_type) {
            Some(data_type) => data_type,
            None => {
                context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidDataType);
            },
        };

        let format = match TexFormat::from_gl_constant(self.format) {
            Some(format) => format,
            None => {
                context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidTextureFormat);
            }
        };

        // GL_INVALID_OPERATION is generated if format does not match
        // internal_format.
        if format != internal_format {
            context.webgl_error(InvalidOperation);
            return Err(TexImageValidationError::TextureFormatMismatch);
        }

        // GL_INVALID_OPERATION is generated if type is
        // GL_UNSIGNED_SHORT_4_4_4_4 or GL_UNSIGNED_SHORT_5_5_5_1 and format is
        // not GL_RGBA.
        //
        // GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_5_6_5
        // and format is not GL_RGB.
        match data_type {
            TexDataType::UnsignedShort4444 |
            TexDataType::UnsignedShort5551 if format != TexFormat::RGBA => {
                context.webgl_error(InvalidOperation);
                return Err(TexImageValidationError::InvalidTypeForFormat);
            },
            TexDataType::UnsignedShort565 if format != TexFormat::RGB => {
                context.webgl_error(InvalidOperation);
                return Err(TexImageValidationError::InvalidTypeForFormat);
            },
            _ => {},
        }

        Ok(TexImage2DValidatorResult {
            width: width,
            height: height,
            level: level,
            border: border,
            texture: texture,
            target: target,
            format: format,
            data_type: data_type,
        })
    }
}
<commit_msg>Properly check for cubic dimensions in gl.copyTexImage2D<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/. */

use canvas_traits::webgl::WebGLError::*;
use dom::bindings::root::DomRoot;
use dom::webglrenderingcontext::WebGLRenderingContext;
use dom::webgltexture::WebGLTexture;
use std::{self, fmt};
use super::WebGLValidator;
use super::types::{TexImageTarget, TexDataType, TexFormat};

/// The errors that the texImage* family of functions can generate.
#[derive(Debug)]
pub enum TexImageValidationError {
    /// An invalid texture target was passed, it contains the invalid target.
    InvalidTextureTarget(u32),
    /// The passed texture target was not bound.
    TextureTargetNotBound(u32),
    /// Invalid texture dimensions were given.
    InvalidCubicTextureDimensions,
    /// A negative level was passed.
    NegativeLevel,
    /// A level too high to be allowed by the implementation was passed.
    LevelTooHigh,
    /// A negative width and height was passed.
    NegativeDimension,
    /// A bigger with and height were passed than what the implementation
    /// allows.
    TextureTooBig,
    /// An invalid data type was passed.
    InvalidDataType,
    /// An invalid texture format was passed.
    InvalidTextureFormat,
    /// Format did not match internal_format.
    TextureFormatMismatch,
    /// Invalid data type for the given format.
    InvalidTypeForFormat,
    /// Invalid border
    InvalidBorder,
    /// Expected a power of two texture.
    NonPotTexture,
}

impl std::error::Error for TexImageValidationError {
    fn description(&self) -> &str {
        use self::TexImageValidationError::*;
        match *self {
            InvalidTextureTarget(_)
                => "Invalid texture target",
            TextureTargetNotBound(_)
                => "Texture was not bound",
            InvalidCubicTextureDimensions
                => "Invalid dimensions were given for a cubic texture target",
            NegativeLevel
                => "A negative level was passed",
            LevelTooHigh
                => "Level too high",
            NegativeDimension
                => "Negative dimensions were passed",
            TextureTooBig
                => "Dimensions given are too big",
            InvalidDataType
                => "Invalid data type",
            InvalidTextureFormat
                => "Invalid texture format",
            TextureFormatMismatch
                => "Texture format mismatch",
            InvalidTypeForFormat
                => "Invalid type for the given format",
            InvalidBorder
                => "Invalid border",
            NonPotTexture
                => "Expected a power of two texture",
        }
    }
}

impl fmt::Display for TexImageValidationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TexImageValidationError({})", std::error::Error::description(self))
    }
}

fn log2(n: u32) -> u32 {
    31 - n.leading_zeros()
}

pub struct CommonTexImage2DValidator<'a> {
    context: &'a WebGLRenderingContext,
    target: u32,
    level: i32,
    internal_format: u32,
    width: i32,
    height: i32,
    border: i32,
}

pub struct CommonTexImage2DValidatorResult {
    pub texture: DomRoot<WebGLTexture>,
    pub target: TexImageTarget,
    pub level: u32,
    pub internal_format: TexFormat,
    pub width: u32,
    pub height: u32,
    pub border: u32,
}

impl<'a> WebGLValidator for CommonTexImage2DValidator<'a> {
    type Error = TexImageValidationError;
    type ValidatedOutput = CommonTexImage2DValidatorResult;
    fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
        // GL_INVALID_ENUM is generated if target is not GL_TEXTURE_2D,
        // GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
        // GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        // GL_TEXTURE_CUBE_MAP_POSITIVE_Z, or GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.
        let target = match TexImageTarget::from_gl_constant(self.target) {
            Some(target) => target,
            None => {
                self.context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidTextureTarget(self.target));
            }
        };

        let texture = self.context.bound_texture_for_target(&target);
        let limits = self.context.limits();

        let max_size = if target.is_cubic() {
             limits.max_cube_map_tex_size
        } else {
             limits.max_tex_size
        };

        //  If an attempt is made to call this function with no WebGLTexture
        //  bound, an INVALID_OPERATION error is generated.
        let texture = match texture {
            Some(texture) => texture,
            None => {
                self.context.webgl_error(InvalidOperation);
                return Err(TexImageValidationError::TextureTargetNotBound(self.target));
            }
        };

        // GL_INVALID_ENUM is generated if internal_format is not an accepted
        // format.
        let internal_format = match TexFormat::from_gl_constant(self.internal_format) {
            Some(format) => format,
            None => {
                self.context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidTextureFormat);
            }
        };

        // GL_INVALID_VALUE is generated if target is one of the six cube map 2D
        // image targets and the width and height parameters are not equal.
        if target.is_cubic() && self.width != self.height {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::InvalidCubicTextureDimensions);
        }

        // GL_INVALID_VALUE is generated if level is less than 0.
        if self.level < 0 {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::NegativeLevel);
        }

        // GL_INVALID_VALUE is generated if width or height is less than 0
        if self.width < 0 || self.height < 0 {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::NegativeDimension);
        }

        let width = self.width as u32;
        let height = self.height as u32;
        let level = self.level as u32;

        // GL_INVALID_VALUE is generated if width or height is greater than
        // GL_MAX_TEXTURE_SIZE when target is GL_TEXTURE_2D or
        // GL_MAX_CUBE_MAP_TEXTURE_SIZE when target is not GL_TEXTURE_2D.
        if width > max_size >> level || height > max_size >> level {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::TextureTooBig);
        }

        // GL_INVALID_VALUE is generated if level is greater than zero and the
        // texture is not power of two.
        if level > 0 && (!width.is_power_of_two() || !height.is_power_of_two()) {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::NonPotTexture);
        }

        // GL_INVALID_VALUE may be generated if level is greater than
        // log_2(max), where max is the returned value of GL_MAX_TEXTURE_SIZE
        // when target is GL_TEXTURE_2D or GL_MAX_CUBE_MAP_TEXTURE_SIZE when
        // target is not GL_TEXTURE_2D.
        if level > log2(max_size) {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::LevelTooHigh);
        }

        // GL_INVALID_VALUE is generated if border is not 0.
        if self.border != 0 {
            self.context.webgl_error(InvalidValue);
            return Err(TexImageValidationError::InvalidBorder);
        }

        Ok(CommonTexImage2DValidatorResult {
            texture: texture,
            target: target,
            level: level,
            internal_format: internal_format,
            width: width,
            height: height,
            border: self.border as u32,
        })
    }
}

impl<'a> CommonTexImage2DValidator<'a> {
    pub fn new(context: &'a WebGLRenderingContext,
               target: u32, level: i32,
               internal_format: u32,
               width: i32, height: i32,
               border: i32) -> Self {
        CommonTexImage2DValidator {
            context: context,
            target: target,
            level: level,
            internal_format: internal_format,
            width: width,
            height: height,
            border: border
        }
    }
}

pub struct TexImage2DValidator<'a> {
    common_validator: CommonTexImage2DValidator<'a>,
    format: u32,
    data_type: u32,
}

impl<'a> TexImage2DValidator<'a> {
    // TODO: Move data validation logic here.
    pub fn new(context: &'a WebGLRenderingContext,
               target: u32,
               level: i32,
               internal_format: u32,
               width: i32,
               height: i32,
               border: i32,
               format: u32,
               data_type: u32) -> Self {
        TexImage2DValidator {
            common_validator: CommonTexImage2DValidator::new(context, target,
                                                             level,
                                                             internal_format,
                                                             width, height,
                                                             border),
            format: format,
            data_type: data_type,
        }
    }
}

/// The validated result of a TexImage2DValidator-validated call.
pub struct TexImage2DValidatorResult {
    /// NB: width, height and level are already unsigned after validation.
    pub width: u32,
    pub height: u32,
    pub level: u32,
    pub border: u32,
    pub texture: DomRoot<WebGLTexture>,
    pub target: TexImageTarget,
    pub format: TexFormat,
    pub data_type: TexDataType,
}

/// TexImage2d validator as per
/// <https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml>
impl<'a> WebGLValidator for TexImage2DValidator<'a> {
    type ValidatedOutput = TexImage2DValidatorResult;
    type Error = TexImageValidationError;

    fn validate(self) -> Result<Self::ValidatedOutput, TexImageValidationError> {
        let context = self.common_validator.context;
        let CommonTexImage2DValidatorResult {
            texture,
            target,
            level,
            internal_format,
            width,
            height,
            border,
        } = self.common_validator.validate()?;

        // GL_INVALID_ENUM is generated if format or data_type is not an
        // accepted value.
        let data_type = match TexDataType::from_gl_constant(self.data_type) {
            Some(data_type) => data_type,
            None => {
                context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidDataType);
            },
        };

        let format = match TexFormat::from_gl_constant(self.format) {
            Some(format) => format,
            None => {
                context.webgl_error(InvalidEnum);
                return Err(TexImageValidationError::InvalidTextureFormat);
            }
        };

        // GL_INVALID_OPERATION is generated if format does not match
        // internal_format.
        if format != internal_format {
            context.webgl_error(InvalidOperation);
            return Err(TexImageValidationError::TextureFormatMismatch);
        }

        // GL_INVALID_OPERATION is generated if type is
        // GL_UNSIGNED_SHORT_4_4_4_4 or GL_UNSIGNED_SHORT_5_5_5_1 and format is
        // not GL_RGBA.
        //
        // GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_5_6_5
        // and format is not GL_RGB.
        match data_type {
            TexDataType::UnsignedShort4444 |
            TexDataType::UnsignedShort5551 if format != TexFormat::RGBA => {
                context.webgl_error(InvalidOperation);
                return Err(TexImageValidationError::InvalidTypeForFormat);
            },
            TexDataType::UnsignedShort565 if format != TexFormat::RGB => {
                context.webgl_error(InvalidOperation);
                return Err(TexImageValidationError::InvalidTypeForFormat);
            },
            _ => {},
        }

        Ok(TexImage2DValidatorResult {
            width: width,
            height: height,
            level: level,
            border: border,
            texture: texture,
            target: target,
            format: format,
            data_type: data_type,
        })
    }
}
<|endoftext|>


<commit_before>use scope;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;

use {Configuration, PanicHandler, ThreadPool};
use super::spawn_async;

#[test]
fn spawn_then_join_in_worker() {
    let (tx, rx) = channel();
    scope(move |_| {
        spawn_async(move || tx.send(22).unwrap());
    });
    assert_eq!(22, rx.recv().unwrap());
}

#[test]
fn spawn_then_join_outside_worker() {
    let (tx, rx) = channel();
    spawn_async(move || tx.send(22).unwrap());
    assert_eq!(22, rx.recv().unwrap());
}

#[test]
fn panic_fwd() {
    let (tx, rx) = channel();

    let tx = Mutex::new(tx);
    let panic_handler: PanicHandler = Arc::new(move |err| {
        let tx = tx.lock().unwrap();
        if let Some(&msg) = err.downcast_ref::<&str>() {
            if msg == "Hello, world!" {
                tx.send(1).unwrap();
            } else {
                tx.send(2).unwrap();
            }
        } else {
            tx.send(3).unwrap();
        }
    });

    let configuration = Configuration::new().set_panic_handler(panic_handler);

    ThreadPool::new(configuration).unwrap().spawn_async(move || panic!("Hello, world!"));

    assert_eq!(1, rx.recv().unwrap());
}
<commit_msg>add a simple test for async futures<commit_after>use futures::{lazy, Future};

use scope;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;

use {Configuration, PanicHandler, ThreadPool};
use super::{spawn_async, spawn_future_async};

#[test]
fn spawn_then_join_in_worker() {
    let (tx, rx) = channel();
    scope(move |_| {
        spawn_async(move || tx.send(22).unwrap());
    });
    assert_eq!(22, rx.recv().unwrap());
}

#[test]
fn spawn_then_join_outside_worker() {
    let (tx, rx) = channel();
    spawn_async(move || tx.send(22).unwrap());
    assert_eq!(22, rx.recv().unwrap());
}

#[test]
fn panic_fwd() {
    let (tx, rx) = channel();

    let tx = Mutex::new(tx);
    let panic_handler: PanicHandler = Arc::new(move |err| {
        let tx = tx.lock().unwrap();
        if let Some(&msg) = err.downcast_ref::<&str>() {
            if msg == "Hello, world!" {
                tx.send(1).unwrap();
            } else {
                tx.send(2).unwrap();
            }
        } else {
            tx.send(3).unwrap();
        }
    });

    let configuration = Configuration::new().set_panic_handler(panic_handler);

    ThreadPool::new(configuration).unwrap().spawn_async(move || panic!("Hello, world!"));

    assert_eq!(1, rx.recv().unwrap());
}

#[test]
fn async_future_map() {
    let data = Arc::new(Mutex::new(format!("Hello, ")));

    let a = spawn_future_async(lazy({
        let data = data.clone();
        move || Ok::<_, ()>(data)
    }));
    let future = spawn_future_async(a.map(|data| {
        let mut v = data.lock().unwrap();
        v.push_str("world!");
    }));
    let () = future.wait().unwrap();

    // future must have executed for the scope to have ended, even
    // though we never invoked `wait` to observe its result
    assert_eq!(&data.lock().unwrap()[..], "Hello, world!");
}
<|endoftext|>


<commit_before>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER, MAX_LPC_ORDER};

pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn lpc_restore_signal(quantization_level: i8,
                          coefficients: &[i32],
                          residual: &[i32],
                          output: &mut [i32]) {
  let order = coefficients.len();

  debug_assert!(order <= MAX_LPC_ORDER);

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter().rev()
                       .zip(&output[i..offset])
                       .fold(0, |result, (coefficient, signal)|
                             result + coefficient * signal);

    output[offset] = residual[i] + (prediction >> quantization_level);
  }
}

pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(_)      => unimplemented!(),
    subframe::Data::Verbatim(_)      => unimplemented!(),
    subframe::Data::Fixed(ref fixed) => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(_)           => unimplemented!(),
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}
<commit_msg>Add `lpc_restore_signal` to root decode function<commit_after>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER, MAX_LPC_ORDER};

pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn lpc_restore_signal(quantization_level: i8,
                          coefficients: &[i32],
                          residual: &[i32],
                          output: &mut [i32]) {
  let order = coefficients.len();

  debug_assert!(order <= MAX_LPC_ORDER);

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter().rev()
                       .zip(&output[i..offset])
                       .fold(0, |result, (coefficient, signal)|
                             result + coefficient * signal);

    output[offset] = residual[i] + (prediction >> quantization_level);
  }
}

pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(_)      => unimplemented!(),
    subframe::Data::Verbatim(_)      => unimplemented!(),
    subframe::Data::Fixed(ref fixed) => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(ref lpc)     => {
      let order        = lpc.order as usize;
      let coefficients = &lpc.qlp_coefficients[0..order];

      for i in 0..order {
        output[i] = lpc.warmup[i];
      }

      lpc_restore_signal(lpc.quantization_level, coefficients, &lpc.residual,
                         output);
    }
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}
<|endoftext|>