<commit_before>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num,hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost < other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            a.r*a.r-b.r*b.r + a.g*a.g-b.g*b.g + a.b*a.b-b.b*b.b ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    ~[~[]]
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);

    // width and height should be replaced by just reading them from the file
    let width = match from_str::<int>(argv[2]) {
        Some(x) => x,
        None() => 0
    };
    let height = match from_str::<int>(argv[3]) {
        Some(x) => x,
        None() => 0
    };

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[ ~[]];
    let mut heit = 0;
    let mut wid = 0;
    loop {
        loop {
            find_arcs[heit][wid] = arc::RWArc::new(pixels[heit][wid]);
                wid+=1;
            if(wid == width) {
                wid = 0;
                break;
            }
        }
        heit+=1;
        if(heit == height) {
            break;
        }
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(0,width-1),(height-1,0),(height-1,width-1) ];

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        let shared_pixels = pixels.clone();
        do spawn { // split into threads here

            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();

            let mut newvisit: bool = true;

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x,y-1)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been or colored
                            let mut col = 0;
                            do shared_arcs[w][z].read |edg| {
                                col = edg.color;
                            }
                            if col < 0 { // then we have a new vertex
                                queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(&shared_pixels[x][y],&shared_pixels[w][z])));
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                Some(e) => {
                        let mut col = 0;
                        do shared_arcs[e.dest.x][e.dest.y].read |dest| {
                        col = dest.color;
                        }
                        if col < 0 {
                            // not in any tree
                            let coord = (e.dest.x,e.dest.y);
                            if *visited.get(&coord) == false { // use visited hashmap to figure out if we're at a new vertex
                                visited.insert(coord,true);
                                x = e.dest.x;
                                y = e.dest.y;
                            newvisit = true;
                            } else {
                                newvisit = false;
                            }

                            // use an arc to write the following
                            //                    pixels[e.dest.x][e.dest.y].color = pixels[e.source.x][e.source.y].color;
                            do shared_arcs[e.dest.x][e.dest.y].write |dest| {
                                do shared_arcs[e.source.x][e.source.y].read |src| {
                                    dest.color = src.color;
                                }
                            }
                        }
                    }
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }
        }
    }
}
<commit_msg>color as we reach anode.<commit_after>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num,hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost < other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            a.r*a.r-b.r*b.r + a.g*a.g-b.g*b.g + a.b*a.b-b.b*b.b ) as float)
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    ~[~[]]
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);

    // width and height should be replaced by just reading them from the file
    let width = match from_str::<int>(argv[2]) {
        Some(x) => x,
        None() => 0
    };
    let height = match from_str::<int>(argv[3]) {
        Some(x) => x,
        None() => 0
    };

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[ ~[]];
    let mut heit = 0;
    let mut wid = 0;
    loop {
        loop {
            find_arcs[heit][wid] = arc::RWArc::new(pixels[heit][wid]);
                wid+=1;
            if(wid == width) {
                wid = 0;
                break;
            }
        }
        heit+=1;
        if(heit == height) {
            break;
        }
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let corners = [ (0,0),(0,width-1),(height-1,0),(height-1,width-1) ];

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        let shared_pixels = pixels.clone();
        do spawn { // split into threads here

            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();

            let mut newvisit: bool = true;

            loop { // iterate through items in the queue, which contains all of the edges/vertices
                if(newvisit){
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x,y-1)];
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking
                            // if neighbor at coord has not been or colored
                            let mut col = 0;
                            let mut newvertex = false;
                            do shared_arcs[w][z].write |dest| {
                                if dest.color < 0 {
                                    do shared_arcs[x][y].read |src| {
                                        dest.color = src.color;
                                    }
                                    newvertex = true;
                                }
                            }

                            if newvertex { // then we have a new vertex
                                queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(&shared_pixels[x][y],&shared_pixels[w][z])));
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop();
                match edge {
                Some(e) => {
                        let mut col = 0;
                        do shared_arcs[e.dest.x][e.dest.y].read |dest| {
                        col = dest.color;
                        }
                        if col < 0 {
                            // not in any tree
                            let coord = (e.dest.x,e.dest.y);
                            if *visited.get(&coord) == false { // use visited hashmap to figure out if we're at a new vertex
                                visited.insert(coord,true);
                                x = e.dest.x;
                                y = e.dest.y;
                                newvisit = true;
                            } else {
                                newvisit = false;
                            }
                        }
                    }
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate bytes;
extern crate futures;
extern crate native_tls;
extern crate tokio_core;
extern crate tokio_tls;
extern crate httpbis;
extern crate log;
extern crate env_logger;

use bytes::Bytes;

use std::sync::Arc;
use std::net::SocketAddr;

use futures::stream;
use futures::future::Future;

use httpbis::solicit::header::Headers;
use httpbis::server::*;
use httpbis::client::*;
use httpbis::http_common::*;
use httpbis::message::SimpleHttpMessage;

use native_tls::TlsAcceptor;
use native_tls::TlsConnector;
use native_tls::Pkcs12;
use native_tls::Certificate;

fn test_tls_acceptor() -> TlsAcceptor {
    let buf = include_bytes!("identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let mut builder = TlsAcceptor::builder(pkcs12).unwrap();
    builder.build().unwrap()
}

fn test_tls_connector() -> TlsConnector {
    let root_ca = include_bytes!("root-ca.der");
    let root_ca = Certificate::from_der(root_ca).unwrap();

    let mut builder = TlsConnector::builder().unwrap();
    builder.add_root_certificate(root_ca).expect("add_root_certificate");
    builder.build().unwrap()
}

#[test]
fn tls() {
    struct ServiceImpl {
    }

    impl HttpService for ServiceImpl {
        fn new_request(&self, _headers: Headers, _req: HttpPartFutureStreamSend) -> HttpPartFutureStreamSend {
            Box::new(stream::iter(vec![
                Ok(HttpStreamPart::intermediate_headers(Headers::ok_200())),
                Ok(HttpStreamPart::last_data(Bytes::from("hello"))),
            ]))
        }
    }

    let server = HttpServer::new(
        "[::1]:0".parse::<SocketAddr>().unwrap(),
        ServerTlsOption::Tls(Arc::new(test_tls_acceptor())),
        Default::default(),
        ServiceImpl {});

    let client: HttpClient = HttpClient::new_expl(
        server.local_addr(),
        ClientTlsOption::Tls("foobar.com".to_owned(), Arc::new(test_tls_connector())),
        Default::default())
            .expect("http client");

    let resp: SimpleHttpMessage = client.start_get_simple_response("/hi", "localhost").wait().unwrap();
    assert_eq!(200, resp.headers.status());
    assert_eq!(&b"hello"[..], &resp.body[..]);
}
<commit_msg>Warnings<commit_after>extern crate bytes;
extern crate futures;
extern crate native_tls;
extern crate tokio_core;
extern crate tokio_tls;
extern crate httpbis;
extern crate log;
extern crate env_logger;

use bytes::Bytes;

use std::sync::Arc;
use std::net::SocketAddr;

use futures::stream;
use futures::future::Future;

use httpbis::solicit::header::Headers;
use httpbis::server::*;
use httpbis::client::*;
use httpbis::http_common::*;
use httpbis::message::SimpleHttpMessage;

use native_tls::TlsAcceptor;
use native_tls::TlsConnector;
use native_tls::Pkcs12;
use native_tls::Certificate;

fn test_tls_acceptor() -> TlsAcceptor {
    let buf = include_bytes!("identity.p12");
    let pkcs12 = Pkcs12::from_der(buf, "mypass").unwrap();
    let builder = TlsAcceptor::builder(pkcs12).unwrap();
    builder.build().unwrap()
}

fn test_tls_connector() -> TlsConnector {
    let root_ca = include_bytes!("root-ca.der");
    let root_ca = Certificate::from_der(root_ca).unwrap();

    let mut builder = TlsConnector::builder().unwrap();
    builder.add_root_certificate(root_ca).expect("add_root_certificate");
    builder.build().unwrap()
}

#[test]
fn tls() {
    struct ServiceImpl {
    }

    impl HttpService for ServiceImpl {
        fn new_request(&self, _headers: Headers, _req: HttpPartFutureStreamSend) -> HttpPartFutureStreamSend {
            Box::new(stream::iter(vec![
                Ok(HttpStreamPart::intermediate_headers(Headers::ok_200())),
                Ok(HttpStreamPart::last_data(Bytes::from("hello"))),
            ]))
        }
    }

    let server = HttpServer::new(
        "[::1]:0".parse::<SocketAddr>().unwrap(),
        ServerTlsOption::Tls(Arc::new(test_tls_acceptor())),
        Default::default(),
        ServiceImpl {});

    let client: HttpClient = HttpClient::new_expl(
        server.local_addr(),
        ClientTlsOption::Tls("foobar.com".to_owned(), Arc::new(test_tls_connector())),
        Default::default())
            .expect("http client");

    let resp: SimpleHttpMessage = client.start_get_simple_response("/hi", "localhost").wait().unwrap();
    assert_eq!(200, resp.headers.status());
    assert_eq!(&b"hello"[..], &resp.body[..]);
}
<|endoftext|>


<commit_before>extern crate glsl_to_spirv;
extern crate proc_macro;
extern crate syn;
extern crate vulkano_shaders;

use proc_macro::TokenStream;

#[proc_macro_derive(VulkanoShader, attributes(src, ty))]
pub fn derive(input: TokenStream) -> TokenStream {
    let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();

    let src = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `src` attribute ; put #[src = \"...\"] for example.");

    let ty_str = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");

    let ty = match &ty_str[..] {
        "vertex" => glsl_to_spirv::ShaderType::Vertex,
        "fragment" => glsl_to_spirv::ShaderType::Fragment,
        "geometry" => glsl_to_spirv::ShaderType::Geometry,
        "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
        "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
        "compute" => glsl_to_spirv::ShaderType::Compute,
        _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
    };

    let spirv_data = match glsl_to_spirv::compile(&src, ty) {
        Ok(compiled) => compiled,
        Err(message) => panic!("{}\nfailed to compile shader", message),
    };

    vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
}
<commit_msg>Added support for #[src=filename]<commit_after>extern crate glsl_to_spirv;
extern crate proc_macro;
extern crate syn;
extern crate vulkano_shaders;

use std::path::Path;
use std::fs::File;
use std::io::Read;

use proc_macro::TokenStream;

#[proc_macro_derive(VulkanoShader, attributes(src, ty))]
pub fn derive(input: TokenStream) -> TokenStream {
    let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();

    let src = {
        let src = syn_item.attrs.iter().filter_map(|attr| {
            match attr.value {
                syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
                    Some(val.clone())
                },
                _ => None
            }
        }).next().expect("Can't find `src` attribute ; put #[src = \"...\"] for example.");

        if Path::new(&src[..]).is_file() {
            let mut buf = String::new();
            File::open(src).and_then(|mut file| file.read_to_string(&mut buf)).expect("Unable to read source from given file");
            buf
        } else {
            src
        }
    };

    println!("Source: {}", src);

    let ty_str = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");

    let ty = match &ty_str[..] {
        "vertex" => glsl_to_spirv::ShaderType::Vertex,
        "fragment" => glsl_to_spirv::ShaderType::Fragment,
        "geometry" => glsl_to_spirv::ShaderType::Geometry,
        "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
        "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
        "compute" => glsl_to_spirv::ShaderType::Compute,
        _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
    };

    let spirv_data = match glsl_to_spirv::compile(&src, ty) {
        Ok(compiled) => compiled,
        Err(message) => panic!("{}\nfailed to compile shader", message),
    };

    vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
//!
//! As far as the author knows, no existing device supports these features. Therefore the code here
//! is mostly a draft and needs rework in both the API and the implementation.

#![allow(dead_code)]        // TODO: this module isn't finished
#![allow(unused_variables)]        // TODO: this module isn't finished

use std::ffi::CStr;
use std::ptr;
use std::sync::Arc;
use std::vec::IntoIter;

use instance::Instance;
use instance::PhysicalDevice;
use swapchain::SupportedSurfaceTransforms;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

// TODO: extract this to a `display` module and solve the visibility problems

/// ?
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
    instance: Arc<Instance>,
    physical_device: usize,
    index: u32,
    properties: vk::DisplayPlanePropertiesKHR,
    supported_displays: Vec<vk::DisplayKHR>,
}

impl DisplayPlane {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: &PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> {
        let vk = device.instance().pointers();

        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let num = unsafe {
            let mut num: u32 = 0;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPlanePropertiesKHR(device.internal_object(),
                                                                            &mut num, ptr::null_mut())));
            num
        };

        let planes: Vec<vk::DisplayPlanePropertiesKHR> = unsafe {
            let mut planes = Vec::with_capacity(num as usize);
            let mut num = num;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPlanePropertiesKHR(device.internal_object(),
                                                                            &mut num,
                                                                            planes.as_mut_ptr())));
            planes.set_len(num as usize);
            planes
        };

        Ok(planes.into_iter().enumerate().map(|(index, prop)| {
            let num = unsafe {
                let mut num: u32 = 0;
                check_errors(vk.GetDisplayPlaneSupportedDisplaysKHR(device.internal_object(), index as u32,
                                                                    &mut num, ptr::null_mut())).unwrap();       // TODO: shouldn't unwrap
                num
            };

            let supported_displays: Vec<vk::DisplayKHR> = unsafe {
                let mut displays = Vec::with_capacity(num as usize);
                let mut num = num;
                check_errors(vk.GetDisplayPlaneSupportedDisplaysKHR(device.internal_object(),
                                                                    index as u32, &mut num,
                                                                    displays.as_mut_ptr())).unwrap();       // TODO: shouldn't unwrap
                displays.set_len(num as usize);
                displays
            };

            DisplayPlane {
                instance: device.instance().clone(),
                physical_device: device.index(),
                index: index as u32,
                properties: prop,
                supported_displays: supported_displays,
            }
        }).collect::<Vec<_>>().into_iter())
    }

    /// Enumerates all the display planes that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: &PhysicalDevice) -> IntoIter<DisplayPlane> {
        DisplayPlane::enumerate_raw(device).unwrap()
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the index of the plane.
    #[inline]
    pub fn index(&self) -> u32 {
        self.index
    }

    /// Returns true if this plane supports the given display.
    #[inline]
    pub fn supports(&self, display: &Display) -> bool {
        // making sure that the physical device is the same
        if self.physical_device().internal_object() != display.physical_device().internal_object() {
            return false;
        }

        self.supported_displays.iter().find(|&&d| d == display.internal_object()).is_some()
    }
}

/// Represents a monitor connected to a physical device.
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
    instance: Arc<Instance>,
    physical_device: usize,
    properties: Arc<vk::DisplayPropertiesKHR>,      // TODO: Arc because struct isn't clone
}

impl Display {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: &PhysicalDevice) -> Result<IntoIter<Display>, OomError> {
        let vk = device.instance().pointers();
        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let num = unsafe {
            let mut num = 0;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPropertiesKHR(device.internal_object(),
                                                                       &mut num, ptr::null_mut())));
            num
        };

        let displays: Vec<vk::DisplayPropertiesKHR> = unsafe {
            let mut displays = Vec::with_capacity(num as usize);
            let mut num = num;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPropertiesKHR(device.internal_object(),
                                                                       &mut num,
                                                                       displays.as_mut_ptr())));
            displays.set_len(num as usize);
            displays
        };

        Ok(displays.into_iter().map(|prop| {
            Display {
                instance: device.instance().clone(),
                physical_device: device.index(),
                properties: Arc::new(prop),
            }
        }).collect::<Vec<_>>().into_iter())
    }

    /// Enumerates all the displays that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: &PhysicalDevice) -> IntoIter<Display> {
        Display::enumerate_raw(device).unwrap()
    }

    /// Returns the name of the display.
    #[inline]
    pub fn name(&self) -> &str {
        unsafe {
            CStr::from_ptr(self.properties.displayName)
                .to_str()
                .expect("non UTF-8 characters in display name")
        }
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the physical dimensions of the display in millimeters.
    #[inline]
    pub fn physical_dimensions(&self) -> [u32; 2] {
        let ref r = self.properties.physicalDimensions;
        [r.width, r.height]
    }

    /// Returns the physical, native, or preferred resolution of the display.
    ///
    /// > **Note**: The display is usually still capable of displaying other resolutions. This is
    /// > only the "best" resolution.
    #[inline]
    pub fn physical_resolution(&self) -> [u32; 2] {
        let ref r = self.properties.physicalResolution;
        [r.width, r.height]
    }

    /// Returns the transforms supported by this display.
    #[inline]
    pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
        SupportedSurfaceTransforms::from_bits(self.properties.supportedTransforms)
    }

    /// Returns true if TODO.
    #[inline]
    pub fn plane_reorder_possible(&self) -> bool {
        self.properties.planeReorderPossible != 0
    }

    /// Returns true if TODO.
    #[inline]
    pub fn persistent_content(&self) -> bool {
        self.properties.persistentContent != 0
    }

    /// See the docs of display_modes().
    pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> {
        let vk = self.instance.pointers();

        let num = unsafe {
            let mut num = 0;
            try!(check_errors(vk.GetDisplayModePropertiesKHR(self.physical_device().internal_object(),
                                                             self.properties.display,
                                                             &mut num, ptr::null_mut())));
            num
        };

        let modes: Vec<vk::DisplayModePropertiesKHR> = unsafe {
            let mut modes = Vec::with_capacity(num as usize);
            let mut num = num;
            try!(check_errors(vk.GetDisplayModePropertiesKHR(self.physical_device().internal_object(),
                                                             self.properties.display, &mut num,
                                                             modes.as_mut_ptr())));
            modes.set_len(num as usize);
            modes
        };

        Ok(modes.into_iter().map(|mode| {
            DisplayMode {
                display: self.clone(),
                display_mode: mode.displayMode,
                parameters: mode.parameters,
            }
        }).collect::<Vec<_>>().into_iter())
    }

    /// Returns a list of all modes available on this display.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from display_modes_raw?
    #[inline]
    pub fn display_modes(&self) -> IntoIter<DisplayMode> {
        self.display_modes_raw().unwrap()
    }
}

unsafe impl VulkanObject for Display {
    type Object = vk::DisplayKHR;

    #[inline]
    fn internal_object(&self) -> vk::DisplayKHR {
        self.properties.display
    }
}

/// Represents a mode on a specific display.
pub struct DisplayMode {
    display: Display,
    display_mode: vk::DisplayModeKHR,
    parameters: vk::DisplayModeParametersKHR,
}

impl DisplayMode {
    /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> {
        let vk = instance.pointers();
        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let parameters = vk::DisplayModeParametersKHR {
            visibleRegion: vk::Extent2D { width: , height:  },
            refreshRate: ,
        };

        let display_mode = {
            let infos = vk::DisplayModeCreateInfoKHR {
                sType: vk::STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR,
                pNext: ptr::null(),
                flags: 0,   // reserved
                parameters: parameters,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDisplayModeKHR(display.device.internal_object(),
                                                      display.display, &infos, ptr::null(),
                                                      &mut output)));
            output
        };

        Ok(Arc::new(DisplayMode {
            instance: display.device.instance().clone(),
            display_mode: display_mode,
            parameters: ,
        }))
    }*/

    /// Returns the display corresponding to this mode.
    #[inline]
    pub fn display(&self) -> &Display {
        &self.display
    }

    /// Returns the dimensions of the region that is visible on the monitor.
    #[inline]
    pub fn visible_region(&self) -> [u32; 2] {
        let ref d = self.parameters.visibleRegion;
        [d.width, d.height]
    }

    /// Returns the refresh rate of this mode.
    #[inline]
    pub fn refresh_rate(&self) -> u32 {
        self.parameters.refreshRate
    }
}

unsafe impl VulkanObject for DisplayMode {
    type Object = vk::DisplayModeKHR;

    #[inline]
    fn internal_object(&self) -> vk::DisplayModeKHR {
        self.display_mode
    }
}
<commit_msg>Add some documentation to the display module<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Allows you to create surfaces that fill a whole display, outside of the windowing system.
//!
//! **As far as the author knows, no existing device supports these features. Therefore the code
//! here is mostly a draft and needs rework in both the API and the implementation.**
//!
//! The purpose of the objects in this module is to let you create a `Surface` object that
//! represents a location on the screen. This is done in four steps:
//!
//! - Choose a `Display` where the surface will be located. A `Display` represents a display
//!   display, usually a monitor. The available displays can be enumerated with
//!   `Display::enumerate`.
//! - Choose a `DisplayMode`, which is the combination of a display, a resolution and a refresh
//!   rate. You can enumerate the modes available on a display with `Display::display_modes`, or
//!   attempt to create your own mode with `TODO`.
//! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion.
//! - Create a `Surface` object with `Surface::from_display_mode` and pass the chosen `DisplayMode`
//!   and `DisplayPlane`.

#![allow(dead_code)]        // TODO: this module isn't finished
#![allow(unused_variables)]        // TODO: this module isn't finished

use std::ffi::CStr;
use std::ptr;
use std::sync::Arc;
use std::vec::IntoIter;

use instance::Instance;
use instance::PhysicalDevice;
use swapchain::SupportedSurfaceTransforms;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

// TODO: extract this to a `display` module and solve the visibility problems

/// ?
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
    instance: Arc<Instance>,
    physical_device: usize,
    index: u32,
    properties: vk::DisplayPlanePropertiesKHR,
    supported_displays: Vec<vk::DisplayKHR>,
}

impl DisplayPlane {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: &PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> {
        let vk = device.instance().pointers();

        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let num = unsafe {
            let mut num: u32 = 0;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPlanePropertiesKHR(device.internal_object(),
                                                                            &mut num, ptr::null_mut())));
            num
        };

        let planes: Vec<vk::DisplayPlanePropertiesKHR> = unsafe {
            let mut planes = Vec::with_capacity(num as usize);
            let mut num = num;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPlanePropertiesKHR(device.internal_object(),
                                                                            &mut num,
                                                                            planes.as_mut_ptr())));
            planes.set_len(num as usize);
            planes
        };

        Ok(planes.into_iter().enumerate().map(|(index, prop)| {
            let num = unsafe {
                let mut num: u32 = 0;
                check_errors(vk.GetDisplayPlaneSupportedDisplaysKHR(device.internal_object(), index as u32,
                                                                    &mut num, ptr::null_mut())).unwrap();       // TODO: shouldn't unwrap
                num
            };

            let supported_displays: Vec<vk::DisplayKHR> = unsafe {
                let mut displays = Vec::with_capacity(num as usize);
                let mut num = num;
                check_errors(vk.GetDisplayPlaneSupportedDisplaysKHR(device.internal_object(),
                                                                    index as u32, &mut num,
                                                                    displays.as_mut_ptr())).unwrap();       // TODO: shouldn't unwrap
                displays.set_len(num as usize);
                displays
            };

            DisplayPlane {
                instance: device.instance().clone(),
                physical_device: device.index(),
                index: index as u32,
                properties: prop,
                supported_displays: supported_displays,
            }
        }).collect::<Vec<_>>().into_iter())
    }

    /// Enumerates all the display planes that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: &PhysicalDevice) -> IntoIter<DisplayPlane> {
        DisplayPlane::enumerate_raw(device).unwrap()
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the index of the plane.
    #[inline]
    pub fn index(&self) -> u32 {
        self.index
    }

    /// Returns true if this plane supports the given display.
    #[inline]
    pub fn supports(&self, display: &Display) -> bool {
        // making sure that the physical device is the same
        if self.physical_device().internal_object() != display.physical_device().internal_object() {
            return false;
        }

        self.supported_displays.iter().find(|&&d| d == display.internal_object()).is_some()
    }
}

/// Represents a monitor connected to a physical device.
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
    instance: Arc<Instance>,
    physical_device: usize,
    properties: Arc<vk::DisplayPropertiesKHR>,      // TODO: Arc because struct isn't clone
}

impl Display {
    /// See the docs of enumerate().
    pub fn enumerate_raw(device: &PhysicalDevice) -> Result<IntoIter<Display>, OomError> {
        let vk = device.instance().pointers();
        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let num = unsafe {
            let mut num = 0;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPropertiesKHR(device.internal_object(),
                                                                       &mut num, ptr::null_mut())));
            num
        };

        let displays: Vec<vk::DisplayPropertiesKHR> = unsafe {
            let mut displays = Vec::with_capacity(num as usize);
            let mut num = num;
            try!(check_errors(vk.GetPhysicalDeviceDisplayPropertiesKHR(device.internal_object(),
                                                                       &mut num,
                                                                       displays.as_mut_ptr())));
            displays.set_len(num as usize);
            displays
        };

        Ok(displays.into_iter().map(|prop| {
            Display {
                instance: device.instance().clone(),
                physical_device: device.index(),
                properties: Arc::new(prop),
            }
        }).collect::<Vec<_>>().into_iter())
    }

    /// Enumerates all the displays that are available on a given physical device.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from raw constructor?
    #[inline]
    pub fn enumerate(device: &PhysicalDevice) -> IntoIter<Display> {
        Display::enumerate_raw(device).unwrap()
    }

    /// Returns the name of the display.
    #[inline]
    pub fn name(&self) -> &str {
        unsafe {
            CStr::from_ptr(self.properties.displayName)
                .to_str()
                .expect("non UTF-8 characters in display name")
        }
    }

    /// Returns the physical device that was used to create this display.
    #[inline]
    pub fn physical_device(&self) -> PhysicalDevice {
        PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
    }

    /// Returns the physical dimensions of the display in millimeters.
    #[inline]
    pub fn physical_dimensions(&self) -> [u32; 2] {
        let ref r = self.properties.physicalDimensions;
        [r.width, r.height]
    }

    /// Returns the physical, native, or preferred resolution of the display.
    ///
    /// > **Note**: The display is usually still capable of displaying other resolutions. This is
    /// > only the "best" resolution.
    #[inline]
    pub fn physical_resolution(&self) -> [u32; 2] {
        let ref r = self.properties.physicalResolution;
        [r.width, r.height]
    }

    /// Returns the transforms supported by this display.
    #[inline]
    pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
        SupportedSurfaceTransforms::from_bits(self.properties.supportedTransforms)
    }

    /// Returns true if TODO.
    #[inline]
    pub fn plane_reorder_possible(&self) -> bool {
        self.properties.planeReorderPossible != 0
    }

    /// Returns true if TODO.
    #[inline]
    pub fn persistent_content(&self) -> bool {
        self.properties.persistentContent != 0
    }

    /// See the docs of display_modes().
    pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> {
        let vk = self.instance.pointers();

        let num = unsafe {
            let mut num = 0;
            try!(check_errors(vk.GetDisplayModePropertiesKHR(self.physical_device().internal_object(),
                                                             self.properties.display,
                                                             &mut num, ptr::null_mut())));
            num
        };

        let modes: Vec<vk::DisplayModePropertiesKHR> = unsafe {
            let mut modes = Vec::with_capacity(num as usize);
            let mut num = num;
            try!(check_errors(vk.GetDisplayModePropertiesKHR(self.physical_device().internal_object(),
                                                             self.properties.display, &mut num,
                                                             modes.as_mut_ptr())));
            modes.set_len(num as usize);
            modes
        };

        Ok(modes.into_iter().map(|mode| {
            DisplayMode {
                display: self.clone(),
                display_mode: mode.displayMode,
                parameters: mode.parameters,
            }
        }).collect::<Vec<_>>().into_iter())
    }

    /// Returns a list of all modes available on this display.
    ///
    /// # Panic
    ///
    /// - Panics if the device or host ran out of memory.
    ///
    // TODO: move iterator creation here from display_modes_raw?
    #[inline]
    pub fn display_modes(&self) -> IntoIter<DisplayMode> {
        self.display_modes_raw().unwrap()
    }
}

unsafe impl VulkanObject for Display {
    type Object = vk::DisplayKHR;

    #[inline]
    fn internal_object(&self) -> vk::DisplayKHR {
        self.properties.display
    }
}

/// Represents a mode on a specific display.
pub struct DisplayMode {
    display: Display,
    display_mode: vk::DisplayModeKHR,
    parameters: vk::DisplayModeParametersKHR,
}

impl DisplayMode {
    /*pub fn new(display: &Display) -> Result<Arc<DisplayMode>, OomError> {
        let vk = instance.pointers();
        assert!(device.instance().loaded_extensions().khr_display);     // TODO: return error instead

        let parameters = vk::DisplayModeParametersKHR {
            visibleRegion: vk::Extent2D { width: , height:  },
            refreshRate: ,
        };

        let display_mode = {
            let infos = vk::DisplayModeCreateInfoKHR {
                sType: vk::STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR,
                pNext: ptr::null(),
                flags: 0,   // reserved
                parameters: parameters,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDisplayModeKHR(display.device.internal_object(),
                                                      display.display, &infos, ptr::null(),
                                                      &mut output)));
            output
        };

        Ok(Arc::new(DisplayMode {
            instance: display.device.instance().clone(),
            display_mode: display_mode,
            parameters: ,
        }))
    }*/

    /// Returns the display corresponding to this mode.
    #[inline]
    pub fn display(&self) -> &Display {
        &self.display
    }

    /// Returns the dimensions of the region that is visible on the monitor.
    #[inline]
    pub fn visible_region(&self) -> [u32; 2] {
        let ref d = self.parameters.visibleRegion;
        [d.width, d.height]
    }

    /// Returns the refresh rate of this mode.
    #[inline]
    pub fn refresh_rate(&self) -> u32 {
        self.parameters.refreshRate
    }
}

unsafe impl VulkanObject for DisplayMode {
    type Object = vk::DisplayModeKHR;

    #[inline]
    fn internal_object(&self) -> vk::DisplayModeKHR {
        self.display_mode
    }
}
<|endoftext|>


<commit_before>// High-level bindings to Azure.
use cairo_hl = cairo::cairo_hl;

use bindgen::{AzCreateColorPattern, AzCreateDrawTarget, AzCreateDrawTargetForCairoSurface};
use bindgen::{AzCreateDrawTargetForData, AzDataSourceSurfaceGetData, AzDataSourceSurfaceGetStride};
use bindgen::AzDrawTargetClearRect;
use bindgen::AzDrawTargetCreateSourceSurfaceFromData;
use bindgen::{AzDrawTargetDrawSurface, AzDrawTargetFillRect, AzDrawTargetFlush};
use bindgen::{AzDrawTargetGetSnapshot, AzDrawTargetSetTransform, AzDrawTargetStrokeRect};
use bindgen::{AzReleaseColorPattern, AzReleaseDrawTarget};
use bindgen::AzReleaseSourceSurface;
use bindgen::AzRetainDrawTarget;
use bindgen::{AzSourceSurfaceGetDataSurface, AzSourceSurfaceGetFormat, AzSourceSurfaceGetSize};
pub use cairo_hl::ImageSurface;
use geom::matrix2d::Matrix2D;
use geom::rect::Rect;
use geom::size::Size2D;
use ptr::{null, to_unsafe_ptr};
use cast::transmute;

pub trait AsAzureRect {
    fn as_azure_rect() -> AzRect;
}

impl Rect<AzFloat> : AsAzureRect {
    fn as_azure_rect() -> AzRect {
        {
            x: self.origin.x,
            y: self.origin.y,
            width: self.size.width,
            height: self.size.height
        }
    }
}

pub trait AsAzureIntSize {
    fn as_azure_int_size() -> AzIntSize;
}

impl Size2D<i32> : AsAzureIntSize {
    fn as_azure_int_size() -> AzIntSize {
        {
            width: self.width,
            height: self.height
        }
    }
}

pub struct Color {
    r: AzFloat,
    g: AzFloat,
    b: AzFloat,
    a: AzFloat,
}

impl Color {
    fn as_azure_color() -> AzColor {
        { r: self.r, g: self.g, b: self.b, a: self.a }
    }
}

pub fn Color(r: AzFloat, g: AzFloat, b: AzFloat, a: AzFloat) -> Color {
    Color { r: r, g: g, b: b, a: a }
}

// FIXME: Should have a class hierarchy here starting with Pattern.
pub struct ColorPattern {
    azure_color_pattern: AzColorPatternRef,

    drop {
        AzReleaseColorPattern(self.azure_color_pattern);
    }
}

pub fn ColorPattern(color: Color) -> ColorPattern {
    ColorPattern {
        azure_color_pattern: AzCreateColorPattern(to_unsafe_ptr(&color.as_azure_color()))
    }
}

pub struct StrokeOptions {
    line_width: AzFloat,
    miter_limit: AzFloat,
    fields: uint16_t,
}

impl StrokeOptions {
    fn as_azure_stroke_options() -> AzStrokeOptions {
        {
            mLineWidth: self.line_width,
            mMiterLimit: self.miter_limit,
            mDashPattern: null(),
            mDashLength: 0,
            mDashOffset: 0.0f as AzFloat,
            fields: self.fields
        }
    }
}

pub fn StrokeOptions(line_width: AzFloat,
                  miter_limit: AzFloat,
                  fields: uint16_t) -> StrokeOptions {
    StrokeOptions {
        line_width: line_width,
        miter_limit: miter_limit,
        fields: fields
    }
}

pub struct DrawOptions {
    alpha: AzFloat,
    fields: uint16_t,
}

impl DrawOptions {
    fn as_azure_draw_options() -> AzDrawOptions {
        {
            mAlpha: self.alpha,
            fields: self.fields
        }
    }
}

pub fn DrawOptions(alpha: AzFloat, fields: uint16_t) -> DrawOptions {
    DrawOptions {
        alpha : alpha,
        fields : fields,
    }
}

pub enum SurfaceFormat {
    B8G8R8A8,
    R8G8R8X8,
    R5G6B5,
    A8
}

impl SurfaceFormat {
    fn as_azure_surface_format() -> AzSurfaceFormat {
        self as AzSurfaceFormat
    }

    static pub fn new(azure_surface_format: AzSurfaceFormat) -> SurfaceFormat {
        match azure_surface_format {
            0 => B8G8R8A8,
            1 => R8G8R8X8,
            2 => R5G6B5,
            3 => A8,
            _ => fail ~"SurfaceFormat::new(): unknown Azure surface format"
        }
    }
}

pub enum Filter {
    Linear,
    Point
}

impl Filter {
    fn as_azure_filter() -> AzFilter {
        self as AzFilter
    }
}

pub struct DrawSurfaceOptions {
    filter: Filter,
    sampling_bounds: bool,
}

impl DrawSurfaceOptions {
    fn as_azure_draw_surface_options() -> AzDrawSurfaceOptions {
        { fields: ((self.filter as int) | (if self.sampling_bounds { 8 } else { 0 })) as u32 }
    }
}

pub fn DrawSurfaceOptions(filter: Filter, sampling_bounds: bool) -> DrawSurfaceOptions {
    DrawSurfaceOptions {
        filter: filter,
        sampling_bounds: sampling_bounds,
    }
}

pub enum BackendType {
    NoBackend,
    Direct2DBackend,
    CoreGraphicsBackend,
    CoreGraphicsAcceleratedBackend,
    CairoBackend,
    SkiaBackend,
    RecordingBackend
}

impl BackendType {
    pub fn as_azure_backend_type(self) -> AzBackendType {
        match self {
            NoBackend                      => 0,
            Direct2DBackend                => 1,
            CoreGraphicsBackend            => 2,
            CoreGraphicsAcceleratedBackend => 3,
            CairoBackend                   => 4,
            SkiaBackend                    => 5,
            RecordingBackend               => 6,
        }
    }
}

pub struct DrawTarget {
    azure_draw_target: AzDrawTargetRef,
    data: Option<~[u8]>,

    drop {
        AzReleaseDrawTarget(self.azure_draw_target);
    }
}

pub impl DrawTarget {
    static pub fn new(backend: BackendType, size: Size2D<i32>, format: SurfaceFormat)
                   -> DrawTarget {
        let azure_draw_target = AzCreateDrawTarget(backend.as_azure_backend_type(),
                                                   to_unsafe_ptr(&size.as_azure_int_size()),
                                                   format.as_azure_surface_format());
        if azure_draw_target == ptr::null() { fail; }
        DrawTarget { azure_draw_target: move azure_draw_target, data: None }
    }

    static pub fn new_with_data(backend: BackendType, data: ~[u8], size: Size2D<i32>, stride: i32,
                                format: SurfaceFormat) -> DrawTarget {
        assert data.len() as i32 == stride * size.height;
        let azure_draw_target =
            AzCreateDrawTargetForData(backend.as_azure_backend_type(),
                                      to_unsafe_ptr(&data[0]),
                                      to_unsafe_ptr(&size.as_azure_int_size()),
                                      stride,
                                      format.as_azure_surface_format());
        if azure_draw_target == ptr::null() { fail; }
        DrawTarget { azure_draw_target: move azure_draw_target, data: Some(move data) }
    }

    fn clone() -> DrawTarget {
        return new_draw_target_from_azure_draw_target(self.azure_draw_target);
    }

    fn flush() {
        AzDrawTargetFlush(self.azure_draw_target);
    }

    fn clear_rect(rect: &Rect<AzFloat>) {
        AzDrawTargetClearRect(self.azure_draw_target, to_unsafe_ptr(&rect.as_azure_rect()));
    }

    fn fill_rect(rect: &Rect<AzFloat>, pattern: &ColorPattern) {
        AzDrawTargetFillRect(self.azure_draw_target,
                             to_unsafe_ptr(&rect.as_azure_rect()),
                             pattern.azure_color_pattern);
    }

    fn stroke_rect(rect: &Rect<AzFloat>, pattern: &ColorPattern, stroke_options: &StrokeOptions,
                   draw_options: &DrawOptions) {
        AzDrawTargetStrokeRect(self.azure_draw_target,
                               to_unsafe_ptr(&rect.as_azure_rect()),
                               pattern.azure_color_pattern,
                               to_unsafe_ptr(&stroke_options.as_azure_stroke_options()),
                               to_unsafe_ptr(&draw_options.as_azure_draw_options()));
    }

    fn draw_surface(surface: SourceSurface, dest: Rect<AzFloat>, source: Rect<AzFloat>,
                    surf_options: DrawSurfaceOptions, options: DrawOptions) {
        AzDrawTargetDrawSurface(self.azure_draw_target,
                                surface.azure_source_surface,
                                to_unsafe_ptr(&dest.as_azure_rect()),
                                to_unsafe_ptr(&source.as_azure_rect()),
                                to_unsafe_ptr(&surf_options.as_azure_draw_surface_options()),
                                to_unsafe_ptr(&options.as_azure_draw_options()));
    }

    fn snapshot(&const self) -> SourceSurface {
        let azure_surface = AzDrawTargetGetSnapshot(self.azure_draw_target);
        SourceSurface(azure_surface)
    }

    fn create_source_surface_from_data(data: &[u8], size: Size2D<i32>, stride: i32,
                                       format: SurfaceFormat) -> SourceSurface {

        assert data.len() as i32 == stride * size.height;
        let azure_surface =
            AzDrawTargetCreateSourceSurfaceFromData(self.azure_draw_target,
                                                    to_unsafe_ptr(&data[0]),
                                                    to_unsafe_ptr(&size.as_azure_int_size()),
                                                    stride,
                                                    format.as_azure_surface_format());
        SourceSurface(azure_surface)
    }

    fn set_transform(matrix: &Matrix2D<AzFloat>) {
        unsafe {
            AzDrawTargetSetTransform(self.azure_draw_target, transmute(matrix));
        }
    }
}

pub fn DrawTarget(cairo_surface: &ImageSurface) -> DrawTarget {
	let size = { width: cairo_surface.width(), height: cairo_surface.height() };
    DrawTarget {
        azure_draw_target: AzCreateDrawTargetForCairoSurface(cairo_surface.cairo_surface,
														     to_unsafe_ptr(&size)),
        data: None
    }
}

// Ugly workaround for the lack of explicit self.
pub fn clone_mutable_draw_target(draw_target: &mut DrawTarget) -> DrawTarget {
    return new_draw_target_from_azure_draw_target(draw_target.azure_draw_target);
}

pub fn new_draw_target(cairo_surface: &ImageSurface) -> DrawTarget {
	let size = { width: cairo_surface.width(), height: cairo_surface.height() };
    DrawTarget {
        azure_draw_target: AzCreateDrawTargetForCairoSurface(cairo_surface.cairo_surface,
														     to_unsafe_ptr(&size)),
        data: None
    }
}

pub fn new_draw_target_from_azure_draw_target(azure_draw_target: AzDrawTargetRef) -> DrawTarget {
    AzRetainDrawTarget(azure_draw_target);
    DrawTarget {
        azure_draw_target: azure_draw_target,
        data: None
    }
}

pub struct SourceSurface {
    priv azure_source_surface: AzSourceSurfaceRef,

    drop {
        AzReleaseSourceSurface(self.azure_source_surface);
    }
}

pub fn SourceSurface(azure_source_surface: AzSourceSurfaceRef) -> SourceSurface {
    SourceSurface {
        azure_source_surface: azure_source_surface
    }
}

pub trait SourceSurfaceMethods {
    fn get_azure_source_surface(&const self) -> AzSourceSurfaceRef;

    fn size(&const self) -> Size2D<i32> {
        let size = AzSourceSurfaceGetSize(self.get_azure_source_surface());
        Size2D { width: size.width, height: size.height }
    }

    fn format(&const self) -> SurfaceFormat {
        SurfaceFormat::new(AzSourceSurfaceGetFormat(self.get_azure_source_surface()))
    }
}

impl SourceSurface {
    pub fn get_data_surface(&const self) -> DataSourceSurface {
        DataSourceSurface {
            azure_data_source_surface: AzSourceSurfaceGetDataSurface(self.azure_source_surface)
        }
    }
}

impl SourceSurface : SourceSurfaceMethods {
    fn get_azure_source_surface(&const self) -> AzSourceSurfaceRef { self.azure_source_surface }
}

pub struct DataSourceSurface {
    priv azure_data_source_surface: AzDataSourceSurfaceRef,

    drop {
        AzReleaseSourceSurface(self.azure_data_source_surface);
    }
}

impl DataSourceSurface {
    pub fn with_data(&const self, f: &fn(&[u8])) {
        unsafe {
            let buf = AzDataSourceSurfaceGetData(self.azure_data_source_surface);
            let len = self.stride() * self.size().height;
            vec::raw::buf_as_slice(buf, len as uint, f);
        }
    }

    pub fn stride(&const self) -> i32 {
        AzDataSourceSurfaceGetStride(self.azure_data_source_surface)
    }

    // FIXME: Workaround for lack of working cross-crate default methods.
    pub fn get_size(&const self) -> Size2D<i32> {
        self.size()
    }
}

impl DataSourceSurface : SourceSurfaceMethods {
    fn get_azure_source_surface(&const self) -> AzSourceSurfaceRef {
        self.azure_data_source_surface
    }
}

<commit_msg>Allow new_with_data() to have an offset, to accommodate weird alignment requirements.<commit_after>// High-level bindings to Azure.
use cairo_hl = cairo::cairo_hl;

use bindgen::{AzCreateColorPattern, AzCreateDrawTarget, AzCreateDrawTargetForCairoSurface};
use bindgen::{AzCreateDrawTargetForData, AzDataSourceSurfaceGetData, AzDataSourceSurfaceGetStride};
use bindgen::AzDrawTargetClearRect;
use bindgen::AzDrawTargetCreateSourceSurfaceFromData;
use bindgen::{AzDrawTargetDrawSurface, AzDrawTargetFillRect, AzDrawTargetFlush};
use bindgen::{AzDrawTargetGetSnapshot, AzDrawTargetSetTransform, AzDrawTargetStrokeRect};
use bindgen::{AzReleaseColorPattern, AzReleaseDrawTarget};
use bindgen::AzReleaseSourceSurface;
use bindgen::AzRetainDrawTarget;
use bindgen::{AzSourceSurfaceGetDataSurface, AzSourceSurfaceGetFormat, AzSourceSurfaceGetSize};
pub use cairo_hl::ImageSurface;
use geom::matrix2d::Matrix2D;
use geom::rect::Rect;
use geom::size::Size2D;
use ptr::{null, to_unsafe_ptr};
use cast::transmute;

pub trait AsAzureRect {
    fn as_azure_rect() -> AzRect;
}

impl Rect<AzFloat> : AsAzureRect {
    fn as_azure_rect() -> AzRect {
        {
            x: self.origin.x,
            y: self.origin.y,
            width: self.size.width,
            height: self.size.height
        }
    }
}

pub trait AsAzureIntSize {
    fn as_azure_int_size() -> AzIntSize;
}

impl Size2D<i32> : AsAzureIntSize {
    fn as_azure_int_size() -> AzIntSize {
        {
            width: self.width,
            height: self.height
        }
    }
}

pub struct Color {
    r: AzFloat,
    g: AzFloat,
    b: AzFloat,
    a: AzFloat,
}

impl Color {
    fn as_azure_color() -> AzColor {
        { r: self.r, g: self.g, b: self.b, a: self.a }
    }
}

pub fn Color(r: AzFloat, g: AzFloat, b: AzFloat, a: AzFloat) -> Color {
    Color { r: r, g: g, b: b, a: a }
}

// FIXME: Should have a class hierarchy here starting with Pattern.
pub struct ColorPattern {
    azure_color_pattern: AzColorPatternRef,

    drop {
        AzReleaseColorPattern(self.azure_color_pattern);
    }
}

pub fn ColorPattern(color: Color) -> ColorPattern {
    ColorPattern {
        azure_color_pattern: AzCreateColorPattern(to_unsafe_ptr(&color.as_azure_color()))
    }
}

pub struct StrokeOptions {
    line_width: AzFloat,
    miter_limit: AzFloat,
    fields: uint16_t,
}

impl StrokeOptions {
    fn as_azure_stroke_options() -> AzStrokeOptions {
        {
            mLineWidth: self.line_width,
            mMiterLimit: self.miter_limit,
            mDashPattern: null(),
            mDashLength: 0,
            mDashOffset: 0.0f as AzFloat,
            fields: self.fields
        }
    }
}

pub fn StrokeOptions(line_width: AzFloat,
                  miter_limit: AzFloat,
                  fields: uint16_t) -> StrokeOptions {
    StrokeOptions {
        line_width: line_width,
        miter_limit: miter_limit,
        fields: fields
    }
}

pub struct DrawOptions {
    alpha: AzFloat,
    fields: uint16_t,
}

impl DrawOptions {
    fn as_azure_draw_options() -> AzDrawOptions {
        {
            mAlpha: self.alpha,
            fields: self.fields
        }
    }
}

pub fn DrawOptions(alpha: AzFloat, fields: uint16_t) -> DrawOptions {
    DrawOptions {
        alpha : alpha,
        fields : fields,
    }
}

pub enum SurfaceFormat {
    B8G8R8A8,
    R8G8R8X8,
    R5G6B5,
    A8
}

impl SurfaceFormat {
    fn as_azure_surface_format() -> AzSurfaceFormat {
        self as AzSurfaceFormat
    }

    static pub fn new(azure_surface_format: AzSurfaceFormat) -> SurfaceFormat {
        match azure_surface_format {
            0 => B8G8R8A8,
            1 => R8G8R8X8,
            2 => R5G6B5,
            3 => A8,
            _ => fail ~"SurfaceFormat::new(): unknown Azure surface format"
        }
    }
}

pub enum Filter {
    Linear,
    Point
}

impl Filter {
    fn as_azure_filter() -> AzFilter {
        self as AzFilter
    }
}

pub struct DrawSurfaceOptions {
    filter: Filter,
    sampling_bounds: bool,
}

impl DrawSurfaceOptions {
    fn as_azure_draw_surface_options() -> AzDrawSurfaceOptions {
        { fields: ((self.filter as int) | (if self.sampling_bounds { 8 } else { 0 })) as u32 }
    }
}

pub fn DrawSurfaceOptions(filter: Filter, sampling_bounds: bool) -> DrawSurfaceOptions {
    DrawSurfaceOptions {
        filter: filter,
        sampling_bounds: sampling_bounds,
    }
}

pub enum BackendType {
    NoBackend,
    Direct2DBackend,
    CoreGraphicsBackend,
    CoreGraphicsAcceleratedBackend,
    CairoBackend,
    SkiaBackend,
    RecordingBackend
}

impl BackendType {
    pub fn as_azure_backend_type(self) -> AzBackendType {
        match self {
            NoBackend                      => 0,
            Direct2DBackend                => 1,
            CoreGraphicsBackend            => 2,
            CoreGraphicsAcceleratedBackend => 3,
            CairoBackend                   => 4,
            SkiaBackend                    => 5,
            RecordingBackend               => 6,
        }
    }
}

pub struct DrawTarget {
    azure_draw_target: AzDrawTargetRef,
    data: Option<~[u8]>,

    drop {
        AzReleaseDrawTarget(self.azure_draw_target);
    }
}

pub impl DrawTarget {
    static pub fn new(backend: BackendType, size: Size2D<i32>, format: SurfaceFormat)
                   -> DrawTarget {
        let azure_draw_target = AzCreateDrawTarget(backend.as_azure_backend_type(),
                                                   to_unsafe_ptr(&size.as_azure_int_size()),
                                                   format.as_azure_surface_format());
        if azure_draw_target == ptr::null() { fail; }
        DrawTarget { azure_draw_target: move azure_draw_target, data: None }
    }

    static pub fn new_with_data(backend: BackendType,
                                data: ~[u8],
                                offset: uint,
                                size: Size2D<i32>,
                                stride: i32,
                                format: SurfaceFormat) -> DrawTarget {
        assert (data.len() - offset) as i32 >= stride * size.height;
        let azure_draw_target =
            AzCreateDrawTargetForData(backend.as_azure_backend_type(),
                                      to_unsafe_ptr(&data[offset]),
                                      to_unsafe_ptr(&size.as_azure_int_size()),
                                      stride,
                                      format.as_azure_surface_format());
        if azure_draw_target == ptr::null() { fail; }
        DrawTarget { azure_draw_target: move azure_draw_target, data: Some(move data) }
    }

    fn clone() -> DrawTarget {
        return new_draw_target_from_azure_draw_target(self.azure_draw_target);
    }

    fn flush() {
        AzDrawTargetFlush(self.azure_draw_target);
    }

    fn clear_rect(rect: &Rect<AzFloat>) {
        AzDrawTargetClearRect(self.azure_draw_target, to_unsafe_ptr(&rect.as_azure_rect()));
    }

    fn fill_rect(rect: &Rect<AzFloat>, pattern: &ColorPattern) {
        AzDrawTargetFillRect(self.azure_draw_target,
                             to_unsafe_ptr(&rect.as_azure_rect()),
                             pattern.azure_color_pattern);
    }

    fn stroke_rect(rect: &Rect<AzFloat>, pattern: &ColorPattern, stroke_options: &StrokeOptions,
                   draw_options: &DrawOptions) {
        AzDrawTargetStrokeRect(self.azure_draw_target,
                               to_unsafe_ptr(&rect.as_azure_rect()),
                               pattern.azure_color_pattern,
                               to_unsafe_ptr(&stroke_options.as_azure_stroke_options()),
                               to_unsafe_ptr(&draw_options.as_azure_draw_options()));
    }

    fn draw_surface(surface: SourceSurface, dest: Rect<AzFloat>, source: Rect<AzFloat>,
                    surf_options: DrawSurfaceOptions, options: DrawOptions) {
        AzDrawTargetDrawSurface(self.azure_draw_target,
                                surface.azure_source_surface,
                                to_unsafe_ptr(&dest.as_azure_rect()),
                                to_unsafe_ptr(&source.as_azure_rect()),
                                to_unsafe_ptr(&surf_options.as_azure_draw_surface_options()),
                                to_unsafe_ptr(&options.as_azure_draw_options()));
    }

    fn snapshot(&const self) -> SourceSurface {
        let azure_surface = AzDrawTargetGetSnapshot(self.azure_draw_target);
        SourceSurface(azure_surface)
    }

    fn create_source_surface_from_data(data: &[u8], size: Size2D<i32>, stride: i32,
                                       format: SurfaceFormat) -> SourceSurface {

        assert data.len() as i32 == stride * size.height;
        let azure_surface =
            AzDrawTargetCreateSourceSurfaceFromData(self.azure_draw_target,
                                                    to_unsafe_ptr(&data[0]),
                                                    to_unsafe_ptr(&size.as_azure_int_size()),
                                                    stride,
                                                    format.as_azure_surface_format());
        SourceSurface(azure_surface)
    }

    fn set_transform(matrix: &Matrix2D<AzFloat>) {
        unsafe {
            AzDrawTargetSetTransform(self.azure_draw_target, transmute(matrix));
        }
    }
}

pub fn DrawTarget(cairo_surface: &ImageSurface) -> DrawTarget {
	let size = { width: cairo_surface.width(), height: cairo_surface.height() };
    DrawTarget {
        azure_draw_target: AzCreateDrawTargetForCairoSurface(cairo_surface.cairo_surface,
														     to_unsafe_ptr(&size)),
        data: None
    }
}

// Ugly workaround for the lack of explicit self.
pub fn clone_mutable_draw_target(draw_target: &mut DrawTarget) -> DrawTarget {
    return new_draw_target_from_azure_draw_target(draw_target.azure_draw_target);
}

pub fn new_draw_target(cairo_surface: &ImageSurface) -> DrawTarget {
	let size = { width: cairo_surface.width(), height: cairo_surface.height() };
    DrawTarget {
        azure_draw_target: AzCreateDrawTargetForCairoSurface(cairo_surface.cairo_surface,
														     to_unsafe_ptr(&size)),
        data: None
    }
}

pub fn new_draw_target_from_azure_draw_target(azure_draw_target: AzDrawTargetRef) -> DrawTarget {
    AzRetainDrawTarget(azure_draw_target);
    DrawTarget {
        azure_draw_target: azure_draw_target,
        data: None
    }
}

pub struct SourceSurface {
    priv azure_source_surface: AzSourceSurfaceRef,

    drop {
        AzReleaseSourceSurface(self.azure_source_surface);
    }
}

pub fn SourceSurface(azure_source_surface: AzSourceSurfaceRef) -> SourceSurface {
    SourceSurface {
        azure_source_surface: azure_source_surface
    }
}

pub trait SourceSurfaceMethods {
    fn get_azure_source_surface(&const self) -> AzSourceSurfaceRef;

    fn size(&const self) -> Size2D<i32> {
        let size = AzSourceSurfaceGetSize(self.get_azure_source_surface());
        Size2D { width: size.width, height: size.height }
    }

    fn format(&const self) -> SurfaceFormat {
        SurfaceFormat::new(AzSourceSurfaceGetFormat(self.get_azure_source_surface()))
    }
}

impl SourceSurface {
    pub fn get_data_surface(&const self) -> DataSourceSurface {
        DataSourceSurface {
            azure_data_source_surface: AzSourceSurfaceGetDataSurface(self.azure_source_surface)
        }
    }
}

impl SourceSurface : SourceSurfaceMethods {
    fn get_azure_source_surface(&const self) -> AzSourceSurfaceRef { self.azure_source_surface }
}

pub struct DataSourceSurface {
    priv azure_data_source_surface: AzDataSourceSurfaceRef,

    drop {
        AzReleaseSourceSurface(self.azure_data_source_surface);
    }
}

impl DataSourceSurface {
    pub fn with_data(&const self, f: &fn(&[u8])) {
        unsafe {
            let buf = AzDataSourceSurfaceGetData(self.azure_data_source_surface);
            let len = self.stride() * self.size().height;
            vec::raw::buf_as_slice(buf, len as uint, f);
        }
    }

    pub fn stride(&const self) -> i32 {
        AzDataSourceSurfaceGetStride(self.azure_data_source_surface)
    }

    // FIXME: Workaround for lack of working cross-crate default methods.
    pub fn get_size(&const self) -> Size2D<i32> {
        self.size()
    }
}

impl DataSourceSurface : SourceSurfaceMethods {
    fn get_azure_source_surface(&const self) -> AzSourceSurfaceRef {
        self.azure_data_source_surface
    }
}

<|endoftext|>


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

use servo_url::ServoUrl;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read};
use std::net::IpAddr;

lazy_static! {
    static ref HOST_TABLE: Option<HashMap<String, IpAddr>> = create_host_table();
}

fn create_host_table() -> Option<HashMap<String, IpAddr>> {
    //TODO: handle bad file path
    let path = match env::var("HOST_FILE") {
        Ok(host_file_path) => host_file_path,
        Err(_) => return None,
    };

    let mut file = match File::open(&path) {
        Ok(f) => BufReader::new(f),
        Err(_) => return None,
    };

    let mut lines = String::new();
    match file.read_to_string(&mut lines) {
        Ok(_) => (),
        Err(_) => return None,
    };

    return Some(parse_hostsfile(&lines));
}

pub fn parse_hostsfile(hostsfile_content: &str) -> HashMap<String, IpAddr> {
    let mut host_table = HashMap::new();
    for line in hostsfile_content.split('\n') {
        let mut ip_host = line.trim().split(|c: char| c == ' ' || c == '\t');
        if let Some(ip) = ip_host.next() {
            if let Ok(address) = ip.parse::<IpAddr>() {
                for token in ip_host {
                    if token.as_bytes()[0] == b'#' {
                        break;
                    }
                    host_table.insert((*token).to_owned(), address);
                }
            }
        }
    }
    host_table
}

pub fn replace_hosts(url: &ServoUrl) -> ServoUrl {
    HOST_TABLE.as_ref().map_or_else(|| url.clone(), |host_table| {
        host_replacement(host_table, url)
    })
}

pub fn host_replacement(host_table: &HashMap<String, IpAddr>,
                        url: &ServoUrl) -> ServoUrl {
    url.domain().and_then(|domain| host_table.get(domain).map(|ip| {
        let mut new_url = url.clone();
        new_url.set_ip_host(*ip).unwrap();
        new_url
    })).unwrap_or_else(|| url.clone())
}
<commit_msg>Provide an API to replace the host table.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use servo_url::ServoUrl;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufReader, Read};
use std::net::IpAddr;
use std::sync::Mutex;

lazy_static! {
    static ref HOST_TABLE: Mutex<Option<HashMap<String, IpAddr>>> = Mutex::new(create_host_table());
}

fn create_host_table() -> Option<HashMap<String, IpAddr>> {
    //TODO: handle bad file path
    let path = match env::var("HOST_FILE") {
        Ok(host_file_path) => host_file_path,
        Err(_) => return None,
    };

    let mut file = match File::open(&path) {
        Ok(f) => BufReader::new(f),
        Err(_) => return None,
    };

    let mut lines = String::new();
    match file.read_to_string(&mut lines) {
        Ok(_) => (),
        Err(_) => return None,
    };

    return Some(parse_hostsfile(&lines));
}

pub fn replace_host_table(table: HashMap<String, IpAddr>) {
    *HOST_TABLE.lock().unwrap() = Some(table);
}

pub fn parse_hostsfile(hostsfile_content: &str) -> HashMap<String, IpAddr> {
    let mut host_table = HashMap::new();
    for line in hostsfile_content.split('\n') {
        let mut ip_host = line.trim().split(|c: char| c == ' ' || c == '\t');
        if let Some(ip) = ip_host.next() {
            if let Ok(address) = ip.parse::<IpAddr>() {
                for token in ip_host {
                    if token.as_bytes()[0] == b'#' {
                        break;
                    }
                    host_table.insert((*token).to_owned(), address);
                }
            }
        }
    }
    host_table
}

pub fn replace_hosts(url: &ServoUrl) -> ServoUrl {
    HOST_TABLE.lock().unwrap().as_ref().map_or_else(|| url.clone(), |host_table| {
        host_replacement(host_table, url)
    })
}

pub fn host_replacement(host_table: &HashMap<String, IpAddr>,
                        url: &ServoUrl) -> ServoUrl {
    url.domain().and_then(|domain| host_table.get(domain).map(|ip| {
        let mut new_url = url.clone();
        new_url.set_ip_host(*ip).unwrap();
        new_url
    })).unwrap_or_else(|| url.clone())
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use backtrace::Backtrace;
use diem_logger::prelude::*;
use serde::Serialize;
use std::{
    panic::{self, PanicInfo},
    process, thread, time,
};

#[derive(Debug, Serialize)]
pub struct CrashInfo {
    details: String,
    backtrace: String,
}

/// Invoke to ensure process exits on a thread panic.
///
/// Tokio's default behavior is to catch panics and ignore them.  Invoking this function will
/// ensure that all subsequent thread panics (even Tokio threads) will report the
/// details/backtrace and then exit.
pub fn setup_panic_handler() {
    panic::set_hook(Box::new(move |pi: &PanicInfo<'_>| {
        handle_panic(pi);
    }));
}

// Formats and logs panic information
fn handle_panic(panic_info: &PanicInfo<'_>) {
    // The Display formatter for a PanicInfo contains the message, payload and location.
    let details = format!("{}", panic_info);
    let backtrace = format!("{:#?}", Backtrace::new());

    let info = CrashInfo { details, backtrace };
    error!("{}", crash_info = toml::to_string_pretty(&info).unwrap());

    // Provide some time to save the log to disk
    thread::sleep(time::Duration::from_millis(100));

    // Kill the process
    process::exit(12);
}
<commit_msg>crash-handler: wait till logs have been flushed to exit<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use backtrace::Backtrace;
use diem_logger::prelude::*;
use serde::Serialize;
use std::{
    panic::{self, PanicInfo},
    process,
};

#[derive(Debug, Serialize)]
pub struct CrashInfo {
    details: String,
    backtrace: String,
}

/// Invoke to ensure process exits on a thread panic.
///
/// Tokio's default behavior is to catch panics and ignore them.  Invoking this function will
/// ensure that all subsequent thread panics (even Tokio threads) will report the
/// details/backtrace and then exit.
pub fn setup_panic_handler() {
    panic::set_hook(Box::new(move |pi: &PanicInfo<'_>| {
        handle_panic(pi);
    }));
}

// Formats and logs panic information
fn handle_panic(panic_info: &PanicInfo<'_>) {
    // The Display formatter for a PanicInfo contains the message, payload and location.
    let details = format!("{}", panic_info);
    let backtrace = format!("{:#?}", Backtrace::new());

    let info = CrashInfo { details, backtrace };
    error!("{}", crash_info = toml::to_string_pretty(&info).unwrap());

    // Wait till the logs have been flushed
    diem_logger::flush();

    // Kill the process
    process::exit(12);
}
<|endoftext|>