<commit_before>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::cell::{Cell, RefCell};
use std::collections::{HashMap, hash_map};
use std::ops::Deref;
use std::rc::{Rc, Weak};
use std::ptr;
use libc::c_int;
use iup_sys::*;
use callbacks::Token;

thread_local!(
    static LDESTROY_CALLBACKS: RefCell<HashMap<*mut Ihandle, Vec<(usize, Box<FnMut(*mut Ihandle)>)>>> =
        RefCell::new(HashMap::new())
);

// simplified version of CallbackRegistry::add_callback
// An ldestroy callback should hold a reference to a control, so that when it is dropped a control
// is dropped. Doing so will cause the LDESTROY_CALLBACKS HashMap to be accessed, causing a panic
// due to being borrowed by remove_ldestroy_callback.
pub fn add_ldestroy_callback_inner(ih: *mut Ihandle, cb: Box<FnMut(*mut Ihandle) + 'static>) -> Token {
    LDESTROY_CALLBACKS.with(|reg| {
        let mut map = reg.borrow_mut();
        let cbs = map.entry(ih).or_insert_with(|| { Vec::with_capacity(4) });
        let id = cbs.last().map(|&(id, _)| id + 1).unwrap_or(0);
        cbs.push((id, cb));

        Token { id: id, ih: ih }
    })
}

pub fn add_ldestroy_callback<F: 'static + FnMut(*mut Ihandle)>(ih: *mut Ihandle, cb: F) -> Token {
    add_ldestroy_callback_inner(ih, Box::new(cb))
}

// simplified version of CallbackRegistry::remove_callback
pub fn remove_ldestroy_callback(token: Token) {
    LDESTROY_CALLBACKS.with(|reg| {
        let mut map = reg.borrow_mut();
        if let hash_map::Entry::Occupied(mut entry) = map.entry(token.ih) {
            let is_empty = {
                let cbs = entry.get_mut();
                let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
                // TODO: if this causes ldestroy_cb() to be called, it will panic
                cbs.remove(index);

                cbs.is_empty()
            };
            if is_empty {
                entry.remove();
            }

            // I could use the below with non-lexical borrows.
            //let cbs = entry.get_mut();
            //let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
            // TODO: if this causes ldestroy_cb() to be called, it will panic
            //cbs.remove(index);

            //if cbs.is_empty() {
            //    entry.remove();
            //}
        }
    });
}

extern fn ldestroy_cb(ih: *mut Ihandle) -> c_int {
    handle_rc_destroy_cb(ih);
    LDESTROY_CALLBACKS.with(|cell| {
        if let Some(mut cbs) = cell.borrow_mut().remove(&ih) {
            for cb in cbs.iter_mut() {
                cb.1(ih);
            }
        }
        IUP_DEFAULT
    })
}

thread_local!(
    static EXISTING_HANDLES: RefCell<HashMap<*mut Ihandle, Weak<HandleBox>>> = RefCell::new(HashMap::new())
);

pub fn handle_rc_destroy_cb(ih: *mut Ihandle) {
    EXISTING_HANDLES.with(|cell| {
        let mut map = cell.borrow_mut();
        if let Some(weak) = map.remove(&ih) {
            // It should be removed when the last strong ref was dropped, so it should always be upgradable.
            let handle = weak.upgrade().expect("could not upgrade Weak in handle map");
            // Since the control is destroyed, zero out to prevent wrapper structs from
            // using after free.
            handle.set(ptr::null_mut());
        }
        // else: No wrapper handles currently exist. Don't need to do anything.

        // Detach any child that still has a reference from a wrapper so that it doesn't
        // get destroyed.
        unsafe {
            // Removing a child shifts the index of the following children by one as you'd expect.
            // The easiest way would be to iterate backward removing children. However,
            // IUP stores children as a singly-linked list starting with the first child.
            // So iterating reverse would be O(n^2) best case. Iterating forward would be O(n)
            // best case and O(n^2) worst case. However, using IupGetNextChild and IupGetBrother
            // is always O(n).
            let mut child = IupGetNextChild(ih, ptr::null_mut());
            while !child.is_null() {
                let brother = IupGetBrother(child);
                if map.contains_key(&child) {
                    IupDetach(child);
                }
                child = brother;
            }
        }
    });
}

/// A `HandleBox` is the wrapper's one reference to a control. If there are multiple `HandleRc`s,
/// they all refer to the same `HandleBox`. Since there will always be at most one `HandleBox` for
/// a certain `*mut Ihandle`, then when the `HandleBox` is dropped, there are no more references
/// from the wrapper to the `*mut Ihandle`.
struct HandleBox(Cell<*mut Ihandle>);

impl Deref for HandleBox {
    type Target = Cell<*mut Ihandle>;
    fn deref(&self) -> &Cell<*mut Ihandle> {
        &self.0
    }
}

impl Drop for HandleBox {
    fn drop(&mut self) {
        if self.get() == ptr::null_mut() {
            return;
        }
        EXISTING_HANDLES.with(|map| {
            map.borrow_mut().remove(&self.get()).expect("handle not found in map");
        });
        unsafe {
            if IupGetParent(self.get()) == ptr::null_mut()
            {
                //println!("deleting control with no parent: {:?}", self.get());
                IupDestroy(self.get());
            }
        }
    }
}

// As a future optimization, the implementation could be changed to not use Rc, since support
// for weak ptrs is not used. Then HandleRc would only be a single indirection instead of two,
// and would get rid of half the allocations. Probably not worth the time though.
#[derive(Clone)]
pub struct HandleRc(Rc<HandleBox>);

impl HandleRc {
    pub unsafe fn new(ih: *mut Ihandle) -> HandleRc {
        assert!(ih != ptr::null_mut(), "handle must be non-null");
        let rc = EXISTING_HANDLES.with(|map|
            match map.borrow_mut().entry(ih) {
                hash_map::Entry::Occupied(entry) =>
                    entry.get().upgrade().expect("could not upgrade Weak in handle map"),
                hash_map::Entry::Vacant(entry) => {
                    IupSetCallback(ih, "LDESTROY_CB".as_ptr() as *const i8, ldestroy_cb);
                    let rc = Rc::new(HandleBox(Cell::new(ih)));
                    entry.insert(Rc::downgrade(&rc));
                    rc
                },
            }
        );
        HandleRc(rc)
    }

    pub fn get(&self) -> *mut Ihandle {
        self.0.get()
    }

    pub fn try_unwrap(self) -> Result<*mut Ihandle, HandleRc> {
        Rc::try_unwrap(self.0).map(|handle_box| {
            let handle = handle_box.get();
            // null out so that `HandleBox` doesn't IupDestroy() it and so that no other
            // `HandleRc` can return it
            handle_box.set(ptr::null_mut());
            handle
        }).map_err(|rc| HandleRc(rc))
    }
}
<commit_msg>Fix incorrect information about Rc requiring two indirections<commit_after>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

use std::cell::{Cell, RefCell};
use std::collections::{HashMap, hash_map};
use std::ops::Deref;
use std::rc::{Rc, Weak};
use std::ptr;
use libc::c_int;
use iup_sys::*;
use callbacks::Token;

thread_local!(
    static LDESTROY_CALLBACKS: RefCell<HashMap<*mut Ihandle, Vec<(usize, Box<FnMut(*mut Ihandle)>)>>> =
        RefCell::new(HashMap::new())
);

// simplified version of CallbackRegistry::add_callback
// An ldestroy callback should hold a reference to a control, so that when it is dropped a control
// is dropped. Doing so will cause the LDESTROY_CALLBACKS HashMap to be accessed, causing a panic
// due to being borrowed by remove_ldestroy_callback.
pub fn add_ldestroy_callback_inner(ih: *mut Ihandle, cb: Box<FnMut(*mut Ihandle) + 'static>) -> Token {
    LDESTROY_CALLBACKS.with(|reg| {
        let mut map = reg.borrow_mut();
        let cbs = map.entry(ih).or_insert_with(|| { Vec::with_capacity(4) });
        let id = cbs.last().map(|&(id, _)| id + 1).unwrap_or(0);
        cbs.push((id, cb));

        Token { id: id, ih: ih }
    })
}

pub fn add_ldestroy_callback<F: 'static + FnMut(*mut Ihandle)>(ih: *mut Ihandle, cb: F) -> Token {
    add_ldestroy_callback_inner(ih, Box::new(cb))
}

// simplified version of CallbackRegistry::remove_callback
pub fn remove_ldestroy_callback(token: Token) {
    LDESTROY_CALLBACKS.with(|reg| {
        let mut map = reg.borrow_mut();
        if let hash_map::Entry::Occupied(mut entry) = map.entry(token.ih) {
            let is_empty = {
                let cbs = entry.get_mut();
                let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
                // TODO: if this causes ldestroy_cb() to be called, it will panic
                cbs.remove(index);

                cbs.is_empty()
            };
            if is_empty {
                entry.remove();
            }

            // I could use the below with non-lexical borrows.
            //let cbs = entry.get_mut();
            //let index = cbs.iter().position(|&(id, _)| id == token.id).expect("failed to remove callback");
            // TODO: if this causes ldestroy_cb() to be called, it will panic
            //cbs.remove(index);

            //if cbs.is_empty() {
            //    entry.remove();
            //}
        }
    });
}

extern fn ldestroy_cb(ih: *mut Ihandle) -> c_int {
    handle_rc_destroy_cb(ih);
    LDESTROY_CALLBACKS.with(|cell| {
        if let Some(mut cbs) = cell.borrow_mut().remove(&ih) {
            for cb in cbs.iter_mut() {
                cb.1(ih);
            }
        }
        IUP_DEFAULT
    })
}

thread_local!(
    static EXISTING_HANDLES: RefCell<HashMap<*mut Ihandle, Weak<HandleBox>>> = RefCell::new(HashMap::new())
);

pub fn handle_rc_destroy_cb(ih: *mut Ihandle) {
    EXISTING_HANDLES.with(|cell| {
        let mut map = cell.borrow_mut();
        if let Some(weak) = map.remove(&ih) {
            // It should be removed when the last strong ref was dropped, so it should always be upgradable.
            let handle = weak.upgrade().expect("could not upgrade Weak in handle map");
            // Since the control is destroyed, zero out to prevent wrapper structs from
            // using after free.
            handle.set(ptr::null_mut());
        }
        // else: No wrapper handles currently exist. Don't need to do anything.

        // Detach any child that still has a reference from a wrapper so that it doesn't
        // get destroyed.
        unsafe {
            // Removing a child shifts the index of the following children by one as you'd expect.
            // The easiest way would be to iterate backward removing children. However,
            // IUP stores children as a singly-linked list starting with the first child.
            // So iterating reverse would be O(n^2) best case. Iterating forward would be O(n)
            // best case and O(n^2) worst case. However, using IupGetNextChild and IupGetBrother
            // is always O(n).
            let mut child = IupGetNextChild(ih, ptr::null_mut());
            while !child.is_null() {
                let brother = IupGetBrother(child);
                if map.contains_key(&child) {
                    IupDetach(child);
                }
                child = brother;
            }
        }
    });
}

/// A `HandleBox` is the wrapper's one reference to a control. If there are multiple `HandleRc`s,
/// they all refer to the same `HandleBox`. Since there will always be at most one `HandleBox` for
/// a certain `*mut Ihandle`, then when the `HandleBox` is dropped, there are no more references
/// from the wrapper to the `*mut Ihandle`.
struct HandleBox(Cell<*mut Ihandle>);

impl Deref for HandleBox {
    type Target = Cell<*mut Ihandle>;
    fn deref(&self) -> &Cell<*mut Ihandle> {
        &self.0
    }
}

impl Drop for HandleBox {
    fn drop(&mut self) {
        if self.get() == ptr::null_mut() {
            return;
        }
        EXISTING_HANDLES.with(|map| {
            map.borrow_mut().remove(&self.get()).expect("handle not found in map");
        });
        unsafe {
            if IupGetParent(self.get()) == ptr::null_mut()
            {
                //println!("deleting control with no parent: {:?}", self.get());
                IupDestroy(self.get());
            }
        }
    }
}

// As a future optimization, the implementation could be changed to not use Rc, since support
// for weak ptrs is not used. It would only get rid of one word of memory though. Not worth
// the time.
#[derive(Clone)]
pub struct HandleRc(Rc<HandleBox>);

impl HandleRc {
    pub unsafe fn new(ih: *mut Ihandle) -> HandleRc {
        assert!(ih != ptr::null_mut(), "handle must be non-null");
        let rc = EXISTING_HANDLES.with(|map|
            match map.borrow_mut().entry(ih) {
                hash_map::Entry::Occupied(entry) =>
                    entry.get().upgrade().expect("could not upgrade Weak in handle map"),
                hash_map::Entry::Vacant(entry) => {
                    IupSetCallback(ih, "LDESTROY_CB".as_ptr() as *const i8, ldestroy_cb);
                    let rc = Rc::new(HandleBox(Cell::new(ih)));
                    entry.insert(Rc::downgrade(&rc));
                    rc
                },
            }
        );
        HandleRc(rc)
    }

    pub fn get(&self) -> *mut Ihandle {
        self.0.get()
    }

    pub fn try_unwrap(self) -> Result<*mut Ihandle, HandleRc> {
        Rc::try_unwrap(self.0).map(|handle_box| {
            let handle = handle_box.get();
            // null out so that `HandleBox` doesn't IupDestroy() it and so that no other
            // `HandleRc` can return it
            handle_box.set(ptr::null_mut());
            handle
        }).map_err(|rc| HandleRc(rc))
    }
}
<|endoftext|>


<commit_before>use futures::future;
use futures::Future;
use hyper::Uri;
use mktemp::Temp;
use std::io::prelude::*;
use std::path::Path;
use std::process::Command;
use tokio_core::reactor::{Handle, Remote};
use tokio_process::CommandExt;
use tera::Tera;

use http_client;
use papers::DocumentSpec;
use error::Error;

pub struct Workspace {
    dir: Temp,
    document_spec: DocumentSpec,
    handle: Handle,
    template_path: ::std::path::PathBuf,
}

/// We ignore file names that end with a slash for now, and always determine the file name from the Uri
/// TODO: investigate Content-Disposition: attachment
fn extract_file_name_from_uri(uri: &Uri) -> Option<String> {
    match uri.path().split('/').last() {
        Some(name) => {
            if !name.is_empty() {
                Some(name.to_string())
            } else {
                None
            }
        },
        None => None,
    }
}

/// Since mktemp::Temp implements Drop by deleting the directory, we don't need to worry about
/// leaving files or directories behind.
impl Workspace {

    pub fn new(remote: Remote, document_spec: DocumentSpec) -> Result<Workspace, Error> {
        let dir = Temp::new_dir()?;
        let mut template_path = dir.to_path_buf();
        template_path.push(Path::new("out.tex"));
        Ok(Workspace {
            document_spec,
            handle: remote.handle().unwrap(),
            template_path,
            dir,
        })
    }

    pub fn preview(self) -> Box<Future<Item=String, Error=Error>> {
        let Workspace {
            handle,
            document_spec,
            template_path: _,
            dir: _,
        } = self;

        let DocumentSpec {
            assets_urls: _,
            callback_url: _,
            template_url,
            variables,
        } = document_spec;

        // Download the template and populate it
        let work = http_client::download_file(&handle.clone(), template_url.0)
            .and_then(|bytes| {
                future::result(::std::string::String::from_utf8(bytes))
                    .map_err(Error::from)
            }).and_then(move |template_string| {
                Tera::one_off(&template_string, &variables, false)
                    .map_err(Error::from)
            });

        Box::new(work)
    }

    pub fn execute(self) -> Box<Future<Item=Vec<u8>, Error=Error>> {
        let Workspace {
            handle,
            document_spec,
            template_path,
            dir,
        } = self;

        let DocumentSpec {
            assets_urls,
            callback_url: _,
            template_url,
            variables,
        } = document_spec;

        let out_tex_path = dir.to_path_buf();
        let out_pdf_path = dir.to_path_buf();

        // First download the template and populate it
        let work = http_client::download_file(&handle.clone(), template_url.0)
                .and_then(|bytes| {
                    future::result(::std::string::String::from_utf8(bytes))
                        .map_err(Error::from)
                        .map(|template_string| (handle, template_string))
                }).and_then(move |(handle, template_string)| {
                    Tera::one_off(&template_string, &variables, false)
                        .map_err(Error::from)
                        .map(|latex_string| (handle, latex_string))
                }).and_then(|(handle, latex_string)| {
                    let mut file = ::std::fs::File::open(template_path.clone()).unwrap();
                    file.write_all(latex_string.as_bytes()).unwrap();
                    future::ok((handle, template_path))
                })

        // Then download the assets and save them in the temporary directory
                .and_then(move |(handle, template_path)| {
                    let named = assets_urls.into_iter().filter_map(|url| {
                        let inner = url.0;
                        extract_file_name_from_uri(&inner).map(|file_name| (file_name, inner))
                    });

                    let inner_handle = handle.clone();

                    let download_named = move |(name, url)| {
                        let mut path = out_tex_path.clone();
                        path.push(name);

                        http_client::download_file(&inner_handle, url)
                            .map(move |bytes| ::std::fs::File::open(&path).unwrap().write_all(&bytes))
                            .map_err(Error::from)
                    };
                    future::join_all(named.map(download_named))
                        .map(|result| (handle, template_path, result))
                })

        // Then run latex
                .and_then(|(handle, template_path, _)| {
                    Command::new("pdflatex")
                        .arg(template_path.clone().to_str().unwrap())
                        .status_async(&handle.clone())
                        .map_err(Error::from)
                }).and_then(|exit_status| {
                    if exit_status.success() {
                        future::ok(())
                    } else {
                        future::err(Error::LatexFailed)
                    }
                })

        // Then construct the path to the generated PDF
                .and_then(|_| {
                    let mut path = out_pdf_path;
                    path.push(Path::new("out.pdf"));
                    future::ok(())
                }).map(|_| Vec::new());

        Box::new(work)
    }
}

#[cfg(test)]
mod tests {
    use hyper::Uri;
    use super::extract_file_name_from_uri;

    #[test]
    fn test_extract_file_name_from_uri_works() {
        let assert_extracted = |input: &'static str, expected_output: Option<&'static str>| {
            let uri = input.parse::<Uri>().unwrap();
            assert_eq!(extract_file_name_from_uri(&uri), expected_output.map(|o| o.to_string()));
        };

        assert_extracted("/logo.png", Some("logo.png"));
        assert_extracted("/assets/", None);
        assert_extracted("/assets/icon", Some("icon"));
        assert_extracted("/", None);
        assert_extracted("http://www.store2be.com", None);
    }
}
<commit_msg>:sparkles: Send the PDF bytes as the request body<commit_after>use futures::future;
use futures::Future;
use hyper::Uri;
use hyper::client::{Client, Request};
use hyper::Method::Post;
use mktemp::Temp;
use std::io::prelude::*;
use std::path::Path;
use std::process::Command;
use tokio_core::reactor::{Handle, Remote};
use tokio_process::CommandExt;
use tera::Tera;

use http_client;
use papers::DocumentSpec;
use error::Error;

pub struct Workspace {
    dir: Temp,
    document_spec: DocumentSpec,
    handle: Handle,
    template_path: ::std::path::PathBuf,
}

/// We ignore file names that end with a slash for now, and always determine the file name from the Uri
/// TODO: investigate Content-Disposition: attachment
fn extract_file_name_from_uri(uri: &Uri) -> Option<String> {
    match uri.path().split('/').last() {
        Some(name) => {
            if !name.is_empty() {
                Some(name.to_string())
            } else {
                None
            }
        },
        None => None,
    }
}

/// Since mktemp::Temp implements Drop by deleting the directory, we don't need to worry about
/// leaving files or directories behind.
impl Workspace {

    pub fn new(remote: Remote, document_spec: DocumentSpec) -> Result<Workspace, Error> {
        let dir = Temp::new_dir()?;
        let mut template_path = dir.to_path_buf();
        template_path.push(Path::new("out.tex"));
        Ok(Workspace {
            document_spec,
            handle: remote.handle().unwrap(),
            template_path,
            dir,
        })
    }

    pub fn preview(self) -> Box<Future<Item=String, Error=Error>> {
        let Workspace {
            handle,
            document_spec,
            template_path: _,
            dir: _,
        } = self;

        let DocumentSpec {
            assets_urls: _,
            callback_url: _,
            template_url,
            variables,
        } = document_spec;

        // Download the template and populate it
        let work = http_client::download_file(&handle.clone(), template_url.0)
            .and_then(|bytes| {
                future::result(::std::string::String::from_utf8(bytes))
                    .map_err(Error::from)
            }).and_then(move |template_string| {
                Tera::one_off(&template_string, &variables, false)
                    .map_err(Error::from)
            });

        Box::new(work)
    }

    pub fn execute(self) -> Box<Future<Item=Vec<u8>, Error=Error>> {
        let Workspace {
            handle,
            document_spec,
            template_path,
            dir,
        } = self;

        let DocumentSpec {
            assets_urls,
            callback_url,
            template_url,
            variables,
        } = document_spec;

        let out_tex_path = dir.to_path_buf();
        let out_pdf_path = dir.to_path_buf();

        // First download the template and populate it
        let work = http_client::download_file(&handle.clone(), template_url.0)
                .and_then(|bytes| {
                    future::result(::std::string::String::from_utf8(bytes))
                        .map_err(Error::from)
                        .map(|template_string| (handle, template_string))
                }).and_then(move |(handle, template_string)| {
                    Tera::one_off(&template_string, &variables, false)
                        .map_err(Error::from)
                        .map(|latex_string| (handle, latex_string))
                }).and_then(|(handle, latex_string)| {
                    let mut file = ::std::fs::File::open(template_path.clone()).unwrap();
                    file.write_all(latex_string.as_bytes()).unwrap();
                    future::ok((handle, template_path))
                })

        // Then download the assets and save them in the temporary directory
                .and_then(move |(handle, template_path)| {
                    let named = assets_urls.into_iter().filter_map(|url| {
                        let inner = url.0;
                        extract_file_name_from_uri(&inner).map(|file_name| (file_name, inner))
                    });

                    let inner_handle = handle.clone();

                    let download_named = move |(name, url)| {
                        let mut path = out_tex_path.clone();
                        path.push(name);

                        http_client::download_file(&inner_handle, url)
                            .map(move |bytes| ::std::fs::File::open(&path).unwrap().write_all(&bytes))
                            .map_err(Error::from)
                    };
                    future::join_all(named.map(download_named))
                        .map(|result| (handle, template_path, result))
                })

        // Then run latex
                .and_then(move |(handle, template_path, _)| {
                    let inner_handle = handle.clone();
                    Command::new("pdflatex")
                        .arg(template_path.clone().to_str().unwrap())
                        .status_async(&inner_handle)
                        .map(|exit_status| (exit_status, handle))
                        .map_err(Error::from)
                }).and_then(|(exit_status, handle)| {
                    if exit_status.success() {
                        future::ok(handle)
                    } else {
                        future::err(Error::LatexFailed)
                    }
                })

        // Then construct the path to the generated PDF
                .and_then(move |handle| {
                    let mut path = out_pdf_path;
                    path.push(Path::new("out.pdf"));
                    future::ok((handle, path))
                })

        // Finally, post it to the callback URL
                .and_then(move |(handle, pdf_path)| {
                    let pdf_file = ::std::fs::File::open(pdf_path).unwrap();
                    let pdf_bytes: Vec<u8> = pdf_file.bytes().collect::<Result<Vec<u8>, _>>().unwrap();

                    let mut request = Request::new(Post, callback_url.0);
                    request.set_body(pdf_bytes);

                    let client = Client::new(&handle);
                    client.request(request);
                    future::ok(())
                }).map(|_| Vec::new());

        Box::new(work)
    }
}

#[cfg(test)]
mod tests {
    use hyper::Uri;
    use super::extract_file_name_from_uri;

    #[test]
    fn test_extract_file_name_from_uri_works() {
        let assert_extracted = |input: &'static str, expected_output: Option<&'static str>| {
            let uri = input.parse::<Uri>().unwrap();
            assert_eq!(extract_file_name_from_uri(&uri), expected_output.map(|o| o.to_string()));
        };

        assert_extracted("/logo.png", Some("logo.png"));
        assert_extracted("/assets/", None);
        assert_extracted("/assets/icon", Some("icon"));
        assert_extracted("/", None);
        assert_extracted("http://www.store2be.com", None);
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

#[macro_use]
extern crate maplit;
extern crate test;
extern crate abra;

use test::Bencher;

use abra::term::Term;
use abra::token::Token;
use abra::document::Document;
use abra::store::{IndexStore, IndexReader};
use abra::store::memory::{MemoryIndexStore, MemoryIndexStoreReader};
use abra::query_set::QuerySetIterator;

fn make_test_store() -> MemoryIndexStore {
    let mut store = MemoryIndexStore::new();

    for i in 0..10000 {
        let mut tokens = Vec::new();

        if i % 3 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("fizz".to_string()),
                position: position,
            });
        }

        if i % 5 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("buzz".to_string()),
                position: position,
            });
        }

        store.insert_or_update_document(Document {
            key: i.to_string(),
            fields: btreemap! {
                "body".to_string() => tokens
            }
        });
    }

    store
}

#[bench]
fn bench_all(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::All {
            iter: reader.iter_docids_all(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_buzz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_conjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Conjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_disjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Disjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_exclusion(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, "body").unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, "body").unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Exclusion {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}
<commit_msg>Updated benchmarks for schema changes<commit_after>#![feature(test)]

#[macro_use]
extern crate maplit;
extern crate test;
extern crate abra;

use test::Bencher;

use abra::term::Term;
use abra::token::Token;
use abra::schema::FieldType;
use abra::document::Document;
use abra::store::{IndexStore, IndexReader};
use abra::store::memory::{MemoryIndexStore, MemoryIndexStoreReader};
use abra::query_set::QuerySetIterator;

fn make_test_store() -> MemoryIndexStore {
    let mut store = MemoryIndexStore::new();
    let body_field = store.add_field("body".to_string(), FieldType::Text).unwrap();

    for i in 0..10000 {
        let mut tokens = Vec::new();

        if i % 3 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("fizz".to_string()),
                position: position,
            });
        }

        if i % 5 == 0 {
            let position = tokens.len() as u32 + 1;
            tokens.push(Token {
                term: Term::String("buzz".to_string()),
                position: position,
            });
        }

        store.insert_or_update_document(Document {
            key: i.to_string(),
            fields: hashmap! {
                body_field => tokens
            }
        });
    }

    store
}

#[bench]
fn bench_all(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::All {
            iter: reader.iter_docids_all(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_buzz_term(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_conjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Conjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_disjunction(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Disjunction {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}

#[bench]
fn bench_fizzbuzz_exclusion(b: &mut Bencher) {
    let store = make_test_store();
    let reader = store.reader();
    let body_field = reader.schema().get_field_by_name("body").unwrap();

    let fizz_term = Term::String("fizz".to_string()).to_bytes();
    let buzz_term = Term::String("buzz".to_string()).to_bytes();

    b.iter(|| {
        let mut fizz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&fizz_term, &body_field).unwrap(),
        };
        let mut buzz_iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Term {
            iter: reader.iter_docids_with_term(&buzz_term, &body_field).unwrap(),
        };
        let mut iterator: QuerySetIterator<MemoryIndexStoreReader> = QuerySetIterator::Exclusion {
            iter_a: Box::new(fizz_iterator),
            iter_b: Box::new(buzz_iterator),
            initialised: false,
            current_doc_a: None,
            current_doc_b: None,
        };

        for doc_id in iterator {}
    });
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};

use crate::{Interface, Main, Resource};

use wayland_commons::debug;
use wayland_commons::map::{Object, ObjectMap, ObjectMetadata};
use wayland_commons::user_data::UserData;
use wayland_commons::{MessageGroup, ThreadGuard};

use super::{ClientInner, Dispatcher, WAYLAND_DEBUG};

pub(crate) type ResourceDestructor = RefCell<dyn FnMut(ResourceInner, crate::DispatchData<'_>)>;

#[derive(Clone)]
pub(crate) struct ObjectMeta {
    pub(crate) dispatcher: Arc<ThreadGuard<RefCell<dyn Dispatcher>>>,
    pub(crate) destructor: Option<Arc<ThreadGuard<ResourceDestructor>>>,
    pub(crate) alive: Arc<AtomicBool>,
    user_data: Arc<UserData>,
}

impl ObjectMetadata for ObjectMeta {
    fn child(&self) -> ObjectMeta {
        ObjectMeta::new()
    }
}

impl ObjectMeta {
    pub(crate) fn new() -> ObjectMeta {
        ObjectMeta {
            alive: Arc::new(AtomicBool::new(true)),
            user_data: Arc::new(UserData::new()),
            dispatcher: super::default_dispatcher(),
            destructor: None,
        }
    }

    pub(crate) fn with_dispatcher<D: Dispatcher>(disp: D) -> ObjectMeta {
        ObjectMeta {
            alive: Arc::new(AtomicBool::new(true)),
            user_data: Arc::new(UserData::new()),
            dispatcher: Arc::new(ThreadGuard::new(RefCell::new(disp))),
            destructor: None,
        }
    }
}

#[derive(Clone)]
pub(crate) struct ResourceInner {
    pub(crate) id: u32,
    pub(crate) object: Object<ObjectMeta>,
    pub(crate) client: ClientInner,
}

impl ResourceInner {
    pub(crate) fn from_id(
        id: u32,
        map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
        client: ClientInner,
    ) -> Option<ResourceInner> {
        let me = map.lock().unwrap().find(id);
        me.map(|obj| ResourceInner { id, object: obj, client })
    }

    pub(crate) fn is_interface<I: Interface>(&self) -> bool {
        self.object.is_interface::<I>()
    }

    pub(crate) fn send<I: Interface>(&self, msg: I::Event) {
        if let Some(ref mut conn_lock) = *self.client.data.lock().unwrap() {
            let is_alive = self.is_alive();

            if !is_alive {
                return;
            }

            let destructor = msg.is_destructor();
            let msg = msg.into_raw(self.id);

            if WAYLAND_DEBUG.load(Ordering::Relaxed) {
                debug::print_send_message(
                    I::NAME,
                    self.id,
                    is_alive,
                    self.object.events[msg.opcode as usize].name,
                    &msg.args,
                );
            }

            // TODO: figure our if this can fail and still be recoverable ?
            conn_lock.write_message(&msg).expect("Sending a message failed.");
            if destructor {
                self.object.meta.alive.store(false, Ordering::Release);
                // schedule a destructor
                conn_lock.schedule_destructor(self.clone());
                // send delete_id
                let _ = conn_lock.delete_id(self.id);
            }
        }
    }

    pub(crate) fn is_alive(&self) -> bool {
        self.object.meta.alive.load(Ordering::Acquire)
    }

    pub(crate) fn version(&self) -> u32 {
        self.object.version
    }

    pub(crate) fn equals(&self, other: &ResourceInner) -> bool {
        self.is_alive() && Arc::ptr_eq(&self.object.meta.alive, &other.object.meta.alive)
    }

    pub(crate) fn same_client_as(&self, other: &ResourceInner) -> bool {
        self.client.equals(&other.client)
    }

    pub(crate) fn post_error(&self, error_code: u32, msg: String) {
        self.client.post_error(self.id, error_code, msg)
    }

    pub(crate) fn user_data(&self) -> &UserData {
        &self.object.meta.user_data
    }

    pub(crate) fn client(&self) -> Option<ClientInner> {
        Some(self.client.clone())
    }

    pub(crate) fn id(&self) -> u32 {
        if self.is_alive() {
            self.id
        } else {
            0
        }
    }

    pub fn assign<I, E>(&self, filter: crate::Filter<E>)
    where
        I: Interface + AsRef<Resource<I>> + From<Resource<I>>,
        E: From<(Main<I>, I::Request)> + 'static,
        I::Request: MessageGroup<Map = super::ResourceMap>,
    {
        self.client.set_dispatcher_for(self.id, super::make_dispatcher(filter));
    }

    pub fn assign_destructor<I, E>(&self, filter: crate::Filter<E>)
    where
        I: Interface + AsRef<Resource<I>> + From<Resource<I>>,
        E: From<Resource<I>> + 'static,
    {
        self.client.set_destructor_for(self.id, super::make_destructor(filter));
    }
}
<commit_msg>server: print zombies as well<commit_after>use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};

use crate::{Interface, Main, Resource};

use wayland_commons::debug;
use wayland_commons::map::{Object, ObjectMap, ObjectMetadata};
use wayland_commons::user_data::UserData;
use wayland_commons::{MessageGroup, ThreadGuard};

use super::{ClientInner, Dispatcher, WAYLAND_DEBUG};

pub(crate) type ResourceDestructor = RefCell<dyn FnMut(ResourceInner, crate::DispatchData<'_>)>;

#[derive(Clone)]
pub(crate) struct ObjectMeta {
    pub(crate) dispatcher: Arc<ThreadGuard<RefCell<dyn Dispatcher>>>,
    pub(crate) destructor: Option<Arc<ThreadGuard<ResourceDestructor>>>,
    pub(crate) alive: Arc<AtomicBool>,
    user_data: Arc<UserData>,
}

impl ObjectMetadata for ObjectMeta {
    fn child(&self) -> ObjectMeta {
        ObjectMeta::new()
    }
}

impl ObjectMeta {
    pub(crate) fn new() -> ObjectMeta {
        ObjectMeta {
            alive: Arc::new(AtomicBool::new(true)),
            user_data: Arc::new(UserData::new()),
            dispatcher: super::default_dispatcher(),
            destructor: None,
        }
    }

    pub(crate) fn with_dispatcher<D: Dispatcher>(disp: D) -> ObjectMeta {
        ObjectMeta {
            alive: Arc::new(AtomicBool::new(true)),
            user_data: Arc::new(UserData::new()),
            dispatcher: Arc::new(ThreadGuard::new(RefCell::new(disp))),
            destructor: None,
        }
    }
}

#[derive(Clone)]
pub(crate) struct ResourceInner {
    pub(crate) id: u32,
    pub(crate) object: Object<ObjectMeta>,
    pub(crate) client: ClientInner,
}

impl ResourceInner {
    pub(crate) fn from_id(
        id: u32,
        map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
        client: ClientInner,
    ) -> Option<ResourceInner> {
        let me = map.lock().unwrap().find(id);
        me.map(|obj| ResourceInner { id, object: obj, client })
    }

    pub(crate) fn is_interface<I: Interface>(&self) -> bool {
        self.object.is_interface::<I>()
    }

    pub(crate) fn send<I: Interface>(&self, msg: I::Event) {
        if let Some(ref mut conn_lock) = *self.client.data.lock().unwrap() {
            let is_alive = self.is_alive();

            let destructor = msg.is_destructor();
            let msg = msg.into_raw(self.id);

            if WAYLAND_DEBUG.load(Ordering::Relaxed) {
                debug::print_send_message(
                    I::NAME,
                    self.id,
                    is_alive,
                    self.object.events[msg.opcode as usize].name,
                    &msg.args,
                );
            }

            if !is_alive {
                return;
            }

            // TODO: figure our if this can fail and still be recoverable ?
            conn_lock.write_message(&msg).expect("Sending a message failed.");
            if destructor {
                self.object.meta.alive.store(false, Ordering::Release);
                // schedule a destructor
                conn_lock.schedule_destructor(self.clone());
                // send delete_id
                let _ = conn_lock.delete_id(self.id);
            }
        }
    }

    pub(crate) fn is_alive(&self) -> bool {
        self.object.meta.alive.load(Ordering::Acquire)
    }

    pub(crate) fn version(&self) -> u32 {
        self.object.version
    }

    pub(crate) fn equals(&self, other: &ResourceInner) -> bool {
        self.is_alive() && Arc::ptr_eq(&self.object.meta.alive, &other.object.meta.alive)
    }

    pub(crate) fn same_client_as(&self, other: &ResourceInner) -> bool {
        self.client.equals(&other.client)
    }

    pub(crate) fn post_error(&self, error_code: u32, msg: String) {
        self.client.post_error(self.id, error_code, msg)
    }

    pub(crate) fn user_data(&self) -> &UserData {
        &self.object.meta.user_data
    }

    pub(crate) fn client(&self) -> Option<ClientInner> {
        Some(self.client.clone())
    }

    pub(crate) fn id(&self) -> u32 {
        if self.is_alive() {
            self.id
        } else {
            0
        }
    }

    pub fn assign<I, E>(&self, filter: crate::Filter<E>)
    where
        I: Interface + AsRef<Resource<I>> + From<Resource<I>>,
        E: From<(Main<I>, I::Request)> + 'static,
        I::Request: MessageGroup<Map = super::ResourceMap>,
    {
        self.client.set_dispatcher_for(self.id, super::make_dispatcher(filter));
    }

    pub fn assign_destructor<I, E>(&self, filter: crate::Filter<E>)
    where
        I: Interface + AsRef<Resource<I>> + From<Resource<I>>,
        E: From<Resource<I>> + 'static,
    {
        self.client.set_destructor_for(self.id, super::make_destructor(filter));
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate harfbuzz_rs;
extern crate image as piston_image;
extern crate rusttype;
extern crate glfw_window;

use harfbuzz_rs::{Face, UnicodeBuffer};
use harfbuzz_rs::rusttype::ScaledRusttypeFont;

use piston_window::*;
use piston_image::{ImageBuffer, Rgba};
use glfw_window::GlfwWindow;

fn main() {
    let mut window: PistonWindow<GlfwWindow> = WindowSettings::new("Hello World!", [512; 2])
        .build()
        .unwrap();

    window.set_swap_buffers(true);
    let glyphs = shape(&mut window);

    println!("window size {:?}", window.window.size());
    println!("window draw size {:?}", window.draw_size());
    println!("render target view dimensions {:?}",
             window.output_color.get_dimensions());

    while let Some(e) = window.next() {
        window.draw_2d(&e, |c, g| {
            clear([1.0, 1.0, 1.0, 1.0], g);
            for &(image, ref texture) in &glyphs {
                image.draw(texture, &DrawState::default(), c.transform, g);
            }
        });
    }
}

fn shape<T: Window>(win: &mut PistonWindow<T>) -> Vec<(Image, G2dTexture)> {
    let index = 0;
    let path = "testfiles/Optima.ttc";
    let mut hb_font = Face::from_file(path, index)
        .expect("Error reading font file.")
        .create_font();

    let s_factor: f64 = 0.5;
    let fontsize: f64 = 80.0;
    hb_font.set_scale(fontsize as i32 * 64, fontsize as i32 * 64);
    hb_font.set_ppem(96 * 64, 96 * 64);

    let rt_font = ScaledRusttypeFont::from_hb_font(&hb_font);

    // Create a buffer with some text and shape it...
    let result = UnicodeBuffer::new().add_str("Hello World! iiiiiiiiiiiiiiiiii").shape(&hb_font, &[]);

    // ... and get the results.
    let positions = result.get_glyph_positions();
    let infos = result.get_glyph_infos();

    let mut cursor = (10*64, 100*64);
    let mut vec = Vec::with_capacity(result.len());
    // iterate over the shaped glyphs
    for (position, info) in positions.iter().zip(infos) {
        let gid = info.codepoint;
        let x_advance = position.x_advance;
        let x_offset = position.x_offset;
        let y_offset = position.y_offset;

        let x_pos: f64 = (cursor.0 + x_offset) as f64 / 64.0;
        let y_pos: f64 = (cursor.1 + y_offset) as f64 / 64.0;

        // separate x_pos and y_pos into integral an fractional parts for subpixel positioning.
        let x_pos_int = x_pos.trunc();
        let x_pos_frac = x_pos.fract();
        let y_pos_int = y_pos.trunc();
        let y_pos_frac = y_pos.fract();

        // no metrics hinting
        cursor.0 += x_advance;

        let glyph = match rt_font.font.glyph(rusttype::GlyphId(gid)) {
            Some(glyph) => glyph,
            None => continue,
        };

        let glyph = glyph.scaled(rt_font.scale).positioned(rusttype::Point {
            x: x_pos_frac as f32,
            y: y_pos_frac as f32,
        });
        let bbox = match glyph.pixel_bounding_box() {
            Some(bbox) => bbox,
            None => continue,
        };
        let image_buffer = draw_glyph(&glyph);

        let x_origin = (x_pos_int + bbox.min.x as f64) * s_factor;
        let y_origin = (y_pos_int + bbox.min.y as f64) * s_factor;
        let width = (bbox.max.x - bbox.min.x) as f64 * s_factor;
        let height = (bbox.max.y - bbox.min.y) as f64 * s_factor;
        let image = Image::new().rect([x_origin, y_origin, width, height]);

        let texture = Texture::from_image(&mut win.factory, &image_buffer, &TextureSettings::new())
            .unwrap();

        vec.push((image, texture));
    }

    vec
}

fn draw_glyph(glyph: &rusttype::PositionedGlyph) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
    let bbox = glyph.pixel_bounding_box().unwrap();
    let mut image_buffer = ImageBuffer::new((bbox.max.x - bbox.min.x) as u32,
                                            (bbox.max.y - bbox.min.y) as u32);
    glyph.draw(|x, y, v| {
        let v = (255.0 * v).round() as u8;
        image_buffer.put_pixel(x, y, Rgba { data: [0, 0, 0, v] })
    });
    image_buffer
}
<commit_msg>Use rusttype font funcs in render.rs example.<commit_after>extern crate piston_window;
extern crate harfbuzz_rs;
extern crate image as piston_image;
extern crate rusttype;
extern crate glfw_window;

use harfbuzz_rs::{Face, UnicodeBuffer};
use harfbuzz_rs::rusttype::{ScaledRusttypeFont, RT_FONT_FUNCS};

use piston_window::*;
use piston_image::{ImageBuffer, Rgba};
use glfw_window::GlfwWindow;

fn main() {
    let mut window: PistonWindow<GlfwWindow> = WindowSettings::new("Hello World!", [512; 2])
        .build()
        .unwrap();

    window.set_swap_buffers(true);
    let glyphs = shape(&mut window);

    println!("window size {:?}", window.window.size());
    println!("window draw size {:?}", window.draw_size());
    println!("render target view dimensions {:?}",
             window.output_color.get_dimensions());

    while let Some(e) = window.next() {
        window.draw_2d(&e, |c, g| {
            clear([1.0, 1.0, 1.0, 1.0], g);
            for &(image, ref texture) in &glyphs {
                image.draw(texture, &DrawState::default(), c.transform, g);
            }
        });
    }
}

fn shape<T: Window>(win: &mut PistonWindow<T>) -> Vec<(Image, G2dTexture)> {
    let index = 0;
    let path = "testfiles/Optima.ttc";
    let rt_font; // declare here so that there are no lifetime issues.
    let mut hb_font = Face::from_file(path, index)
        .expect("Error reading font file.")
        .create_font();

    let s_factor: f64 = 0.5;
    let fontsize: f64 = 80.0;
    hb_font.set_scale(fontsize as i32 * 64, fontsize as i32 * 64);
    hb_font.set_ppem(96 * 64, 96 * 64);

    rt_font = ScaledRusttypeFont::from_hb_font(&hb_font);
    hb_font.set_font_funcs(&RT_FONT_FUNCS, &rt_font);

    // Create a buffer with some text and shape it...
    let result = UnicodeBuffer::new().add_str("Hello World! iiiiiiiiiiiiiiiiii").shape(&hb_font, &[]);

    // ... and get the results.
    let positions = result.get_glyph_positions();
    let infos = result.get_glyph_infos();

    let mut cursor = (10*64, 100*64);
    let mut vec = Vec::with_capacity(result.len());
    // iterate over the shaped glyphs
    for (position, info) in positions.iter().zip(infos) {
        let gid = info.codepoint;
        let x_advance = position.x_advance;
        let x_offset = position.x_offset;
        let y_offset = position.y_offset;

        let x_pos: f64 = (cursor.0 + x_offset) as f64 / 64.0;
        let y_pos: f64 = (cursor.1 + y_offset) as f64 / 64.0;

        // separate x_pos and y_pos into integral an fractional parts for subpixel positioning.
        let x_pos_int = x_pos.trunc();
        let x_pos_frac = x_pos.fract();
        let y_pos_int = y_pos.trunc();
        let y_pos_frac = y_pos.fract();

        // no metrics hinting
        cursor.0 += x_advance;

        let glyph = match rt_font.font.glyph(rusttype::GlyphId(gid)) {
            Some(glyph) => glyph,
            None => continue,
        };

        let glyph = glyph.scaled(rt_font.scale).positioned(rusttype::Point {
            x: x_pos_frac as f32,
            y: y_pos_frac as f32,
        });
        let bbox = match glyph.pixel_bounding_box() {
            Some(bbox) => bbox,
            None => continue,
        };
        let image_buffer = draw_glyph(&glyph);

        let x_origin = (x_pos_int + bbox.min.x as f64) * s_factor;
        let y_origin = (y_pos_int + bbox.min.y as f64) * s_factor;
        let width = (bbox.max.x - bbox.min.x) as f64 * s_factor;
        let height = (bbox.max.y - bbox.min.y) as f64 * s_factor;
        let image = Image::new().rect([x_origin, y_origin, width, height]);

        let texture = Texture::from_image(&mut win.factory, &image_buffer, &TextureSettings::new())
            .unwrap();

        vec.push((image, texture));
    }

    vec
}

fn draw_glyph(glyph: &rusttype::PositionedGlyph) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
    let bbox = glyph.pixel_bounding_box().unwrap();
    let mut image_buffer = ImageBuffer::new((bbox.max.x - bbox.min.x) as u32,
                                            (bbox.max.y - bbox.min.y) as u32);
    glyph.draw(|x, y, v| {
        let v = (255.0 * v).round() as u8;
        image_buffer.put_pixel(x, y, Rgba { data: [0, 0, 0, v] })
    });
    image_buffer
}
<|endoftext|>


<commit_before>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;
extern crate docopt;
extern crate quiche;
extern crate env_logger;

use std::fs;
use std::net;
use std::path;
use std::collections::hash_map;
use std::collections::HashMap;

use docopt::Docopt;

use quiche::packet;
use quiche::rand;

const LOCAL_CONN_ID_LEN: usize = 16;

const TRANSPORT_PARAMS: quiche::TransportParams = quiche::TransportParams {
    idle_timeout: 30,
    initial_max_data: 10_000_000,
    initial_max_bidi_streams: 100,
    initial_max_uni_streams: 100,
    max_packet_size: 1500,
    ack_delay_exponent: 3,
    disable_migration: true,
    max_ack_delay: 25,
    initial_max_stream_data_bidi_local: 1_000_000,
    initial_max_stream_data_bidi_remote: 1_000_000,
    initial_max_stream_data_uni: 1_000_000,
    stateless_reset_token_present: true,
    stateless_reset_token: [0xba; 16],
};

const USAGE: &str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; TRANSPORT_PARAMS.max_packet_size as usize];
    let mut out = [0; TRANSPORT_PARAMS.max_packet_size as usize];

    env_logger::init();

    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Conn>> = HashMap::new();

    loop {
        // Garbage collect closed connections.
        connections.retain(|_, ref mut c| {
            debug!("Collecting garbage");

            if c.is_closed() {
                debug!("{} connection collected", c.trace_id());
            }

            !c.is_closed()
        });

        let (len, src) = socket.recv_from(&mut buf).unwrap();
        debug!("Got {} bytes from {}", len, src);

        let buf = &mut buf[..len];

        let hdr = if packet::has_long_header(buf[0]) {
            packet::Header::decode_long(buf)
        } else {
            packet::Header::decode_short(buf, LOCAL_CONN_ID_LEN)
        };

        let hdr = match hdr {
            Ok(v) => v,

            Err(e) => {
                error!("Parsing packet header failed: {:?}", e);
                continue
            }
        };

        if hdr.ty == packet::Type::VersionNegotiation {
            error!("Version negotiation invalid on the server");
            continue;
        }

        let conn = match connections.entry(src) {
            hash_map::Entry::Vacant(v) =>{
                if hdr.version != quiche::VERSION_DRAFT15 {
                    warn!("Doing version negotiation");

                    let len = packet::negotiate_version(&hdr, &mut out).unwrap();
                    let out = &out[..len];

                    socket.send_to(out, &src).unwrap();
                    continue;
                }

                if hdr.ty != packet::Type::Initial {
                    error!("Packet is not Initial");
                    continue;
                }

                let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                rand::rand_bytes(&mut scid[..]);

                let config = quiche::Config {
                    version: quiche::VERSION_DRAFT15,

                    local_conn_id: &scid,

                    local_transport_params: &TRANSPORT_PARAMS,

                    tls_server_name: args.get_str("--name"),
                    tls_certificate: args.get_str("--cert"),
                    tls_certificate_key: args.get_str("--key"),
                };

                debug!("New connection: dcid={} scid={} lcid={}",
                       hex_dump(&hdr.dcid),
                       hex_dump(&hdr.scid),
                       hex_dump(&scid));

                let conn = quiche::Conn::new(config, true).unwrap();

                v.insert(conn)
            },

            hash_map::Entry::Occupied(v) => v.into_mut(),
        };

        let mut left = len;

        // Process potentially coalesced packets.
        while left > 0 {
            let read = match conn.recv(&mut buf[len - left..len]) {
                Ok(v)  => v,
                Err(e) => panic!("{} recv failed: {:?}", conn.trace_id(), e),
            };

            left -= read;

            debug!("{} read {} bytes", conn.trace_id(), read);
        }

        let streams: Vec<u64> = conn.stream_iter().collect();
        for s in streams {
            info!("{} stream {} is readable", conn.trace_id(), s);
            handle_stream(conn, s, &args);
        }

        let mut written = 0;
        while written < buf.len() {
            let write = match conn.send(&mut out) {
                Ok(v) => v,

                Err(quiche::Error::NothingToDo) => {
                    debug!("{} done writing", conn.trace_id());
                    break;
                },

                Err(e) => panic!("{} socket send failed: {:?}",
                                 conn.trace_id(), e),
            };

            // TODO: coalesce packets.
            socket.send_to(&out[..write], &src).unwrap();
            written += write;

            debug!("{} written {} bytes", conn.trace_id(), write);
        }
    }
}

fn handle_stream(conn: &mut quiche::Conn, stream: u64, args: &docopt::ArgvMap) {
    let stream_data = match conn.stream_recv(stream) {
        Ok(v) => v,
        Err(e) => panic!("{} stream recv failed {:?}",
                         conn.trace_id(), e),
    };

    if &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = path::Path::new(&uri);
        let mut path = path::PathBuf::from(args.get_str("--root"));

        for c in uri.components() {
            if let path::Component::Normal(v) = c {
                path.push(v)
            }
        }

        info!("{} got GET request for {:?} on stream {}",
              conn.trace_id(), path, stream);

        let data = fs::read(path.as_path())
                      .unwrap_or_else(|_| Vec::from(String::from("Not Found!")));

        info!("{} sending response of size {} on stream {}",
              conn.trace_id(), data.len(), stream);

        if let Err(e) = conn.stream_send(stream, &data, true) {
            panic!("{} stream send failed {:?}", conn.trace_id(), e);
        }
    }
}

fn hex_dump(buf: &[u8]) -> String {
    let vec: Vec<String> = buf.iter()
                              .map(|b| format!("{:02x}", b))
                              .collect();

    vec.join("")
}
<commit_msg>server: increase static egress flight size<commit_after>// Copyright (c) 2018, Alessandro Ghedini
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;
extern crate docopt;
extern crate quiche;
extern crate env_logger;

use std::fs;
use std::net;
use std::path;
use std::collections::hash_map;
use std::collections::HashMap;

use docopt::Docopt;

use quiche::packet;
use quiche::rand;

const LOCAL_CONN_ID_LEN: usize = 16;

const TRANSPORT_PARAMS: quiche::TransportParams = quiche::TransportParams {
    idle_timeout: 30,
    initial_max_data: 10_000_000,
    initial_max_bidi_streams: 100,
    initial_max_uni_streams: 100,
    max_packet_size: 1500,
    ack_delay_exponent: 3,
    disable_migration: true,
    max_ack_delay: 25,
    initial_max_stream_data_bidi_local: 1_000_000,
    initial_max_stream_data_bidi_remote: 1_000_000,
    initial_max_stream_data_uni: 1_000_000,
    stateless_reset_token_present: true,
    stateless_reset_token: [0xba; 16],
};

const USAGE: &str = "Usage: server [options]

Options:
  -h --help         Show this screen.
  --listen <addr>   Listen on the given IP:port [default: 127.0.0.1:4433]
  --cert <file>     TLS certificate path [default: examples/cert.crt]
  --key <file>      TLS certificate key path [default: examples/cert.key]
  --root <dir>      Root directory [default: examples/root/]
  --name <str>      Name of the server [default: quic.tech]
";

fn main() {
    let mut buf = [0; TRANSPORT_PARAMS.max_packet_size as usize];
    let mut out = [0; TRANSPORT_PARAMS.max_packet_size as usize];

    env_logger::init();

    let args = Docopt::new(USAGE)
                      .and_then(|dopt| dopt.parse())
                      .unwrap_or_else(|e| e.exit());

    let socket = net::UdpSocket::bind(args.get_str("--listen")).unwrap();

    let mut connections: HashMap<net::SocketAddr, Box<quiche::Conn>> = HashMap::new();

    loop {
        // Garbage collect closed connections.
        connections.retain(|_, ref mut c| {
            debug!("Collecting garbage");

            if c.is_closed() {
                debug!("{} connection collected", c.trace_id());
            }

            !c.is_closed()
        });

        let (len, src) = socket.recv_from(&mut buf).unwrap();
        debug!("Got {} bytes from {}", len, src);

        let buf = &mut buf[..len];

        let hdr = if packet::has_long_header(buf[0]) {
            packet::Header::decode_long(buf)
        } else {
            packet::Header::decode_short(buf, LOCAL_CONN_ID_LEN)
        };

        let hdr = match hdr {
            Ok(v) => v,

            Err(e) => {
                error!("Parsing packet header failed: {:?}", e);
                continue
            }
        };

        if hdr.ty == packet::Type::VersionNegotiation {
            error!("Version negotiation invalid on the server");
            continue;
        }

        let conn = match connections.entry(src) {
            hash_map::Entry::Vacant(v) =>{
                if hdr.version != quiche::VERSION_DRAFT15 {
                    warn!("Doing version negotiation");

                    let len = packet::negotiate_version(&hdr, &mut out).unwrap();
                    let out = &out[..len];

                    socket.send_to(out, &src).unwrap();
                    continue;
                }

                if hdr.ty != packet::Type::Initial {
                    error!("Packet is not Initial");
                    continue;
                }

                let mut scid: [u8; LOCAL_CONN_ID_LEN] = [0; LOCAL_CONN_ID_LEN];
                rand::rand_bytes(&mut scid[..]);

                let config = quiche::Config {
                    version: quiche::VERSION_DRAFT15,

                    local_conn_id: &scid,

                    local_transport_params: &TRANSPORT_PARAMS,

                    tls_server_name: args.get_str("--name"),
                    tls_certificate: args.get_str("--cert"),
                    tls_certificate_key: args.get_str("--key"),
                };

                debug!("New connection: dcid={} scid={} lcid={}",
                       hex_dump(&hdr.dcid),
                       hex_dump(&hdr.scid),
                       hex_dump(&scid));

                let conn = quiche::Conn::new(config, true).unwrap();

                v.insert(conn)
            },

            hash_map::Entry::Occupied(v) => v.into_mut(),
        };

        let mut left = len;

        // Process potentially coalesced packets.
        while left > 0 {
            let read = match conn.recv(&mut buf[len - left..len]) {
                Ok(v)  => v,
                Err(e) => panic!("{} recv failed: {:?}", conn.trace_id(), e),
            };

            left -= read;

            debug!("{} read {} bytes", conn.trace_id(), read);
        }

        let streams: Vec<u64> = conn.stream_iter().collect();
        for s in streams {
            info!("{} stream {} is readable", conn.trace_id(), s);
            handle_stream(conn, s, &args);
        }

        let mut written = 0;
        while written < buf.len() * 10 {
            let write = match conn.send(&mut out) {
                Ok(v) => v,

                Err(quiche::Error::NothingToDo) => {
                    debug!("{} done writing", conn.trace_id());
                    break;
                },

                Err(e) => panic!("{} socket send failed: {:?}",
                                 conn.trace_id(), e),
            };

            // TODO: coalesce packets.
            socket.send_to(&out[..write], &src).unwrap();
            written += write;

            debug!("{} written {} bytes", conn.trace_id(), write);
        }
    }
}

fn handle_stream(conn: &mut quiche::Conn, stream: u64, args: &docopt::ArgvMap) {
    let stream_data = match conn.stream_recv(stream) {
        Ok(v) => v,
        Err(e) => panic!("{} stream recv failed {:?}",
                         conn.trace_id(), e),
    };

    if &stream_data[..4] == b"GET " {
        let uri = &stream_data[4..stream_data.len()];
        let uri = String::from_utf8(uri.to_vec()).unwrap();
        let uri = String::from(uri.lines().next().unwrap());
        let uri = path::Path::new(&uri);
        let mut path = path::PathBuf::from(args.get_str("--root"));

        for c in uri.components() {
            if let path::Component::Normal(v) = c {
                path.push(v)
            }
        }

        info!("{} got GET request for {:?} on stream {}",
              conn.trace_id(), path, stream);

        let data = fs::read(path.as_path())
                      .unwrap_or_else(|_| Vec::from(String::from("Not Found!")));

        info!("{} sending response of size {} on stream {}",
              conn.trace_id(), data.len(), stream);

        if let Err(e) = conn.stream_send(stream, &data, true) {
            panic!("{} stream send failed {:?}", conn.trace_id(), e);
        }
    }
}

fn hex_dump(buf: &[u8]) -> String {
    let vec: Vec<String> = buf.iter()
                              .map(|b| format!("{:02x}", b))
                              .collect();

    vec.join("")
}
<|endoftext|>


<commit_before>use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
use crate::infer::InferCtxt;
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;

pub mod find_anon_type;
mod different_lifetimes;
mod named_anon_conflict;
mod placeholder_error;
mod static_impl_trait;
mod trait_impl_difference;
mod util;

impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
    pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
        NiceRegionError::new(self, error.clone()).try_report().is_some()
    }
}

pub struct NiceRegionError<'cx, 'tcx> {
    infcx: &'cx InferCtxt<'cx, 'tcx>,
    error: Option<RegionResolutionError<'tcx>>,
    regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
}

impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
    pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
        Self { infcx, error: Some(error), regions: None }
    }

    pub fn new_from_span(
        infcx: &'cx InferCtxt<'cx, 'tcx>,
        span: Span,
        sub: ty::Region<'tcx>,
        sup: ty::Region<'tcx>,
    ) -> Self {
        Self { infcx, error: None, regions: Some((span, sub, sup)) }
    }

    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx>> {
        // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
        // the nice region errors are required when running under the MIR borrow checker.
        self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
    }

    pub fn try_report(&self) -> Option<ErrorReported> {
        self.try_report_from_nll()
            .map(|mut diag| {
                diag.emit();
                ErrorReported
            })
            .or_else(|| self.try_report_impl_not_conforming_to_trait())
            .or_else(|| self.try_report_anon_anon_conflict())
            .or_else(|| self.try_report_static_impl_trait())
    }

    pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
        match (&self.error, self.regions) {
            (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
            (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
                Some((origin.span(), sub, sup))
            }
            (None, Some((span, sub, sup))) => Some((span, sub, sup)),
            _ => None,
        }
    }
}
<commit_msg>Apply tidy check<commit_after>use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
use crate::infer::InferCtxt;
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;

mod different_lifetimes;
pub mod find_anon_type;
mod named_anon_conflict;
mod placeholder_error;
mod static_impl_trait;
mod trait_impl_difference;
mod util;

impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
    pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
        NiceRegionError::new(self, error.clone()).try_report().is_some()
    }
}

pub struct NiceRegionError<'cx, 'tcx> {
    infcx: &'cx InferCtxt<'cx, 'tcx>,
    error: Option<RegionResolutionError<'tcx>>,
    regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
}

impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
    pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
        Self { infcx, error: Some(error), regions: None }
    }

    pub fn new_from_span(
        infcx: &'cx InferCtxt<'cx, 'tcx>,
        span: Span,
        sub: ty::Region<'tcx>,
        sup: ty::Region<'tcx>,
    ) -> Self {
        Self { infcx, error: None, regions: Some((span, sub, sup)) }
    }

    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx>> {
        // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
        // the nice region errors are required when running under the MIR borrow checker.
        self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
    }

    pub fn try_report(&self) -> Option<ErrorReported> {
        self.try_report_from_nll()
            .map(|mut diag| {
                diag.emit();
                ErrorReported
            })
            .or_else(|| self.try_report_impl_not_conforming_to_trait())
            .or_else(|| self.try_report_anon_anon_conflict())
            .or_else(|| self.try_report_static_impl_trait())
    }

    pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
        match (&self.error, self.regions) {
            (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
            (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
                Some((origin.span(), sub, sup))
            }
            (None, Some((span, sub, sup))) => Some((span, sub, sup)),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use libc::{uint64_t, int64_t, c_double, c_int};
use std::mem;

pub type HeartbeatWindowCompleteFn = extern fn(*const Heartbeat, *const HeartbeatRecord, uint64_t);

#[link(name = "hbs-pow")]
extern {
    fn heartbeat_init(hb: *mut Heartbeat,
                      window_size: uint64_t,
                      window_buffer: *mut HeartbeatRecord,
                      hwc_callback: Option<HeartbeatWindowCompleteFn>) -> c_int;

    fn heartbeat(hb: *mut Heartbeat,
                 user_tag: uint64_t,
                 work: uint64_t,
                 start_time: int64_t,
                 end_time: int64_t);

    fn heartbeat_pow(hb: *mut Heartbeat,
                     user_tag: uint64_t,
                     work: uint64_t,
                     start_time: int64_t,
                     end_time: int64_t,
                     start_energy: uint64_t,
                     end_energy: uint64_t);

    pub fn heartbeat_log_window_buffer(hb: *const Heartbeat,
                                       fd: c_int,
                                       print_header: c_int) -> c_int;

    fn hb_get_user_tag(hb: *const Heartbeat) -> uint64_t;

    fn hb_get_window_rate(hb: *const Heartbeat) -> c_double;

    fn hb_get_window_power(hb: *const Heartbeat) -> c_double;
}

#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatTimeData {
    total_time: int64_t,
    window_time: int64_t,
}

#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatWorkData {
    total_work: uint64_t,
    window_work: uint64_t,
}

#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatEnergyData {
    total_energy: uint64_t,
    window_energy: uint64_t,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct HeartbeatRecord {
    pub id: uint64_t,
    pub user_tag: uint64_t,

    pub work: uint64_t,
    pub start_time: int64_t,
    pub end_time: int64_t,
    pub global_perf: c_double,
    pub window_perf: c_double,
    pub instant_perf: c_double,

    pub start_energy: uint64_t,
    pub end_energy: uint64_t,
    pub global_pwr: c_double,
    pub window_pwr: c_double,
    pub instant_pwr: c_double,
}

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
/// A `Heartbeat` is used for tracking performance/power of recurring jobs.
pub struct Heartbeat {
    counter: uint64_t,
    buffer_index: uint64_t,
    read_index: uint64_t,
    window_size: uint64_t,
    window_buffer: *mut HeartbeatRecord,
    hwc_callback: HeartbeatWindowCompleteFn,

    td: HeartbeatTimeData,
    wd: HeartbeatWorkData,
    ed: HeartbeatEnergyData,
}

pub struct HeartbeatSimple {
    pub hb: Heartbeat,
    pub hbr: Vec<HeartbeatRecord>,
}

impl HeartbeatSimple {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatWindowCompleteFn>) -> Result<HeartbeatSimple, &'static str> {
        unsafe {
            let mut hb = HeartbeatSimple {
                hb: mem::uninitialized(),
                hbr: Vec::with_capacity(window_size)
            };
            match heartbeat_init(&mut hb.hb, window_size as u64, hb.hbr.as_mut_ptr(), hwc_callback) {
                0 => Ok(hb),
                _ => Err("Failed to initialize heartbeat")
            }
        }
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: i64,
                     end_time: i64) {
        unsafe {
            heartbeat(&mut self.hb, tag, work, start_time, end_time)
        }
    }

    /// Issue a heartbeat with energy data.
    pub fn heartbeat_pow(&mut self,
                         tag: u64,
                         work: u64,
                         start_time: i64,
                         end_time: i64,
                         start_energy: u64,
                         end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&self) -> u64 {
        unsafe {
            hb_get_user_tag(&self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&self) -> f64 {
        unsafe {
            hb_get_window_rate(&self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&self) -> f64 {
        unsafe {
            hb_get_window_power(&self.hb)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::uint64_t;

    extern fn heartbeat_window_complete_callback(hb: *const Heartbeat,
                                                 _hbr: *const HeartbeatRecord,
                                                 _size: uint64_t) {
    const STDOUT: i32 = 1;
    unsafe {
        heartbeat_log_window_buffer(hb, STDOUT, 0);
    }
}

    #[test]
    fn test_simple() {
        const TIME_INC: i64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatSimple::new(5, Some(heartbeat_window_complete_callback)).unwrap();
        let mut start_time: i64 = 0;
        let mut end_time: i64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        let mut tag: u64 = 0;
        for _ in 0..10 {
            hb.heartbeat_pow(tag, 1, start_time, end_time, start_energy, end_energy);
            assert!(hb.get_tag() == tag);
            assert!(hb.get_window_perf() == 1.0);
            assert!(hb.get_window_pwr() == 1.0);
            tag += 1;
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }
}
<commit_msg>Documentation<commit_after>use libc::{uint64_t, int64_t, c_double, c_int};
use std::mem;

/// Typedef for the window completion callback function.
pub type HeartbeatWindowCompleteFn = extern fn(*const Heartbeat, *const HeartbeatRecord, uint64_t);

#[link(name = "hbs-pow")]
extern {
    /// Initialize a Heartbeat.
    fn heartbeat_init(hb: *mut Heartbeat,
                      window_size: uint64_t,
                      window_buffer: *mut HeartbeatRecord,
                      hwc_callback: Option<HeartbeatWindowCompleteFn>) -> c_int;

    /// Issue a heartbeat.
    fn heartbeat(hb: *mut Heartbeat,
                 user_tag: uint64_t,
                 work: uint64_t,
                 start_time: int64_t,
                 end_time: int64_t);

    /// Issue a heartbeat with energy data.
    fn heartbeat_pow(hb: *mut Heartbeat,
                     user_tag: uint64_t,
                     work: uint64_t,
                     start_time: int64_t,
                     end_time: int64_t,
                     start_energy: uint64_t,
                     end_energy: uint64_t);

    /// Writes the window buffer to the log specified by the file descriptor.
    pub fn heartbeat_log_window_buffer(hb: *const Heartbeat,
                                       fd: c_int,
                                       print_header: c_int) -> c_int;

    /// Utility function to get the most recent user-specified tag
    fn hb_get_user_tag(hb: *const Heartbeat) -> uint64_t;

    /// Utility function to get the current window performance.
    fn hb_get_window_rate(hb: *const Heartbeat) -> c_double;

    /// Utility function to get the current window power.
    fn hb_get_window_power(hb: *const Heartbeat) -> c_double;
}

/// Time data.
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatTimeData {
    total_time: int64_t,
    window_time: int64_t,
}

/// Work data.
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatWorkData {
    total_work: uint64_t,
    window_work: uint64_t,
}

/// Energy data
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatEnergyData {
    total_energy: uint64_t,
    window_energy: uint64_t,
}

/// A Heartbeat record with current rates (performance and power).
#[derive(Clone, Copy)]
#[repr(C)]
pub struct HeartbeatRecord {
    pub id: uint64_t,
    pub user_tag: uint64_t,

    pub work: uint64_t,
    pub start_time: int64_t,
    pub end_time: int64_t,
    pub global_perf: c_double,
    pub window_perf: c_double,
    pub instant_perf: c_double,

    pub start_energy: uint64_t,
    pub end_energy: uint64_t,
    pub global_pwr: c_double,
    pub window_pwr: c_double,
    pub instant_pwr: c_double,
}

/// A `Heartbeat` is used for tracking performance/power of recurring jobs.
/// This represents a C struct.
#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Heartbeat {
    counter: uint64_t,
    buffer_index: uint64_t,
    read_index: uint64_t,
    window_size: uint64_t,
    window_buffer: *mut HeartbeatRecord,
    hwc_callback: HeartbeatWindowCompleteFn,

    td: HeartbeatTimeData,
    wd: HeartbeatWorkData,
    ed: HeartbeatEnergyData,
}

/// Heartbeat wrapper. Contains the window data buffer.
pub struct HeartbeatSimple {
    pub hb: Heartbeat,
    pub hbr: Vec<HeartbeatRecord>,
}

impl HeartbeatSimple {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatWindowCompleteFn>) -> Result<HeartbeatSimple, &'static str> {
        unsafe {
            let mut hb = HeartbeatSimple {
                hb: mem::uninitialized(),
                hbr: Vec::with_capacity(window_size)
            };
            match heartbeat_init(&mut hb.hb, window_size as u64, hb.hbr.as_mut_ptr(), hwc_callback) {
                0 => Ok(hb),
                _ => Err("Failed to initialize heartbeat")
            }
        }
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: i64,
                     end_time: i64) {
        unsafe {
            heartbeat(&mut self.hb, tag, work, start_time, end_time)
        }
    }

    /// Issue a heartbeat with energy data.
    pub fn heartbeat_pow(&mut self,
                         tag: u64,
                         work: u64,
                         start_time: i64,
                         end_time: i64,
                         start_energy: u64,
                         end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&self) -> u64 {
        unsafe {
            hb_get_user_tag(&self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&self) -> f64 {
        unsafe {
            hb_get_window_rate(&self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&self) -> f64 {
        unsafe {
            hb_get_window_power(&self.hb)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::uint64_t;

    extern fn heartbeat_window_complete_callback(hb: *const Heartbeat,
                                                 _hbr: *const HeartbeatRecord,
                                                 _size: uint64_t) {
    const STDOUT: i32 = 1;
    unsafe {
        heartbeat_log_window_buffer(hb, STDOUT, 0);
    }
}

    #[test]
    fn test_simple() {
        const TIME_INC: i64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatSimple::new(5, Some(heartbeat_window_complete_callback)).unwrap();
        let mut start_time: i64 = 0;
        let mut end_time: i64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        let mut tag: u64 = 0;
        for _ in 0..10 {
            hb.heartbeat_pow(tag, 1, start_time, end_time, start_energy, end_energy);
            assert!(hb.get_tag() == tag);
            assert!(hb.get_window_perf() == 1.0);
            assert!(hb.get_window_pwr() == 1.0);
            tag += 1;
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }
}
<|endoftext|>