<commit_before>use std::io::Cursor;

use kuchiki::NodeRef;
use kuchiki::NodeDataRef;
use kuchiki::NodeData;
use kuchiki::ElementData;

use model::ListTopicItem;
use model::ListTopicTitleItem;
use model::ListTopicAuthorItem;
use model::ShowItem;
use model::ShowReplyItem;
use model::UrlQueryItem;
use reply_model::*;

use regex::Regex;
use url::Url;
use std::collections::HashMap;

#[derive(Clone)]
pub struct Index { }

impl Index {
    pub fn new() -> Self {
        Index {}
    }
    pub fn build(&mut self, document: &NodeRef) -> Result<Vec<ListTopicItem>, &'static str> {

            let trs_option = document.select(".Topic_ListPanel tr[id]");

            if trs_option.is_err() {
                return Err("fail to parse list topics item, reaons: trs_option not found");
            }

            let trs = trs_option.unwrap();

            let list_topics = trs.enumerate().map(list_topic_items_handler).collect::<Vec<_>>();

            let err_list_topics_option = list_topics.iter().filter(|x| x.is_err()).next();

            if err_list_topics_option.is_some() {
                return Err(&"fail to parse list topics items, reason: 'error list topic item' was found");
            }

            let result = list_topics.iter().map(|x| x.clone().unwrap() ).collect::<Vec<_>>();

            Ok(result)
    }
}

fn list_topic_items_handler((index,tr): (usize, ::kuchiki::NodeDataRef<::kuchiki::ElementData>)) -> Result<ListTopicItem, &'static str> {

    let items = match tr.as_node().select("td") {
        Ok(items) => items,
        Err(e) => panic!("{:?}", e)
    };

    let mut result: ListTopicItem = Default::default();

    for (j, item) in items.enumerate().filter(|&(j, _)| j > 0 && j < 6) {
        match j {
            1 => { result.title = parse_list_topic_title_item(&item) },
            2 => { result.author = parse_list_topic_author_item(&item) },
            3 => {
                let (date, time) = {
                    let text = item.text_contents().trim().to_string();
                    let map = text.split("\n").map(|x| x.trim().to_string()).collect::<Vec<_>>();
                    if map.len() < 2 {
                        panic!("length of map is invalid.");
                    }
                    (map[0].clone(), map[1].clone())
                };
                result.last_replied_date = date;
                result.last_replied_time = time;
            },
            4 => {
                let text = item.text_contents().trim().to_string();
                result.reply_count = text
            },
            5 => {
                let text = item.text_contents().trim().to_string();
                result.rating = text
            },
            _ => {}
        }
    }

    Ok(result)

}

fn parse_list_topic_title_item(item: &NodeDataRef<ElementData>) -> ListTopicTitleItem {
    let (first_link, links_count) = {
        let mut links = match item.as_node().select("a") {
            Ok(links) => links,
            Err(e) => panic!("ERR: {:?}", e)
        };

        let first_link_option = links.next();
        let last_link_option = links.last();

        let first_link = match first_link_option {
            Some(first_link) => first_link,
            None => { panic!("ERR: Can't find 'first_link'.") }
        };

        let max_page = match last_link_option {
            Some(last_link) =>
                last_link.text_contents().trim().to_string().parse::<usize>()
                .unwrap_or(0)
            ,
            None => { 1 }
        };

        (first_link, max_page)
    };

    let (url_str, url_query_item) = {
        let attrs = &(first_link.attributes).borrow();
        let href = attrs.get("href").unwrap_or("");

        let base_url = match Url::parse("http://forum1.hkgolden.com/view.aspx") {
            Ok(url) => url,
            Err(e) => { panic!(format!("fail to parse Base URL. Reason: {}", e)) }
        };
        let url = match base_url.join(&href) {
            Ok(url) => url,
            Err(e) => { panic!(format!("fail to build URL. Reason: {}", e)) }
        };
        let url_str = url.into_string();
        let url_query_item = parse_url_query_item(&url_str);
        (url_str, url_query_item)
    };

    let text = first_link.text_contents().trim().to_string();

     ListTopicTitleItem {
        url: url_str,
        url_query: url_query_item,
        text: text,
        num_of_pages: links_count
    }
}

fn parse_list_topic_author_item(item: &NodeDataRef<ElementData>) -> ListTopicAuthorItem {
    let (url, name) = {
        let mut links = match item.as_node().select("a") {
            Ok(links) => links,
            Err(e) => panic!("ERR: {:?}", e)
        };

        let first_link_option = links.next();

        let first_link = match first_link_option {
            Some(first_link) => first_link,
            None => { panic!("ERR: Can't find 'first_link'.") }
        };

        let attrs = &(first_link.attributes).borrow();
        let href = attrs.get("href").unwrap_or("").to_string();
        let text = first_link.text_contents().trim().to_string();
        (href, text)
    };

    ListTopicAuthorItem {
       url: url,
       name: name
    }
}

fn parse_url_query_item(url_str: &str) -> UrlQueryItem {
    let url = Url::parse(&url_str).expect("fail to parse url query item, reason: invalid url");
    let query = url.query().expect("fail to parse url query item, reason: invalid url query");
    let re = Regex::new(r"(\\?|&)(?P<key>[^&=]+)=(?P<value>[^&]+)").expect("fail to parse url query item, reason: invalid regex");

    let (channel, message) = {

        let mut map = HashMap::new();

        for cap in re.captures_iter(query) {
            let key = cap.name("key").unwrap_or("").to_string();
            let value = cap.name("value").unwrap_or("").to_string();
            map.entry(key).or_insert(value);
        }

        if map.len() < 2 {
            panic!("length of map is invalid.")
        }

        (
            map.get("type").expect("fail to parse url query item, reason: can not get value of 'type' attribute").to_string(),
            map.get("message").expect("fail to parse url query item, reason: can not get value of 'message' attribute").to_string()
        )
    };

    UrlQueryItem {
        channel: String::from(channel),
        message: String::from(message)
    }

}
<commit_msg>return result trait from index builder<commit_after>use std::io::Cursor;

use kuchiki::NodeRef;
use kuchiki::NodeDataRef;
use kuchiki::NodeData;
use kuchiki::ElementData;

use model::ListTopicItem;
use model::ListTopicTitleItem;
use model::ListTopicAuthorItem;
use model::UrlQueryItem;

use regex::Regex;
use url::Url;
use std::collections::HashMap;

#[derive(Clone)]
pub struct Index {}

impl Index {
    pub fn new() -> Self {
        Index {}
    }
    pub fn build(&mut self, document: &NodeRef) -> Result<Vec<ListTopicItem>, &'static str> {

        let trs_option = document.select(".Topic_ListPanel tr[id]");

        if trs_option.is_err() {
            return Err("fail to parse list topics item, reaons: trs_option not found");
        }

        let trs = trs_option.unwrap();

        let list_topics = trs.enumerate().map(list_topic_items_handler).collect::<Vec<_>>();

        let err_list_topics_option = list_topics.iter().filter(|x| x.is_err()).next();

        if err_list_topics_option.is_some() {
            return Err(&"fail to parse list topics items, reason: 'error list topic item' was found");
        }

        let result = list_topics.iter().map(|x| x.clone().unwrap()).collect::<Vec<_>>();

        Ok(result)
    }
}

fn list_topic_items_handler((index, tr): (usize, ::kuchiki::NodeDataRef<::kuchiki::ElementData>)) -> Result<ListTopicItem, &'static str> {

    let items_option = tr.as_node().select("td");

    if items_option.is_err() {
        return Err("fail to parse list topic items, reason: items_option not found");
    }

    let items = items_option.unwrap();

    let mut result: ListTopicItem = Default::default();

    for (j, item) in items.enumerate().filter(|&(j, _)| j > 0 && j < 6) {
        match j {
            1 => {
                match parse_list_topic_title_item(&item) {
                    Ok(s) => result.title = s,
                    Err(_) => {}
                }
            }
            2 => {
                match parse_list_topic_author_item(&item) {
                    Ok(s) => result.author = s,
                    Err(_) => {}
                }
            }
            3 => {
                let (date, time) = {
                    let text = item.text_contents().trim().to_string();
                    let map = text.split("\n").map(|x| x.trim().to_string()).collect::<Vec<_>>();
                    let count = map.len();

                    if count < 2 {
                        error!("length of map is invalid. length: {}", count);
                        return Err(&"length of map is invalid.");
                    }

                    let mut map_enumerator = map.iter().enumerate();
                    let date_option = match map_enumerator.clone()
                              .filter(|&(i, _)| i == 0)
                              .map(|(i, e)| (i, e))
                              .next() {
                        Some((i, text)) => Some(text),
                        None => None,
                    };

                    let time_option = match map_enumerator.clone()
                              .filter(|&(i, _)| i == 1)
                              .map(|(i, e)| (i, e))
                              .next() {
                        Some((i, text)) => Some(text),
                        None => None,
                    };

                    if date_option.is_none() {
                        return Err("fail to parse list topic items, reason: date_option not found");
                    }

                    if time_option.is_none() {
                        return Err("fail to parse list topic items, reason: time_option not found");
                    }

                    (date_option.unwrap().clone(), time_option.unwrap().clone())
                };
                result.last_replied_date = date;
                result.last_replied_time = time;
            }
            4 => {
                let text = item.text_contents().trim().to_string();
                result.reply_count = text
            }
            5 => {
                let text = item.text_contents().trim().to_string();
                result.rating = text
            }
            _ => {}
        }
    }

    Ok(result)

}

fn parse_list_topic_title_item(item: &NodeDataRef<ElementData>) -> Result<ListTopicTitleItem, &'static str> {
    let (first_link, links_count) = {
        let mut links_option = item.as_node().select("a");

        if links_option.is_err() {
            return Err("fail to parse list topic title item, reason: links not found");
        }

        let mut links = links_option.unwrap();

        let first_link_option = links.next();
        let last_link_option = links.last();

        if first_link_option.is_none() {
            return Err("fail to parse list topic title item, reason: first_link_option not found");
        }
        let first_link = first_link_option.unwrap();

        let max_page = match last_link_option {
            Some(last_link) => {
                last_link.text_contents()
                    .trim()
                    .to_string()
                    .parse::<usize>()
                    .unwrap_or(0)
            }
            None => 1,
        };

        (first_link, max_page)
    };

    let (url_str, url_query_item) = {
        let attrs = &(first_link.attributes).borrow();
        let href = attrs.get("href").unwrap_or("");

        let base_url_option = Url::parse("http://forum1.hkgolden.com/view.aspx");

        if base_url_option.is_err() {
            return Err("fail to parse list topic title item, reason: base_url_option not found");
        }
        let base_url = base_url_option.unwrap();

        let url_result = base_url.join(&href);

        if url_result.is_err() {
            return Err("fail to parse list topic title item, reason: fail to build URL. ");
        }
        let url = url_result.unwrap();

        let url_str = url.into_string();
        let url_query_option = parse_url_query_item(&url_str);

        if url_query_option.is_err() {
            return Err("fail to parse list topic title item, reason: fail to parse url query");
        }

        let url_query = url_query_option.unwrap();

        (url_str, url_query)
    };

    let text = first_link.text_contents().trim().to_string();

    Ok(ListTopicTitleItem {
           url: url_str,
           url_query: url_query_item,
           text: text,
           num_of_pages: links_count,
       })
}

fn parse_list_topic_author_item(item: &NodeDataRef<ElementData>) -> Result<ListTopicAuthorItem, &'static str> {
    let (url, name) = {

        let links_option = item.as_node().select("a");

        if links_option.is_err() {
            return Err("fail to parse list topic author item, reason: links_option not found");
        }

        let mut links = links_option.unwrap();

        let first_link_option = links.next();

        if first_link_option.is_none() {
            return Err("fail to parse list topic title item, reason: first_link_option not found");
        }
        let first_link = first_link_option.unwrap();

        let attrs = &(first_link.attributes).borrow();
        let href = attrs.get("href").unwrap_or("").to_string();
        let text = first_link.text_contents().trim().to_string();
        (href, text)
    };

    Ok(ListTopicAuthorItem {
           url: url,
           name: name,
       })
}

fn parse_url_query_item(url_str: &str) -> Result<UrlQueryItem, &'static str> {

    let url_option = Url::parse(&url_str);
    if url_option.is_err() {
        return Err("fail to parse url query item, reason: invalid url");
    }
    let url = url_option.unwrap();

    let query_option = url.query();
    if query_option.is_none() {
        return Err("fail to parse url query item, reason: invalid url query");
    }
    let query = query_option.unwrap();

    let re = Regex::new(r"(\\?|&)(?P<key>[^&=]+)=(?P<value>[^&]+)").expect("fail to parse url query item, reason: invalid regex");

    let (channel, message) = {

        let mut map = HashMap::new();

        for cap in re.captures_iter(query) {
            let key = cap.name("key").unwrap_or("").to_string();
            let value = cap.name("value").unwrap_or("").to_string();
            map.entry(key).or_insert(value);
        }

        let count = map.len();
        if count < 2 {
            error!("length of map is invalid. length: {}", count);
            return Err(&"length of map is invalid.");
        }

        let type_option = map.get("type");
        if type_option.is_none() {
            return Err(&"fail to parse url query item, reason: can not get value of 'type' attribute");
        }

        let message_option = map.get("message");
        if message_option.is_none() {
            return Err(&"fail to parse url query item, reason: can not get value of 'message' attribute");
        }

        (type_option.unwrap().to_string(), message_option.unwrap().to_string())
    };

    Ok(UrlQueryItem {
           channel: String::from(channel),
           message: String::from(message),
       })
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use rustc_serialize::Encoder;
use rustc_serialize::Encodable;
use rustc_serialize::Decoder;
use rustc_serialize::Decodable;
use rustc_serialize::hex::FromHex;

#[derive(Clone,Debug)]
pub struct BytesContainer {
    bytes: Vec<u8>,
}

impl BytesContainer {
    pub fn new(bytes: Vec<u8>) -> BytesContainer {
        BytesContainer { bytes: bytes }
    }

    pub fn get<'a>(&'a self) -> &'a Vec<u8> {
        &self.bytes
    }

    pub fn get_mut<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.bytes
    }

    pub fn to_bytestr(&self) -> String {
        let bytestr: Vec<String> = self.bytes.iter().map(|b| format!("{:02X}", b)).collect();
        bytestr.join("")
    }

    pub fn from_bytestr(bytestr: &str) -> Result<BytesContainer, ()> {
        match bytestr.from_hex() {
            Ok(vec) => Ok(BytesContainer::new(vec)),
            _ => Err(()),
        }
    }
}

impl Decodable for BytesContainer {
    fn decode<T: Decoder>(d: &mut T) -> Result<BytesContainer, T::Error> {
        let bytestr = try!(String::decode(d));
        match BytesContainer::from_bytestr(&bytestr) {
            Ok(bc) => Ok(bc),
            Err(_) => Err(d.error("Failed to parse hex string")),
        }
    }
}

impl Encodable for BytesContainer {
    fn encode<T: Encoder>(&self, d: &mut T) -> Result<(), T::Error> {
        self.to_bytestr().encode(d)
    }
}
<commit_msg>Added Drop trait to clear memory after drop<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use rustc_serialize::Encoder;
use rustc_serialize::Encodable;
use rustc_serialize::Decoder;
use rustc_serialize::Decodable;
use rustc_serialize::hex::FromHex;

#[derive(Clone,Debug)]
pub struct BytesContainer {
    bytes: Vec<u8>,
}

impl BytesContainer {
    pub fn new(bytes: Vec<u8>) -> BytesContainer {
        BytesContainer { bytes: bytes }
    }

    pub fn get<'a>(&'a self) -> &'a Vec<u8> {
        &self.bytes
    }

    pub fn get_mut<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.bytes
    }

    pub fn to_bytestr(&self) -> String {
        let bytestr: Vec<String> = self.bytes.iter().map(|b| format!("{:02X}", b)).collect();
        bytestr.join("")
    }

    pub fn from_bytestr(bytestr: &str) -> Result<BytesContainer, ()> {
        match bytestr.from_hex() {
            Ok(vec) => Ok(BytesContainer::new(vec)),
            _ => Err(()),
        }
    }
}

impl Decodable for BytesContainer {
    fn decode<T: Decoder>(d: &mut T) -> Result<BytesContainer, T::Error> {
        let bytestr = try!(String::decode(d));
        match BytesContainer::from_bytestr(&bytestr) {
            Ok(bc) => Ok(bc),
            Err(_) => Err(d.error("Failed to parse hex string")),
        }
    }
}

impl Encodable for BytesContainer {
    fn encode<T: Encoder>(&self, d: &mut T) -> Result<(), T::Error> {
        self.to_bytestr().encode(d)
    }
}

impl Drop for BytesContainer {
    fn drop(&mut self) {
        for i in 0..self.bytes.len() {
            self.bytes[i] = 0;
        }
    }
}

#[test]
fn test_memclear() {
    unsafe {
        // this will point to the vec of bytes
        let ptr : *const Vec<u8>;

        // init a vec and let it go out of scope
        {
            let a = vec![1,2,3];
            let bc = BytesContainer::new(a);

            // assign pointer
            ptr = bc.get();
        }

        // now the data should be cleared
        assert_eq!(*ptr, vec!(0,0,0));
    }
}
<|endoftext|>


<commit_before>//!
//! Support to register a [`GbmDevice`](GbmDevice)
//! to an open [`Session`](::backend::session::Session).
//!

use drm::control::crtc;
use gbm::BufferObject;
use std::cell::RefCell;
use std::collections::HashMap;
use std::os::unix::io::RawFd;
use std::rc::{Rc, Weak};

use super::{GbmDevice, GbmSurfaceInternal};
use crate::backend::drm::{RawDevice, RawSurface};
use crate::backend::session::{AsSessionObserver, SessionObserver};

/// [`SessionObserver`](SessionObserver)
/// linked to the [`GbmDevice`](GbmDevice) it was
/// created from.
pub struct GbmDeviceObserver<
    S: SessionObserver + 'static,
    D: RawDevice + ::drm::control::Device + AsSessionObserver<S> + 'static,
> {
    observer: S,
    backends: Weak<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
    logger: ::slog::Logger,
}

impl<
        S: SessionObserver + 'static,
        D: RawDevice + ::drm::control::Device + AsSessionObserver<S> + 'static,
    > AsSessionObserver<GbmDeviceObserver<S, D>> for GbmDevice<D>
{
    fn observer(&mut self) -> GbmDeviceObserver<S, D> {
        GbmDeviceObserver {
            observer: (**self.dev.borrow_mut()).observer(),
            backends: Rc::downgrade(&self.backends),
            logger: self.logger.clone(),
        }
    }
}

impl<
        S: SessionObserver + 'static,
        D: RawDevice + ::drm::control::Device + AsSessionObserver<S> + 'static,
    > SessionObserver for GbmDeviceObserver<S, D>
{
    fn pause(&mut self, devnum: Option<(u32, u32)>) {
        self.observer.pause(devnum);
    }

    fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
        self.observer.activate(devnum);
        let mut crtcs = Vec::new();
        if let Some(backends) = self.backends.upgrade() {
            for (crtc, backend) in backends.borrow().iter() {
                if let Some(backend) = backend.upgrade() {
                    // restart rendering loop, if it was previously running
                    if let Some(fb) = backend.current_frame_buffer.get() {
                        if backend.crtc.page_flip(fb).is_err() {
                            // Try more!
                            if let Err(err) = backend.recreate() {
                                error!(
                                    self.logger,
                                    "Failed to re-create gbm surface, is the device gone?\n\t{}", err
                                );
                            }
                            if let Err(err) = unsafe { backend.page_flip() } {
                                warn!(self.logger, "Failed to restart rendering loop. Error: {}", err);
                                // TODO bubble this up the user somehow
                                //      maybe expose a "running" state from a surface?
                            }
                        }
                    }

                    // reset cursor
                    {
                        use ::drm::control::Device;

                        let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) =
                            unsafe { &*backend.cursor.as_ptr() };
                        if backend
                            .dev
                            .borrow()
                            .set_cursor2(*crtc, Some(cursor), ((*hotspot).0 as i32, (*hotspot).1 as i32))
                            .is_err()
                        {
                            if let Err(err) = backend.dev.borrow().set_cursor(*crtc, Some(cursor)) {
                                error!(self.logger, "Failed to reset cursor. Error: {}", err);
                            }
                        }
                    }
                } else {
                    crtcs.push(*crtc);
                }
            }
            for crtc in crtcs {
                backends.borrow_mut().remove(&crtc);
            }
        }
    }
}
<commit_msg>gbm: cleanup session rendering loop restart<commit_after>//!
//! Support to register a [`GbmDevice`](GbmDevice)
//! to an open [`Session`](::backend::session::Session).
//!

use drm::control::crtc;
use gbm::BufferObject;
use std::cell::RefCell;
use std::collections::HashMap;
use std::os::unix::io::RawFd;
use std::rc::{Rc, Weak};

use super::{GbmDevice, GbmSurfaceInternal};
use crate::backend::drm::{RawDevice, RawSurface};
use crate::backend::graphics::CursorBackend;
use crate::backend::session::{AsSessionObserver, SessionObserver};

/// [`SessionObserver`](SessionObserver)
/// linked to the [`GbmDevice`](GbmDevice) it was
/// created from.
pub struct GbmDeviceObserver<
    S: SessionObserver + 'static,
    D: RawDevice + ::drm::control::Device + AsSessionObserver<S> + 'static,
> {
    observer: S,
    backends: Weak<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
    logger: ::slog::Logger,
}

impl<
        O: SessionObserver + 'static,
        S: CursorBackend<CursorFormat=dyn drm::buffer::Buffer> + RawSurface + 'static,
        D: RawDevice<Surface=S> + drm::control::Device + AsSessionObserver<O> + 'static,
    > AsSessionObserver<GbmDeviceObserver<O, D>> for GbmDevice<D>
{
    fn observer(&mut self) -> GbmDeviceObserver<O, D> {
        GbmDeviceObserver {
            observer: (**self.dev.borrow_mut()).observer(),
            backends: Rc::downgrade(&self.backends),
            logger: self.logger.clone(),
        }
    }
}

impl<
        O: SessionObserver + 'static,
        S: CursorBackend<CursorFormat=dyn drm::buffer::Buffer> + RawSurface + 'static,
        D: RawDevice<Surface=S> + drm::control::Device + AsSessionObserver<O> + 'static,
    > SessionObserver for GbmDeviceObserver<O, D>
{
    fn pause(&mut self, devnum: Option<(u32, u32)>) {
        self.observer.pause(devnum);
    }

    fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
        self.observer.activate(devnum);
        let mut crtcs = Vec::new();
        if let Some(backends) = self.backends.upgrade() {
            for (crtc, backend) in backends.borrow().iter() {
                if let Some(backend) = backend.upgrade() {
                    // restart rendering loop, if it was previously running
                    if let Some(current_fb) = backend.current_frame_buffer.get() {
                        let result = if backend.crtc.commit_pending() {
                            backend.crtc.commit(current_fb)
                        } else {
                            RawSurface::page_flip(&backend.crtc, current_fb)
                        };

                        if let Err(err) = result {
                            warn!(
                                self.logger,
                                "Failed to restart rendering loop. Re-creating resources. Error: {}", err
                            );
                            // TODO bubble up
                        }
                    }

                    // reset cursor
                    {
                        use ::drm::control::Device;

                        let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) =
                            unsafe { &*backend.cursor.as_ptr() };
                        if backend.crtc.set_cursor_representation(cursor, *hotspot)
                            .is_err()
                        {
                            if let Err(err) = backend.dev.borrow().set_cursor(*crtc, Some(cursor)) {
                                error!(self.logger, "Failed to reset cursor. Error: {}", err);
                            }
                        }
                    }
                } else {
                    crtcs.push(*crtc);
                }
            }
            for crtc in crtcs {
                backends.borrow_mut().remove(&crtc);
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod Home {
    use chrono::{NaiveDate};

    pub struct NewsItem {
        pub title: String,
        pub date: NaiveDate,
    }

    fn changeFuncName() -> NewsItem {
        let item :NewsItem = NewsItem{
                                title: String::from("Ethereum bounty contracts have now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!"),
                                date: NaiveDate::from_ymd(2019, 1, 22)
                            };
        item
    }

}<commit_msg>Example fn now returns array of NewsItem structs<commit_after>pub mod Home {
    use chrono::{NaiveDate};

    pub struct NewsItem {
        pub title: String,
        pub date: NaiveDate,
    }

    fn changeFuncName() -> [NewsItem; 1] {
        let aNewsItems: [NewsItem; 1] = [
            NewsItem{
                title: String::from(
                    "Ethereum bounty contractshave now been added for anyone that would like to try to push the boundaries of human knowledge. The first contract is a competition for the correct solution to a³+b³+c³ = 33. Tweet me if you need assistance using these contracts!"),
                date: NaiveDate::from_ymd(2019, 1, 22)
            }
        ];
        aNewsItems
    }

}<|endoftext|>


<commit_before>use std::str::FromStr;
use std::sync::Arc;
use std::ascii::AsciiExt;
use std::borrow::Cow;

use futures::{Future, AsyncSink};
use futures::sink::Sink;
use futures::sync::oneshot::{Sender};
use futures::sync::mpsc::{unbounded as channel};
use minihttp::Status;
use minihttp::server::Head;
use rustc_serialize::json::Json;

use intern::SessionId;
use config::chat::Chat;
use incoming::{Input};
use chat::{Cid, MessageError};
use chat::backend;
use chat::message::AuthData;
use chat::processor::{Action, ConnectionMessage};

/// Issue Auth call to backend.
///
/// Send Auth message to proper backend
/// returninng Hello/Error message.
fn auth_data(handshake: &Head) -> Result<AuthData, Status> {
    let mut cookie = None;
    let mut auth = None;
    for (key, value) in handshake.headers() {
        if key.eq_ignore_ascii_case("Cookie") {
            if cookie.is_some() {
                debug!("Duplicate Cookie header");
                return Err(Status::BadRequest);
            }
            cookie = Some(String::from_utf8_lossy(value).into_owned());
        } else if key.eq_ignore_ascii_case("Authorization") {
            if auth.is_some() {
                debug!("Duplicate Authorization header");
                return Err(Status::BadRequest);
            }
            auth = Some(String::from_utf8_lossy(value).into_owned());
        }
    }
    let url_qs = handshake.path().expect("invalid path for websocket hanshake")
        .splitn(2, "?").nth(1).unwrap_or("").to_string();

    Ok(AuthData {
        http_cookie: cookie,
        http_authorization: auth,
        url_querystring: url_qs,
    })
}

/*
    let payload = message::encode_auth(&serialize_cid(&conn_id), &data);

    let dest = self.chat_config.message_handlers
        .resolve("tangle.authorize_connection");
    let path: Cow<_> = if dest.path == "/" {
        "/tangle/authorize_connection".into()
    } else {
        (dest.path.to_string() + "/tangle/authorize_connection").into()
    };
    request_fn_buffered(self.client.upstream(&dest.upstream),
        move |mut e| {
        })
}
*/

pub fn start_authorize(inp: &Input, settings: &Arc<Chat>,
                       response: Sender<Result<(SessionId, Json), Status>>)
{
    let conn_id = Cid::new();
    let (tx, rx) = channel();

    let pool = inp.runtime.chat_processor.read()
        .expect("chat pool locked")
        .pool(&settings.session_pool);
    let sess_cfg = inp.config.session_pools
        .get(&settings.session_pool).unwrap(); // FIXME: unwrap

    pool.send(Action::NewConnection {
        conn_id: conn_id,
        channel: tx,
    });

    let dest = settings.message_handlers
        .resolve("tangle.authorize_connection");
    let path: Cow<_> = if dest.path == "/" {
        "/tangle/authorize_connection".into()
    } else {
        (dest.path.to_string() + "/tangle/authorize_connection").into()
    };
    let mut up = inp.runtime.http_pools.upstream(&dest.upstream);

    let auth_data = match auth_data(inp.headers) {
        Ok(data) => data,
        Err(e) => {
            response.complete(Err(e));
            return;
        }
    };
    let codec = Box::new(backend::AuthCodec::new(path.into_owned(),
        conn_id, auth_data, response));

    match up.get_mut().get_mut() {
        Some(pool) => {
            match pool.start_send(codec) {
                Ok(AsyncSink::NotReady(codec)) => {
                    // codec.into_inner().send(Err(Status::ServiceUnavailable))
                    unimplemented!();
                }
                Ok(AsyncSink::Ready) => {
                    debug!("Sent /tangle/authorize_connection to proxy");
                }
                Err(e) => {
                    error!("Error sending to pool {:?}: {}", dest.upstream, e);
                    // TODO(tailhook) ensure that sender is closed
                }
            }
        }
        None => {
            error!("No such pool {:?}", dest.upstream);
            // codec.into_inner().send(Err(Status::NotFound))
            unimplemented!();
        }
    }

/*

    Box::new(chat_api.authorize_connection(&req, cid, tx.clone())
        .map_err(|e| -> Error { unimplemented!() })
        .map(move |data| {
            let resp = match chat::parse_userinfo(data) {
                Ok((sess_id, userinfo)) => {
                    let session_api = chat_api.session_api(
                        sess_id, cid, userinfo, tx);
                    WebsocketChat(Ready(init, session_api, rx))
                }
                Err(e) => {
                    error!("Bad data returned by \
                        authorize_connection: {}", e);
                    WebsocketChat(AuthError(init,
                        Status::InternalServerError))
                }
            };
            Serializer {
                config: cfg,
                debug: debug,
                response: resp,
                handle: h1,
                request: None,
            }
        }))
        */
}

/// Returns true when status is one in the set which backend is allowed
/// (and expected) to return
///
/// All http statuses returned from a backend that doesn't match this list
/// will be logged.
pub fn good_status(status: Status) -> bool {
    matches!(status,
        Status::Forbidden|
        Status::Unauthorized|
        Status::NotFound|
        Status::Gone|
        Status::BadRequest)
}

/// Parse userinfo received on Auth call;
pub fn parse_userinfo(response: Json)
    -> Result<(SessionId, Json), MessageError>
{
    use super::message::ValidationError::*;
    use super::error::MessageError::*;
    match response {
        Json::Object(data) => {
            let sess_id = match data.get("user_id".into()) {
                Some(&Json::String(ref s)) => {
                    SessionId::from_str(s.as_str())
                    .map_err(|_| ValidationError(InvalidUserId))?
                }
                _ => return Err(ValidationError(InvalidUserId)),
            };
            Ok((sess_id, Json::Object(data)))
        }
        _ => {
            Err(ValidationError(ObjectExpected))
        }
    }
}
<commit_msg>Remove old commented out code<commit_after>use std::str::FromStr;
use std::sync::Arc;
use std::ascii::AsciiExt;
use std::borrow::Cow;

use futures::{Future, AsyncSink};
use futures::sink::Sink;
use futures::sync::oneshot::{Sender};
use futures::sync::mpsc::{unbounded as channel};
use minihttp::Status;
use minihttp::server::Head;
use rustc_serialize::json::Json;

use intern::SessionId;
use config::chat::Chat;
use incoming::{Input};
use chat::{Cid, MessageError};
use chat::backend;
use chat::message::AuthData;
use chat::processor::{Action, ConnectionMessage};

/// Issue Auth call to backend.
///
/// Send Auth message to proper backend
/// returninng Hello/Error message.
fn auth_data(handshake: &Head) -> Result<AuthData, Status> {
    let mut cookie = None;
    let mut auth = None;
    for (key, value) in handshake.headers() {
        if key.eq_ignore_ascii_case("Cookie") {
            if cookie.is_some() {
                debug!("Duplicate Cookie header");
                return Err(Status::BadRequest);
            }
            cookie = Some(String::from_utf8_lossy(value).into_owned());
        } else if key.eq_ignore_ascii_case("Authorization") {
            if auth.is_some() {
                debug!("Duplicate Authorization header");
                return Err(Status::BadRequest);
            }
            auth = Some(String::from_utf8_lossy(value).into_owned());
        }
    }
    let url_qs = handshake.path().expect("invalid path for websocket hanshake")
        .splitn(2, "?").nth(1).unwrap_or("").to_string();

    Ok(AuthData {
        http_cookie: cookie,
        http_authorization: auth,
        url_querystring: url_qs,
    })
}

pub fn start_authorize(inp: &Input, settings: &Arc<Chat>,
                       response: Sender<Result<(SessionId, Json), Status>>)
{
    let conn_id = Cid::new();
    let (tx, rx) = channel();

    let pool = inp.runtime.chat_processor.read()
        .expect("chat pool locked")
        .pool(&settings.session_pool);
    let sess_cfg = inp.config.session_pools
        .get(&settings.session_pool).unwrap(); // FIXME: unwrap

    pool.send(Action::NewConnection {
        conn_id: conn_id,
        channel: tx,
    });

    let dest = settings.message_handlers
        .resolve("tangle.authorize_connection");
    let path: Cow<_> = if dest.path == "/" {
        "/tangle/authorize_connection".into()
    } else {
        (dest.path.to_string() + "/tangle/authorize_connection").into()
    };
    let mut up = inp.runtime.http_pools.upstream(&dest.upstream);

    let auth_data = match auth_data(inp.headers) {
        Ok(data) => data,
        Err(e) => {
            response.complete(Err(e));
            return;
        }
    };
    let codec = Box::new(backend::AuthCodec::new(path.into_owned(),
        conn_id, auth_data, response));

    match up.get_mut().get_mut() {
        Some(pool) => {
            match pool.start_send(codec) {
                Ok(AsyncSink::NotReady(codec)) => {
                    // codec.into_inner().send(Err(Status::ServiceUnavailable))
                    unimplemented!();
                }
                Ok(AsyncSink::Ready) => {
                    debug!("Sent /tangle/authorize_connection to proxy");
                }
                Err(e) => {
                    error!("Error sending to pool {:?}: {}", dest.upstream, e);
                    // TODO(tailhook) ensure that sender is closed
                }
            }
        }
        None => {
            error!("No such pool {:?}", dest.upstream);
            // codec.into_inner().send(Err(Status::NotFound))
            unimplemented!();
        }
    }

}

/// Returns true when status is one in the set which backend is allowed
/// (and expected) to return
///
/// All http statuses returned from a backend that doesn't match this list
/// will be logged.
pub fn good_status(status: Status) -> bool {
    matches!(status,
        Status::Forbidden|
        Status::Unauthorized|
        Status::NotFound|
        Status::Gone|
        Status::BadRequest)
}

/// Parse userinfo received on Auth call;
pub fn parse_userinfo(response: Json)
    -> Result<(SessionId, Json), MessageError>
{
    use super::message::ValidationError::*;
    use super::error::MessageError::*;
    match response {
        Json::Object(data) => {
            let sess_id = match data.get("user_id".into()) {
                Some(&Json::String(ref s)) => {
                    SessionId::from_str(s.as_str())
                    .map_err(|_| ValidationError(InvalidUserId))?
                }
                _ => return Err(ValidationError(InvalidUserId)),
            };
            Ok((sess_id, Json::Object(data)))
        }
        _ => {
            Err(ValidationError(ObjectExpected))
        }
    }
}
<|endoftext|>


<commit_before>use reqwest;

use self::access::{Access, get_access};
use self::expiration::{Expiration, get_expiration};
use self::format::{Format, get_format};
use construct_api_url;
use objects::PastebinMessage;

use std::io::Read;
use std::error::Error;
use std::env;

pub mod access;
pub mod expiration;
pub mod format;

use error::{Result, check_for_error};

pub struct Paster {
    developer_key: String,
}

impl Paster {
    pub fn new(developer_key: Option<String>) -> Self {
        let developer_key =
            developer_key.or_else(|| env::var("PASTEBIN_DEVELOPER_TOKEN").ok())
                         .expect("You should pass in a token to new or set the PASTEBIN_DEVELOPER_TOKEN env var");
        Paster {
            developer_key: developer_key,
        }
    }

    pub fn paste(&self, code: &str, access: &Access, name: &str, expiration: &Expiration, format: &Format, user_key: &str) -> Result<PastebinMessage> {
        let path = ["api_post.php"];
        let url = construct_api_url(&path);
        let access = get_access(access);
        let expiration = get_expiration(expiration);
        let format = get_format(format);
        let dev_key = &self.developer_key;

        let params = [("api_option", "paste"),
                      ("api_user_key", user_key),
                      ("api_paste_private", access),
                      ("api_paste_name", name),
                      ("api_expire_date", expiration),
                      ("api_paste_format", format),
                      ("api_dev_key", dev_key),
                      ("api_paste_code", code)];

        self.send_post_request(&url, &params)
    }

    fn send_post_request(&self, url: &str, params: &[(&str, &str)]) -> Result<PastebinMessage> {
        let client = reqwest::Client::new().unwrap();
        let mut res = client.post(url).form(&params).send()?;
        assert!(res.status().is_success());
        let mut result: String = String::new();
        res.read_to_string(&mut result);
        check_for_error(result)
    }
}
<commit_msg>removed unused imports<commit_after>use reqwest;

use self::access::{Access, get_access};
use self::expiration::{Expiration, get_expiration};
use self::format::{Format, get_format};
use construct_api_url;
use objects::PastebinMessage;

use std::io::Read;
use std::env;

pub mod access;
pub mod expiration;
pub mod format;

use error::{Result, check_for_error};

pub struct Paster {
    developer_key: String,
}

impl Paster {
    pub fn new(developer_key: Option<String>) -> Self {
        let developer_key =
            developer_key.or_else(|| env::var("PASTEBIN_DEVELOPER_TOKEN").ok())
                         .expect("You should pass in a token to new or set the PASTEBIN_DEVELOPER_TOKEN env var");
        Paster {
            developer_key: developer_key,
        }
    }

    pub fn paste(&self, code: &str, access: &Access, name: &str, expiration: &Expiration, format: &Format, user_key: &str) -> Result<PastebinMessage> {
        let path = ["api_post.php"];
        let url = construct_api_url(&path);
        let access = get_access(access);
        let expiration = get_expiration(expiration);
        let format = get_format(format);
        let dev_key = &self.developer_key;

        let params = [("api_option", "paste"),
                      ("api_user_key", user_key),
                      ("api_paste_private", access),
                      ("api_paste_name", name),
                      ("api_expire_date", expiration),
                      ("api_paste_format", format),
                      ("api_dev_key", dev_key),
                      ("api_paste_code", code)];

        self.send_post_request(&url, &params)
    }

    fn send_post_request(&self, url: &str, params: &[(&str, &str)]) -> Result<PastebinMessage> {
        let client = reqwest::Client::new().unwrap();
        let mut res = client.post(url).form(&params).send()?;
        assert!(res.status().is_success());
        let mut result: String = String::new();
        res.read_to_string(&mut result)?;
        check_for_error(result)
    }
}
<|endoftext|>


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

#[cfg(target_os = "windows")]
pub use self::windows::shell_escape;

#[cfg(any(test, target_os = "windows"))]
mod windows {
    use std::borrow::Cow;

    const SPACE: char = ' ';
    const ESCAPE_CHAR: char = '\\';
    const QUOTE_CHAR: char = '"';
    const BACKSLASH: char = '\\';
    const SLASH: char = '/';

    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    ///
    /// Escape double quotes and spaces by wrapping the string in double quotes.
    ///
    /// Turn all backslashes into forward slashes.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        // check if string needs to be escaped
        let mut has_spaces = false;
        let mut has_backslashes = false;
        let mut has_quotes = false;
        for ch in s.chars() {
            match ch {
                QUOTE_CHAR => has_quotes = true,
                SPACE => has_spaces = true,
                BACKSLASH => has_backslashes = true,
                _ => {}
            }
        }
        if !has_spaces && !has_backslashes && !has_quotes {
            return s
        }
        let mut es = String::with_capacity(s.len());
        if has_spaces {
            es.push(QUOTE_CHAR);
        }
        for ch in s.chars() {
            match ch {
                BACKSLASH => { es.push(SLASH); continue }
                QUOTE_CHAR => es.push(ESCAPE_CHAR),
                _ => {}
            }
            es.push(ch)
        }
        if has_spaces {
            es.push(QUOTE_CHAR);
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#""linker=gcc -L/foo -Wl,bar""#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"\path\to\my documents\"#.into()),
                                r#""/path/to/my documents/""#);
    }
}

#[cfg(not(target_os = "windows"))]
pub use self::other::shell_escape;

#[cfg(any(test, not(target_os = "windows")))]
mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    #[cfg(not(target_os = "windows"))]
    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<commit_msg>Fix erronous cfg directive<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(target_os = "windows")]
pub use self::windows::shell_escape;

#[cfg(any(test, target_os = "windows"))]
mod windows {
    use std::borrow::Cow;

    const SPACE: char = ' ';
    const ESCAPE_CHAR: char = '\\';
    const QUOTE_CHAR: char = '"';
    const BACKSLASH: char = '\\';
    const SLASH: char = '/';

    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    ///
    /// Escape double quotes and spaces by wrapping the string in double quotes.
    ///
    /// Turn all backslashes into forward slashes.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        // check if string needs to be escaped
        let mut has_spaces = false;
        let mut has_backslashes = false;
        let mut has_quotes = false;
        for ch in s.chars() {
            match ch {
                QUOTE_CHAR => has_quotes = true,
                SPACE => has_spaces = true,
                BACKSLASH => has_backslashes = true,
                _ => {}
            }
        }
        if !has_spaces && !has_backslashes && !has_quotes {
            return s
        }
        let mut es = String::with_capacity(s.len());
        if has_spaces {
            es.push(QUOTE_CHAR);
        }
        for ch in s.chars() {
            match ch {
                BACKSLASH => { es.push(SLASH); continue }
                QUOTE_CHAR => es.push(ESCAPE_CHAR),
                _ => {}
            }
            es.push(ch)
        }
        if has_spaces {
            es.push(QUOTE_CHAR);
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#""linker=gcc -L/foo -Wl,bar""#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"\path\to\my documents\"#.into()),
                                r#""/path/to/my documents/""#);
    }
}

#[cfg(not(target_os = "windows"))]
pub use self::other::shell_escape;

#[cfg(any(test, not(target_os = "windows")))]
mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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.

use crate::place_over_frame::RenderPassPlaceOverFrame;

use vulkano_win::VkSurfaceBuild;

use std::collections::HashMap;
use std::sync::Arc;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features, Queue};
use vulkano::format::Format;
use vulkano::image::view::ImageView;
use vulkano::image::{AttachmentImage, ImageUsage, ImageViewAbstract, SampleCount, SwapchainImage};
use vulkano::instance::debug::DebugCallback;
use vulkano::instance::Instance;
use vulkano::instance::InstanceExtensions;
use vulkano::swapchain::{
    AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform,
    Swapchain, SwapchainCreationError,
};
use vulkano::sync::{FlushError, GpuFuture};
use vulkano::{swapchain, sync, Version};
use winit::event_loop::EventLoop;
use winit::window::{Fullscreen, Window, WindowBuilder};

/// Final render target (swapchain image)
pub type FinalImageView = Arc<ImageView<Arc<SwapchainImage<Window>>>>;
/// Other intermediate render targets
pub type InterimImageView = Arc<ImageView<Arc<AttachmentImage>>>;

/// A simple struct to organize renderpasses.
/// You could add more here. E.g. the `frame_system`
/// from the deferred examples...
pub struct RenderPasses {
    pub place_over_frame: RenderPassPlaceOverFrame,
}

#[derive(Debug, Copy, Clone)]
pub struct RenderOptions {
    pub title: &'static str,
    pub window_size: [u32; 2],
    pub v_sync: bool,
}

impl Default for RenderOptions {
    fn default() -> Self {
        RenderOptions {
            title: "App",
            window_size: [1920, 1080],
            v_sync: false,
        }
    }
}

pub struct Renderer {
    _debug_callback: DebugCallback,
    _instance: Arc<Instance>,
    device: Arc<Device>,
    surface: Arc<Surface<Window>>,
    queue: Arc<Queue>,
    swap_chain: Arc<Swapchain<Window>>,
    image_index: usize,
    final_views: Vec<FinalImageView>,
    /// Image view that is to be rendered with our pipeline.
    /// (bool refers to whether it should get resized with swapchain resize)
    interim_image_views: HashMap<usize, (InterimImageView, bool)>,
    recreate_swapchain: bool,
    previous_frame_end: Option<Box<dyn GpuFuture>>,
    render_passes: RenderPasses,
    is_fullscreen: bool,
}

impl Renderer {
    /// Creates a new GPU renderer for window with given parameters
    pub fn new(event_loop: &EventLoop<()>, opts: RenderOptions) -> Self {
        println!("Creating renderer for window size {:?}", opts.window_size);
        // Add instance extensions based on needs
        let instance_extensions = InstanceExtensions {
            ext_debug_utils: true,
            ..vulkano_win::required_extensions()
        };
        // Create instance
        #[cfg(not(target_os = "macos"))]
        let layers = vec!["VK_LAYER_LUNARG_standard_validation"];
        #[cfg(target_os = "macos")]
        let layers = vec!["VK_LAYER_KHRONOS_validation"];
        let _instance = Instance::new(None, Version::V1_2, &instance_extensions, layers)
            .expect("Failed to create instance");
        // Create debug callback for printing vulkan errors and warnings
        let _debug_callback = DebugCallback::errors_and_warnings(&_instance, |msg| {
            println!(
                "{} {:?} {:?}: {}",
                msg.layer_prefix.unwrap_or("unknown"),
                msg.ty,
                msg.severity,
                msg.description
            );
        })
        .unwrap();

        // Get desired device
        let physical_device = PhysicalDevice::enumerate(&_instance)
            .min_by_key(|p| match p.properties().device_type {
                PhysicalDeviceType::DiscreteGpu => 0,
                PhysicalDeviceType::IntegratedGpu => 1,
                PhysicalDeviceType::VirtualGpu => 2,
                PhysicalDeviceType::Cpu => 3,
                PhysicalDeviceType::Other => 4,
            })
            .unwrap();
        println!("Using device {}", physical_device.properties().device_name);

        // Create rendering surface along with window
        let surface = WindowBuilder::new()
            .with_inner_size(winit::dpi::LogicalSize::new(
                opts.window_size[0],
                opts.window_size[1],
            ))
            .with_title(opts.title)
            .build_vk_surface(event_loop, _instance.clone())
            .unwrap();
        println!("Window scale factor {}", surface.window().scale_factor());

        // Create device
        let (device, queue) = Self::create_device(physical_device, surface.clone());
        // Create swap chain & frame(s) to which we'll render
        let (swap_chain, final_images) = Self::create_swap_chain(
            surface.clone(),
            physical_device,
            device.clone(),
            queue.clone(),
            if opts.v_sync {
                PresentMode::Fifo
            } else {
                PresentMode::Immediate
            },
        );
        let previous_frame_end = Some(sync::now(device.clone()).boxed());
        let is_fullscreen = swap_chain.surface().window().fullscreen().is_some();
        let image_format = final_images.first().unwrap().format();
        let render_passes = RenderPasses {
            place_over_frame: RenderPassPlaceOverFrame::new(queue.clone(), image_format),
        };

        Renderer {
            _debug_callback,
            _instance,
            device,
            surface,
            queue,
            swap_chain,
            image_index: 0,
            final_views: final_images,
            interim_image_views: HashMap::new(),
            previous_frame_end,
            recreate_swapchain: false,
            render_passes,
            is_fullscreen,
        }
    }

    /// Creates vulkan device with required queue families and required extensions
    fn create_device(
        physical: PhysicalDevice,
        surface: Arc<Surface<Window>>,
    ) -> (Arc<Device>, Arc<Queue>) {
        let queue_family = physical
            .queue_families()
            .find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false))
            .unwrap();

        // Add device extensions based on needs,
        let device_extensions = DeviceExtensions {
            khr_swapchain: true,
            ..DeviceExtensions::none()
        };

        // Add device features
        let features = Features {
            fill_mode_non_solid: true,
            ..Features::none()
        };
        let (device, mut queues) = {
            Device::new(
                physical,
                &features,
                &physical.required_extensions().union(&device_extensions),
                [(queue_family, 0.5)].iter().cloned(),
            )
            .unwrap()
        };
        (device, queues.next().unwrap())
    }

    /// Creates swapchain and swapchain images
    fn create_swap_chain(
        surface: Arc<Surface<Window>>,
        physical: PhysicalDevice,
        device: Arc<Device>,
        queue: Arc<Queue>,
        present_mode: PresentMode,
    ) -> (Arc<Swapchain<Window>>, Vec<FinalImageView>) {
        let caps = surface.capabilities(physical).unwrap();
        let alpha = caps.supported_composite_alpha.iter().next().unwrap();
        let format = caps.supported_formats[0].0;
        let dimensions: [u32; 2] = surface.window().inner_size().into();
        let (swap_chain, images) = Swapchain::start(device, surface)
            .num_images(caps.min_image_count)
            .format(format)
            .dimensions(dimensions)
            .usage(ImageUsage::color_attachment())
            .sharing_mode(&queue)
            .composite_alpha(alpha)
            .transform(SurfaceTransform::Identity)
            .present_mode(present_mode)
            .fullscreen_exclusive(FullscreenExclusive::Default)
            .clipped(true)
            .color_space(ColorSpace::SrgbNonLinear)
            .layers(1)
            .build()
            .unwrap();
        let images = images
            .into_iter()
            .map(|image| ImageView::new(image).unwrap())
            .collect::<Vec<_>>();
        (swap_chain, images)
    }

    /// Return default image format for images (swapchain format may differ)
    pub fn image_format(&self) -> Format {
        Format::R8G8B8A8_UNORM
    }

    /// Return swapchain image format
    #[allow(unused)]
    pub fn swapchain_format(&self) -> Format {
        self.final_views[self.image_index].format()
    }

    /// Returns the index of last swapchain image that is the next render target
    /// All camera views will render onto their image at the same index
    #[allow(unused)]
    pub fn image_index(&self) -> usize {
        self.image_index
    }

    /// Access device
    pub fn device(&self) -> Arc<Device> {
        self.device.clone()
    }

    /// Access rendering queue
    pub fn queue(&self) -> Arc<Queue> {
        self.queue.clone()
    }

    /// Render target surface
    #[allow(unused)]
    pub fn surface(&self) -> Arc<Surface<Window>> {
        self.surface.clone()
    }

    /// Winit window
    pub fn window(&self) -> &Window {
        self.surface.window()
    }

    /// Winit window size
    #[allow(unused)]
    pub fn window_size(&self) -> [u32; 2] {
        let size = self.window().inner_size();
        [size.width, size.height]
    }

    /// Size of the final swapchain image (surface)
    pub fn final_image_size(&self) -> [u32; 2] {
        self.final_views[0].image().dimensions().width_height()
    }

    /// Return final image which can be used as a render pipeline target
    pub fn final_image(&self) -> FinalImageView {
        self.final_views[self.image_index].clone()
    }

    /// Return scale factor accounted window size
    #[allow(unused)]
    pub fn resolution(&self) -> [u32; 2] {
        let size = self.window().inner_size();
        let scale_factor = self.window().scale_factor();
        [
            (size.width as f64 / scale_factor) as u32,
            (size.height as f64 / scale_factor) as u32,
        ]
    }

    /// Add interim image view that can be used as a render target.
    pub fn add_interim_image_view(
        &mut self,
        key: usize,
        view_size: Option<[u32; 2]>,
        format: Format,
    ) {
        let image = ImageView::new(
            AttachmentImage::multisampled_with_usage(
                self.device(),
                if view_size.is_some() {
                    view_size.unwrap()
                } else {
                    self.final_image_size()
                },
                SampleCount::Sample1,
                format,
                ImageUsage {
                    sampled: true,
                    // So we can use the image as an input attachment
                    input_attachment: true,
                    // So we can write to the image in e.g. a compute shader
                    storage: true,
                    ..ImageUsage::none()
                },
            )
            .unwrap(),
        )
        .unwrap();
        self.interim_image_views
            .insert(key, (image.clone(), !view_size.is_some()));
    }

    /// Get interim image view by key
    pub fn get_interim_image_view(&mut self, key: usize) -> InterimImageView {
        self.interim_image_views.get(&key).unwrap().clone().0
    }

    /// Remove an interim image view from the renderer
    pub fn remove_interim_image_view(&mut self, key: usize) {
        self.interim_image_views.remove(&key);
    }

    /// Toggles fullscreen view
    pub fn toggle_fullscreen(&mut self) {
        self.is_fullscreen = !self.is_fullscreen;
        self.window().set_fullscreen(if self.is_fullscreen {
            Some(Fullscreen::Borderless(self.window().current_monitor()))
        } else {
            None
        });
    }

    /// Resize swapchain and camera view images
    pub fn resize(&mut self) {
        self.recreate_swapchain = true
    }

    /*================
    RENDERING
    =================*/

    /// Acquires next swapchain image and increments image index
    /// This is the first to call in render orchestration.
    /// Returns a gpu future representing the time after which the swapchain image has been acquired
    /// and previous frame ended.
    /// After this, execute command buffers and return future from them to `finish_frame`.
    pub(crate) fn start_frame(&mut self) -> Result<Box<dyn GpuFuture>, AcquireError> {
        // Recreate swap chain if needed (when resizing of window occurs or swapchain is outdated)
        // Also resize render views if needed
        if self.recreate_swapchain {
            self.recreate_swapchain_and_views();
        }

        // Acquire next image in the swapchain
        let (image_num, suboptimal, acquire_future) =
            match swapchain::acquire_next_image(self.swap_chain.clone(), None) {
                Ok(r) => r,
                Err(AcquireError::OutOfDate) => {
                    self.recreate_swapchain = true;
                    return Err(AcquireError::OutOfDate);
                }
                Err(e) => panic!("Failed to acquire next image: {:?}", e),
            };
        if suboptimal {
            self.recreate_swapchain = true;
        }
        // Update our image index
        self.image_index = image_num;

        let future = self.previous_frame_end.take().unwrap().join(acquire_future);
        Ok(future.boxed())
    }

    /// Finishes render by presenting the swapchain
    pub(crate) fn finish_frame(&mut self, after_future: Box<dyn GpuFuture>) {
        let future = after_future
            .then_swapchain_present(
                self.queue.clone(),
                self.swap_chain.clone(),
                self.image_index,
            )
            .then_signal_fence_and_flush();
        match future {
            Ok(future) => {
                // Prevent OutOfMemory error on Nvidia :(
                // https://github.com/vulkano-rs/vulkano/issues/627
                match future.wait(None) {
                    Ok(x) => x,
                    Err(err) => println!("{:?}", err),
                }
                self.previous_frame_end = Some(future.boxed());
            }
            Err(FlushError::OutOfDate) => {
                self.recreate_swapchain = true;
                self.previous_frame_end = Some(sync::now(self.device.clone()).boxed());
            }
            Err(e) => {
                println!("Failed to flush future: {:?}", e);
                self.previous_frame_end = Some(sync::now(self.device.clone()).boxed());
            }
        }
    }

    /// Swapchain is recreated when resized. Interim image views that should follow swapchain
    /// are also recreated
    fn recreate_swapchain_and_views(&mut self) {
        let dimensions: [u32; 2] = self.window().inner_size().into();
        let (new_swapchain, new_images) =
            match self.swap_chain.recreate().dimensions(dimensions).build() {
                Ok(r) => r,
                Err(SwapchainCreationError::UnsupportedDimensions) => {
                    println!(
                        "{}",
                        SwapchainCreationError::UnsupportedDimensions.to_string()
                    );
                    return;
                }
                Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
            };

        self.swap_chain = new_swapchain;
        let new_images = new_images
            .into_iter()
            .map(|image| ImageView::new(image).unwrap())
            .collect::<Vec<_>>();
        self.final_views = new_images;
        // Resize images that follow swapchain size
        let resizable_views = self
            .interim_image_views
            .iter()
            .filter(|(_, (_img, follow_swapchain))| *follow_swapchain)
            .map(|c| *c.0)
            .collect::<Vec<usize>>();
        for i in resizable_views {
            self.remove_interim_image_view(i);
            self.add_interim_image_view(i, None, self.image_format());
        }
        self.recreate_swapchain = false;
    }
}

/// Between `start_frame` and `end_frame` use this pipeline to fill framebuffer with your interim image
pub fn image_over_frame_renderpass<F>(
    renderer: &mut Renderer,
    before_pipeline_future: F,
    image: InterimImageView,
) -> Box<dyn GpuFuture>
where
    F: GpuFuture + 'static,
{
    renderer
        .render_passes
        .place_over_frame
        .render(before_pipeline_future, image, renderer.final_image())
        .then_signal_fence_and_flush()
        .unwrap()
        .boxed()
}
<commit_msg>Remove validation layer request from fractal example (#1708)<commit_after>// Copyright (c) 2021 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://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.

use crate::place_over_frame::RenderPassPlaceOverFrame;

use vulkano_win::VkSurfaceBuild;

use std::collections::HashMap;
use std::sync::Arc;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features, Queue};
use vulkano::format::Format;
use vulkano::image::view::ImageView;
use vulkano::image::{AttachmentImage, ImageUsage, ImageViewAbstract, SampleCount, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::instance::InstanceExtensions;
use vulkano::swapchain::{
    AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform,
    Swapchain, SwapchainCreationError,
};
use vulkano::sync::{FlushError, GpuFuture};
use vulkano::{swapchain, sync, Version};
use winit::event_loop::EventLoop;
use winit::window::{Fullscreen, Window, WindowBuilder};

/// Final render target (swapchain image)
pub type FinalImageView = Arc<ImageView<Arc<SwapchainImage<Window>>>>;
/// Other intermediate render targets
pub type InterimImageView = Arc<ImageView<Arc<AttachmentImage>>>;

/// A simple struct to organize renderpasses.
/// You could add more here. E.g. the `frame_system`
/// from the deferred examples...
pub struct RenderPasses {
    pub place_over_frame: RenderPassPlaceOverFrame,
}

#[derive(Debug, Copy, Clone)]
pub struct RenderOptions {
    pub title: &'static str,
    pub window_size: [u32; 2],
    pub v_sync: bool,
}

impl Default for RenderOptions {
    fn default() -> Self {
        RenderOptions {
            title: "App",
            window_size: [1920, 1080],
            v_sync: false,
        }
    }
}

pub struct Renderer {
    _instance: Arc<Instance>,
    device: Arc<Device>,
    surface: Arc<Surface<Window>>,
    queue: Arc<Queue>,
    swap_chain: Arc<Swapchain<Window>>,
    image_index: usize,
    final_views: Vec<FinalImageView>,
    /// Image view that is to be rendered with our pipeline.
    /// (bool refers to whether it should get resized with swapchain resize)
    interim_image_views: HashMap<usize, (InterimImageView, bool)>,
    recreate_swapchain: bool,
    previous_frame_end: Option<Box<dyn GpuFuture>>,
    render_passes: RenderPasses,
    is_fullscreen: bool,
}

impl Renderer {
    /// Creates a new GPU renderer for window with given parameters
    pub fn new(event_loop: &EventLoop<()>, opts: RenderOptions) -> Self {
        println!("Creating renderer for window size {:?}", opts.window_size);
        // Add instance extensions based on needs
        let instance_extensions = InstanceExtensions {
            ..vulkano_win::required_extensions()
        };
        // Create instance
        let _instance = Instance::new(None, Version::V1_2, &instance_extensions, None)
            .expect("Failed to create instance");

        // Get desired device
        let physical_device = PhysicalDevice::enumerate(&_instance)
            .min_by_key(|p| match p.properties().device_type {
                PhysicalDeviceType::DiscreteGpu => 0,
                PhysicalDeviceType::IntegratedGpu => 1,
                PhysicalDeviceType::VirtualGpu => 2,
                PhysicalDeviceType::Cpu => 3,
                PhysicalDeviceType::Other => 4,
            })
            .unwrap();
        println!("Using device {}", physical_device.properties().device_name);

        // Create rendering surface along with window
        let surface = WindowBuilder::new()
            .with_inner_size(winit::dpi::LogicalSize::new(
                opts.window_size[0],
                opts.window_size[1],
            ))
            .with_title(opts.title)
            .build_vk_surface(event_loop, _instance.clone())
            .unwrap();
        println!("Window scale factor {}", surface.window().scale_factor());

        // Create device
        let (device, queue) = Self::create_device(physical_device, surface.clone());
        // Create swap chain & frame(s) to which we'll render
        let (swap_chain, final_images) = Self::create_swap_chain(
            surface.clone(),
            physical_device,
            device.clone(),
            queue.clone(),
            if opts.v_sync {
                PresentMode::Fifo
            } else {
                PresentMode::Immediate
            },
        );
        let previous_frame_end = Some(sync::now(device.clone()).boxed());
        let is_fullscreen = swap_chain.surface().window().fullscreen().is_some();
        let image_format = final_images.first().unwrap().format();
        let render_passes = RenderPasses {
            place_over_frame: RenderPassPlaceOverFrame::new(queue.clone(), image_format),
        };

        Renderer {
            _instance,
            device,
            surface,
            queue,
            swap_chain,
            image_index: 0,
            final_views: final_images,
            interim_image_views: HashMap::new(),
            previous_frame_end,
            recreate_swapchain: false,
            render_passes,
            is_fullscreen,
        }
    }

    /// Creates vulkan device with required queue families and required extensions
    fn create_device(
        physical: PhysicalDevice,
        surface: Arc<Surface<Window>>,
    ) -> (Arc<Device>, Arc<Queue>) {
        let queue_family = physical
            .queue_families()
            .find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false))
            .unwrap();

        // Add device extensions based on needs,
        let device_extensions = DeviceExtensions {
            khr_swapchain: true,
            ..DeviceExtensions::none()
        };

        // Add device features
        let features = Features {
            fill_mode_non_solid: true,
            ..Features::none()
        };
        let (device, mut queues) = {
            Device::new(
                physical,
                &features,
                &physical.required_extensions().union(&device_extensions),
                [(queue_family, 0.5)].iter().cloned(),
            )
            .unwrap()
        };
        (device, queues.next().unwrap())
    }

    /// Creates swapchain and swapchain images
    fn create_swap_chain(
        surface: Arc<Surface<Window>>,
        physical: PhysicalDevice,
        device: Arc<Device>,
        queue: Arc<Queue>,
        present_mode: PresentMode,
    ) -> (Arc<Swapchain<Window>>, Vec<FinalImageView>) {
        let caps = surface.capabilities(physical).unwrap();
        let alpha = caps.supported_composite_alpha.iter().next().unwrap();
        let format = caps.supported_formats[0].0;
        let dimensions: [u32; 2] = surface.window().inner_size().into();
        let (swap_chain, images) = Swapchain::start(device, surface)
            .num_images(caps.min_image_count)
            .format(format)
            .dimensions(dimensions)
            .usage(ImageUsage::color_attachment())
            .sharing_mode(&queue)
            .composite_alpha(alpha)
            .transform(SurfaceTransform::Identity)
            .present_mode(present_mode)
            .fullscreen_exclusive(FullscreenExclusive::Default)
            .clipped(true)
            .color_space(ColorSpace::SrgbNonLinear)
            .layers(1)
            .build()
            .unwrap();
        let images = images
            .into_iter()
            .map(|image| ImageView::new(image).unwrap())
            .collect::<Vec<_>>();
        (swap_chain, images)
    }

    /// Return default image format for images (swapchain format may differ)
    pub fn image_format(&self) -> Format {
        Format::R8G8B8A8_UNORM
    }

    /// Return swapchain image format
    #[allow(unused)]
    pub fn swapchain_format(&self) -> Format {
        self.final_views[self.image_index].format()
    }

    /// Returns the index of last swapchain image that is the next render target
    /// All camera views will render onto their image at the same index
    #[allow(unused)]
    pub fn image_index(&self) -> usize {
        self.image_index
    }

    /// Access device
    pub fn device(&self) -> Arc<Device> {
        self.device.clone()
    }

    /// Access rendering queue
    pub fn queue(&self) -> Arc<Queue> {
        self.queue.clone()
    }

    /// Render target surface
    #[allow(unused)]
    pub fn surface(&self) -> Arc<Surface<Window>> {
        self.surface.clone()
    }

    /// Winit window
    pub fn window(&self) -> &Window {
        self.surface.window()
    }

    /// Winit window size
    #[allow(unused)]
    pub fn window_size(&self) -> [u32; 2] {
        let size = self.window().inner_size();
        [size.width, size.height]
    }

    /// Size of the final swapchain image (surface)
    pub fn final_image_size(&self) -> [u32; 2] {
        self.final_views[0].image().dimensions().width_height()
    }

    /// Return final image which can be used as a render pipeline target
    pub fn final_image(&self) -> FinalImageView {
        self.final_views[self.image_index].clone()
    }

    /// Return scale factor accounted window size
    #[allow(unused)]
    pub fn resolution(&self) -> [u32; 2] {
        let size = self.window().inner_size();
        let scale_factor = self.window().scale_factor();
        [
            (size.width as f64 / scale_factor) as u32,
            (size.height as f64 / scale_factor) as u32,
        ]
    }

    /// Add interim image view that can be used as a render target.
    pub fn add_interim_image_view(
        &mut self,
        key: usize,
        view_size: Option<[u32; 2]>,
        format: Format,
    ) {
        let image = ImageView::new(
            AttachmentImage::multisampled_with_usage(
                self.device(),
                if view_size.is_some() {
                    view_size.unwrap()
                } else {
                    self.final_image_size()
                },
                SampleCount::Sample1,
                format,
                ImageUsage {
                    sampled: true,
                    // So we can use the image as an input attachment
                    input_attachment: true,
                    // So we can write to the image in e.g. a compute shader
                    storage: true,
                    ..ImageUsage::none()
                },
            )
            .unwrap(),
        )
        .unwrap();
        self.interim_image_views
            .insert(key, (image.clone(), !view_size.is_some()));
    }

    /// Get interim image view by key
    pub fn get_interim_image_view(&mut self, key: usize) -> InterimImageView {
        self.interim_image_views.get(&key).unwrap().clone().0
    }

    /// Remove an interim image view from the renderer
    pub fn remove_interim_image_view(&mut self, key: usize) {
        self.interim_image_views.remove(&key);
    }

    /// Toggles fullscreen view
    pub fn toggle_fullscreen(&mut self) {
        self.is_fullscreen = !self.is_fullscreen;
        self.window().set_fullscreen(if self.is_fullscreen {
            Some(Fullscreen::Borderless(self.window().current_monitor()))
        } else {
            None
        });
    }

    /// Resize swapchain and camera view images
    pub fn resize(&mut self) {
        self.recreate_swapchain = true
    }

    /*================
    RENDERING
    =================*/

    /// Acquires next swapchain image and increments image index
    /// This is the first to call in render orchestration.
    /// Returns a gpu future representing the time after which the swapchain image has been acquired
    /// and previous frame ended.
    /// After this, execute command buffers and return future from them to `finish_frame`.
    pub(crate) fn start_frame(&mut self) -> Result<Box<dyn GpuFuture>, AcquireError> {
        // Recreate swap chain if needed (when resizing of window occurs or swapchain is outdated)
        // Also resize render views if needed
        if self.recreate_swapchain {
            self.recreate_swapchain_and_views();
        }

        // Acquire next image in the swapchain
        let (image_num, suboptimal, acquire_future) =
            match swapchain::acquire_next_image(self.swap_chain.clone(), None) {
                Ok(r) => r,
                Err(AcquireError::OutOfDate) => {
                    self.recreate_swapchain = true;
                    return Err(AcquireError::OutOfDate);
                }
                Err(e) => panic!("Failed to acquire next image: {:?}", e),
            };
        if suboptimal {
            self.recreate_swapchain = true;
        }
        // Update our image index
        self.image_index = image_num;

        let future = self.previous_frame_end.take().unwrap().join(acquire_future);
        Ok(future.boxed())
    }

    /// Finishes render by presenting the swapchain
    pub(crate) fn finish_frame(&mut self, after_future: Box<dyn GpuFuture>) {
        let future = after_future
            .then_swapchain_present(
                self.queue.clone(),
                self.swap_chain.clone(),
                self.image_index,
            )
            .then_signal_fence_and_flush();
        match future {
            Ok(future) => {
                // Prevent OutOfMemory error on Nvidia :(
                // https://github.com/vulkano-rs/vulkano/issues/627
                match future.wait(None) {
                    Ok(x) => x,
                    Err(err) => println!("{:?}", err),
                }
                self.previous_frame_end = Some(future.boxed());
            }
            Err(FlushError::OutOfDate) => {
                self.recreate_swapchain = true;
                self.previous_frame_end = Some(sync::now(self.device.clone()).boxed());
            }
            Err(e) => {
                println!("Failed to flush future: {:?}", e);
                self.previous_frame_end = Some(sync::now(self.device.clone()).boxed());
            }
        }
    }

    /// Swapchain is recreated when resized. Interim image views that should follow swapchain
    /// are also recreated
    fn recreate_swapchain_and_views(&mut self) {
        let dimensions: [u32; 2] = self.window().inner_size().into();
        let (new_swapchain, new_images) =
            match self.swap_chain.recreate().dimensions(dimensions).build() {
                Ok(r) => r,
                Err(SwapchainCreationError::UnsupportedDimensions) => {
                    println!(
                        "{}",
                        SwapchainCreationError::UnsupportedDimensions.to_string()
                    );
                    return;
                }
                Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
            };

        self.swap_chain = new_swapchain;
        let new_images = new_images
            .into_iter()
            .map(|image| ImageView::new(image).unwrap())
            .collect::<Vec<_>>();
        self.final_views = new_images;
        // Resize images that follow swapchain size
        let resizable_views = self
            .interim_image_views
            .iter()
            .filter(|(_, (_img, follow_swapchain))| *follow_swapchain)
            .map(|c| *c.0)
            .collect::<Vec<usize>>();
        for i in resizable_views {
            self.remove_interim_image_view(i);
            self.add_interim_image_view(i, None, self.image_format());
        }
        self.recreate_swapchain = false;
    }
}

/// Between `start_frame` and `end_frame` use this pipeline to fill framebuffer with your interim image
pub fn image_over_frame_renderpass<F>(
    renderer: &mut Renderer,
    before_pipeline_future: F,
    image: InterimImageView,
) -> Box<dyn GpuFuture>
where
    F: GpuFuture + 'static,
{
    renderer
        .render_passes
        .place_over_frame
        .render(before_pipeline_future, image, renderer.final_image())
        .then_signal_fence_and_flush()
        .unwrap()
        .boxed()
}
<|endoftext|>


<commit_before>//! Contains interface for a pull-based (StAX-like) FBX parser.

use std::io::Read;
use self::error::Result;

pub use self::error::{Error, ErrorKind};
use common::{FbxFormatType, OwnedProperty};

mod error;
mod parser;

/// A node of an FBX input stream.
///
/// Items of this enum are emitted by [`reader::EventReader`](struct.EventReader.html).
#[derive(Debug, Clone)]
pub enum FbxEvent {
    /// Denotes start of FBX data.
    ///
    /// For Binary FBX, this item corresponds to magic binary.
    StartFbx(FbxFormatType),
    /// Denotes end of FBX data.
    ///
    /// NOTE: Current implementation of Binary FBX parser does not read to the last byte of the FBX stream.
    EndFbx,
    /// Denotes beginning of a node.
    StartNode {
        /// Node name.
        name: String,
        /// Node properties.
        properties: Vec<OwnedProperty>,
    },
    /// Denotes end of a node.
    EndNode,
    /// Comment.
    ///
    /// Comment only appears in ASCII FBX.
    Comment(String),
}

impl FbxEvent {
    pub fn as_writer_event<'a>(&'a self) -> ::writer::FbxEvent {
        use writer::FbxEvent as WriterEvent;
        match *self {
            FbxEvent::StartFbx(ref format) => WriterEvent::StartFbx(format.clone()),
            FbxEvent::EndFbx => WriterEvent::EndFbx,
            FbxEvent::StartNode{ ref name, ref properties } => WriterEvent::StartNode {
                name: &name,
                properties: properties.iter().map(|p| p.borrow()).collect(),
            },
            FbxEvent::EndNode => WriterEvent::EndNode,
            FbxEvent::Comment(ref msg) => WriterEvent::Comment(&msg),
        }
    }
}

/// A wrapper around an `std::io::Read` instance which provides pull-based FBX parsing.
pub struct EventReader<R: Read> {
    source: R,
    parser: parser::Parser,
}

impl<R: Read> EventReader<R> {
    /// Creates a new reader, consuming the given stream.
    pub fn new(source: R) -> Self {
        EventReader {
            source: source,
            parser: parser::Parser::new(ParserConfig::new()),
        }
    }

    /// Creates a new reader with provided configuration, consuming the given stream.
    pub fn new_with_config(source: R, config: ParserConfig) -> Self {
        EventReader {
            source: source,
            parser: parser::Parser::new(config),
        }
    }

    /// Pulls and returns next FBX event from the stream.
    pub fn next(&mut self) -> Result<FbxEvent> {
        self.parser.next(&mut self.source)
    }
}

impl <R: Read> IntoIterator for EventReader<R> {
    type Item = Result<FbxEvent>;
    type IntoIter = Events<R>;

    /// Consumes `EventReader` and returns an iterator (`Events`) over it.
    fn into_iter(self) -> Events<R> {
        Events {
            reader: self,
            finished: false,
        }
    }
}

/// An iterator over FBX events created from some type implementing `Read`.
///
/// When the next event is [`reader::error::Error`](struct.Error.html) or
/// [`reader::FbxEvent::EndFbx`](enum.FbxEvent.html) then it will be returned
/// by the iterator once, and then it will stop producing events.
pub struct Events<R: Read> {
    reader: EventReader<R>,
    finished: bool,
}

impl<R: Read> Events<R> {
    /// Returns internal `EventReader`.
    #[allow(dead_code)]
    fn into_inner(self) -> EventReader<R> {
        self.reader
    }
}

impl<R: Read> Iterator for Events<R> {
    type Item = Result<FbxEvent>;

    fn next(&mut self) -> Option<Result<FbxEvent>> {
        if self.finished {
            None
        } else {
            let ev = self.reader.next();
            match ev {
                Ok(FbxEvent::EndFbx) | Err(_) => self.finished = true,
                _ => {}
            }
            Some(ev)
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParserConfig {
    pub ignore_comments: bool,
}

impl ParserConfig {
    /// Creates a new config with default options.
    pub fn new() -> Self {
        ParserConfig {
            ignore_comments: false,
        }
    }

    /// Creates an FBX reader with this configuration.
    pub fn create_reader<R: Read>(self, source: R) -> EventReader<R> {
        EventReader::new_with_config(source, self)
    }

    /// Sets the field to provided value and returns updated config object.
    pub fn ignore_comments(mut self, value: bool) -> Self {
        self.ignore_comments = value;
        self
    }
}

impl Default for ParserConfig {
    fn default() -> ParserConfig {
        ParserConfig::new()
    }
}
<commit_msg>Add TODO to source code<commit_after>//! Contains interface for a pull-based (StAX-like) FBX parser.

use std::io::Read;
use self::error::Result;

pub use self::error::{Error, ErrorKind};
use common::{FbxFormatType, OwnedProperty};

mod error;
mod parser;

/// A node of an FBX input stream.
///
/// Items of this enum are emitted by [`reader::EventReader`](struct.EventReader.html).
#[derive(Debug, Clone)]
pub enum FbxEvent {
    /// Denotes start of FBX data.
    ///
    /// For Binary FBX, this item corresponds to magic binary.
    StartFbx(FbxFormatType),
    /// Denotes end of FBX data.
    ///
    /// NOTE: Current implementation of Binary FBX parser does not read to the last byte of the FBX stream.
    EndFbx,
    /// Denotes beginning of a node.
    StartNode {
        /// Node name.
        name: String,
        /// Node properties.
        properties: Vec<OwnedProperty>,
    },
    /// Denotes end of a node.
    EndNode,
    /// Comment.
    ///
    /// Comment only appears in ASCII FBX.
    Comment(String),
}

impl FbxEvent {
    pub fn as_writer_event<'a>(&'a self) -> ::writer::FbxEvent {
        use writer::FbxEvent as WriterEvent;
        match *self {
            FbxEvent::StartFbx(ref format) => WriterEvent::StartFbx(format.clone()),
            FbxEvent::EndFbx => WriterEvent::EndFbx,
            FbxEvent::StartNode{ ref name, ref properties } => WriterEvent::StartNode {
                name: &name,
                properties: properties.iter().map(|p| p.borrow()).collect(),
            },
            FbxEvent::EndNode => WriterEvent::EndNode,
            FbxEvent::Comment(ref msg) => WriterEvent::Comment(&msg),
        }
    }
}

/// A wrapper around an `std::io::Read` instance which provides pull-based FBX parsing.
pub struct EventReader<R: Read> {
    source: R,
    parser: parser::Parser,
}

impl<R: Read> EventReader<R> {
    /// Creates a new reader, consuming the given stream.
    pub fn new(source: R) -> Self {
        EventReader {
            source: source,
            parser: parser::Parser::new(ParserConfig::new()),
        }
    }

    /// Creates a new reader with provided configuration, consuming the given stream.
    pub fn new_with_config(source: R, config: ParserConfig) -> Self {
        EventReader {
            source: source,
            parser: parser::Parser::new(config),
        }
    }

    /// Pulls and returns next FBX event from the stream.
    pub fn next(&mut self) -> Result<FbxEvent> {
        self.parser.next(&mut self.source)
    }
}

impl <R: Read> IntoIterator for EventReader<R> {
    type Item = Result<FbxEvent>;
    type IntoIter = Events<R>;

    /// Consumes `EventReader` and returns an iterator (`Events`) over it.
    fn into_iter(self) -> Events<R> {
        Events {
            reader: self,
            finished: false,
        }
    }
}

/// An iterator over FBX events created from some type implementing `Read`.
///
/// When the next event is [`reader::error::Error`](struct.Error.html) or
/// [`reader::FbxEvent::EndFbx`](enum.FbxEvent.html) then it will be returned
/// by the iterator once, and then it will stop producing events.
pub struct Events<R: Read> {
    reader: EventReader<R>,
    finished: bool,
}

impl<R: Read> Events<R> {
    /// Returns internal `EventReader`.
    #[allow(dead_code)]
    fn into_inner(self) -> EventReader<R> {
        self.reader
    }
}

impl<R: Read> Iterator for Events<R> {
    type Item = Result<FbxEvent>;

    fn next(&mut self) -> Option<Result<FbxEvent>> {
        if self.finished {
            None
        } else {
            let ev = self.reader.next();
            match ev {
                Ok(FbxEvent::EndFbx) | Err(_) => self.finished = true,
                _ => {}
            }
            Some(ev)
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParserConfig {
    pub ignore_comments: bool,
    // TODO: add strict mode
    //pub strict: bool,
}

impl ParserConfig {
    /// Creates a new config with default options.
    pub fn new() -> Self {
        ParserConfig {
            ignore_comments: false,
        }
    }

    /// Creates an FBX reader with this configuration.
    pub fn create_reader<R: Read>(self, source: R) -> EventReader<R> {
        EventReader::new_with_config(source, self)
    }

    /// Sets the field to provided value and returns updated config object.
    pub fn ignore_comments(mut self, value: bool) -> Self {
        self.ignore_comments = value;
        self
    }
}

impl Default for ParserConfig {
    fn default() -> ParserConfig {
        ParserConfig::new()
    }
}
<|endoftext|>