<commit_before>//! A crate exposing the `pact` APIs to other languages
//! via a C Foreign Function Interface.

#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![warn(missing_copy_implementations)]

use std::ffi::CStr;
use std::str::FromStr;

use ::log::warn;
use env_logger::Builder;
use libc::c_char;
use pact_models::interaction::Interaction;
use pact_models::pact::Pact;
use pact_models::v4::pact::V4Pact;

use models::message::Message;
use pact_matching as pm;
pub use pact_matching::Mismatch;

use crate::util::*;

pub mod error;
pub mod log;
pub mod models;
pub(crate) mod util;
pub mod mock_server;
pub mod verifier;
pub mod plugins;

const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");

/// Get the current library version
#[no_mangle]
pub extern "C" fn pactffi_version() -> *const c_char {
    VERSION.as_ptr() as *const c_char
}

/// Initialise the mock server library, can provide an environment variable name to use to
/// set the log levels.
///
/// # Safety
///
/// log_env_var must be a valid NULL terminated UTF-8 string.
#[no_mangle]
pub unsafe extern fn pactffi_init(log_env_var: *const c_char) {
    let log_env_var = if !log_env_var.is_null() {
        let c_str = CStr::from_ptr(log_env_var);
        match c_str.to_str() {
            Ok(str) => str,
            Err(err) => {
                warn!("Failed to parse the environment variable name as a UTF-8 string: {}", err);
                "LOG_LEVEL"
            }
        }
    } else {
        "LOG_LEVEL"
    };

    let env = env_logger::Env::new().filter(log_env_var);
    let mut builder = Builder::from_env(env);
    builder.try_init().unwrap_or(());
}

/// Initialises logging, and sets the log level explicitly.
///
/// # Safety
///
/// Exported functions are inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn pactffi_init_with_log_level(level: *const c_char) {
    let mut builder = Builder::from_default_env();
    let log_level = log_level_from_c_char(level);

    builder.filter_level(log_level.to_level_filter());
    builder.try_init().unwrap_or(());
}

/// Enable ANSI coloured output on Windows.
///
/// # Safety
///
/// This function is safe.
#[no_mangle]
#[cfg(windows)]
pub extern "C" fn pactffi_enable_ansi_support() {
  if let Err(err) = ansi_term::enable_ansi_support() {
    warn!("Could not enable ANSI console support - {err}");
  }
}

/// Log using the shared core logging facility.
///
/// This is useful for callers to have a single set of logs.
///
/// * `source` - String. The source of the log, such as the class or caller framework to
///                      disambiguate log lines from the rust logging (e.g. pact_go)
/// * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR
/// * `message` - Message to log
///
/// # Safety
/// This function will fail if any of the pointers passed to it are invalid.
#[no_mangle]
pub unsafe extern "C" fn pactffi_log_message(source: *const c_char, log_level: *const c_char, message: *const c_char) {
    let target = convert_cstr("target", source).unwrap_or("client");

    if !message.is_null() {
        if let Some(message) = convert_cstr("message", message) {
            ::log::log!(target: target, log_level_from_c_char(log_level), "{}", message)
        }
    }
}

unsafe fn log_level_from_c_char(log_level: *const c_char) -> ::log::Level {
    if !log_level.is_null() {
        let level = convert_cstr("log_level", log_level).unwrap_or("INFO");
        ::log::Level::from_str(level).unwrap_or(::log::Level::Info)
    } else {
        ::log::Level::Info
    }
}

fn convert_cstr(name: &str, value: *const c_char) -> Option<&str> {
    unsafe {
        if value.is_null() {
            ::log::warn!("{} is NULL!", name);
            None
        } else {
            let c_str = CStr::from_ptr(value);
            match c_str.to_str() {
                Ok(str) => Some(str),
                Err(err) => {
                    ::log::warn!("Failed to parse {} name as a UTF-8 string: {}", name, err);
                    None
                }
            }
        }
    }
}

ffi_fn! {
    /// Match a pair of messages, producing a collection of mismatches,
    /// which is empty if the two messages matched.
    fn pactffi_match_message(msg_1: *const Message, msg_2: *const Message) -> *const Mismatches {
        let msg_1: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_1 as *mut Message) };
        let msg_2: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_2 as *mut Message) };

        let runtime = tokio::runtime::Runtime::new().unwrap();
        let mismatches = runtime.block_on(async move {
            // TODO: match_message also requires the Pact that the messages belong to
            Mismatches(pm::match_message(&msg_1, &msg_2, &V4Pact::default().boxed()).await)
        });

        ptr::raw_to(mismatches) as *const Mismatches
    } {
        ptr::null_to::<Mismatches>() as *const Mismatches
    }
}

ffi_fn! {
    /// Get an iterator over mismatches.
    fn pactffi_mismatches_get_iter(mismatches: *const Mismatches) -> *mut MismatchesIterator {
        let mismatches = as_ref!(mismatches);
        let iter = MismatchesIterator { current: 0, mismatches };
        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<MismatchesIterator>()
    }
}

ffi_fn! {
    /// Delete mismatches
    fn pactffi_mismatches_delete(mismatches: *const Mismatches) {
        ptr::drop_raw(mismatches as *mut Mismatches);
    }
}

ffi_fn! {
    /// Get the next mismatch from a mismatches iterator.
    ///
    /// Returns a null pointer if no mismatches remain.
    fn pactffi_mismatches_iter_next(iter: *mut MismatchesIterator) -> *const Mismatch {
        let iter = as_mut!(iter);
        let mismatches = as_ref!(iter.mismatches);
        let index = iter.next();
        let mismatch = mismatches
            .0
            .get(index)
            .ok_or(anyhow::anyhow!("iter past the end of mismatches"))?;
       mismatch as *const Mismatch
    } {
        ptr::null_to::<Mismatch>()
    }
}

ffi_fn! {
    /// Delete a mismatches iterator when you're done with it.
    fn pactffi_mismatches_iter_delete(iter: *mut MismatchesIterator) {
        ptr::drop_raw(iter);
    }
}

ffi_fn! {
    /// Get a JSON representation of the mismatch.
    fn pactffi_mismatch_to_json(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let json = mismatch.to_json().to_string();
        string::to_c(&json)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get the type of a mismatch.
    fn pactffi_mismatch_type(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let t = mismatch.mismatch_type();
        string::to_c(t)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a summary of a mismatch.
    fn pactffi_mismatch_summary(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let summary = mismatch.summary();
        string::to_c(&summary)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a description of a mismatch.
    fn pactffi_mismatch_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let description = mismatch.description();
        string::to_c(&description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get an ANSI-compatible description of a mismatch.
    fn pactffi_mismatch_ansi_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let ansi_description = mismatch.ansi_description();
        string::to_c(&ansi_description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

/// A collection of mismatches from a matching comparison.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct Mismatches(Vec<Mismatch>);

/// An iterator over mismatches.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct MismatchesIterator {
    current: usize,
    mismatches: *const Mismatches,
}

impl MismatchesIterator {
    fn next(&mut self) -> usize {
        let idx = self.current;
        self.current += 1;
        idx
    }
}
<commit_msg>chore: add non-windows init ansi support function<commit_after>//! A crate exposing the `pact` APIs to other languages
//! via a C Foreign Function Interface.

#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![warn(missing_copy_implementations)]

use std::ffi::CStr;
use std::str::FromStr;

use ::log::warn;
use env_logger::Builder;
use libc::c_char;
use pact_models::interaction::Interaction;
use pact_models::pact::Pact;
use pact_models::v4::pact::V4Pact;

use models::message::Message;
use pact_matching as pm;
pub use pact_matching::Mismatch;

use crate::util::*;

pub mod error;
pub mod log;
pub mod models;
pub(crate) mod util;
pub mod mock_server;
pub mod verifier;
pub mod plugins;

const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");

/// Get the current library version
#[no_mangle]
pub extern "C" fn pactffi_version() -> *const c_char {
    VERSION.as_ptr() as *const c_char
}

/// Initialise the mock server library, can provide an environment variable name to use to
/// set the log levels.
///
/// # Safety
///
/// log_env_var must be a valid NULL terminated UTF-8 string.
#[no_mangle]
pub unsafe extern fn pactffi_init(log_env_var: *const c_char) {
    let log_env_var = if !log_env_var.is_null() {
        let c_str = CStr::from_ptr(log_env_var);
        match c_str.to_str() {
            Ok(str) => str,
            Err(err) => {
                warn!("Failed to parse the environment variable name as a UTF-8 string: {}", err);
                "LOG_LEVEL"
            }
        }
    } else {
        "LOG_LEVEL"
    };

    let env = env_logger::Env::new().filter(log_env_var);
    let mut builder = Builder::from_env(env);
    builder.try_init().unwrap_or(());
}

/// Initialises logging, and sets the log level explicitly.
///
/// # Safety
///
/// Exported functions are inherently unsafe.
#[no_mangle]
pub unsafe extern "C" fn pactffi_init_with_log_level(level: *const c_char) {
    let mut builder = Builder::from_default_env();
    let log_level = log_level_from_c_char(level);

    builder.filter_level(log_level.to_level_filter());
    builder.try_init().unwrap_or(());
}

/// Enable ANSI coloured output on Windows. On non-Windows platforms, this function is a no-op.
///
/// # Safety
///
/// This function is safe.
#[no_mangle]
#[cfg(windows)]
pub extern "C" fn pactffi_enable_ansi_support() {
  if let Err(err) = ansi_term::enable_ansi_support() {
    warn!("Could not enable ANSI console support - {err}");
  }
}

/// Enable ANSI coloured output on Windows. On non-Windows platforms, this function is a no-op.
///
/// # Safety
///
/// This function is safe.
#[no_mangle]
#[cfg(not(windows))]
pub extern "C" fn pactffi_enable_ansi_support() { }

/// Log using the shared core logging facility.
///
/// This is useful for callers to have a single set of logs.
///
/// * `source` - String. The source of the log, such as the class or caller framework to
///                      disambiguate log lines from the rust logging (e.g. pact_go)
/// * `log_level` - String. One of TRACE, DEBUG, INFO, WARN, ERROR
/// * `message` - Message to log
///
/// # Safety
/// This function will fail if any of the pointers passed to it are invalid.
#[no_mangle]
pub unsafe extern "C" fn pactffi_log_message(source: *const c_char, log_level: *const c_char, message: *const c_char) {
    let target = convert_cstr("target", source).unwrap_or("client");

    if !message.is_null() {
        if let Some(message) = convert_cstr("message", message) {
            ::log::log!(target: target, log_level_from_c_char(log_level), "{}", message)
        }
    }
}

unsafe fn log_level_from_c_char(log_level: *const c_char) -> ::log::Level {
    if !log_level.is_null() {
        let level = convert_cstr("log_level", log_level).unwrap_or("INFO");
        ::log::Level::from_str(level).unwrap_or(::log::Level::Info)
    } else {
        ::log::Level::Info
    }
}

fn convert_cstr(name: &str, value: *const c_char) -> Option<&str> {
    unsafe {
        if value.is_null() {
            ::log::warn!("{} is NULL!", name);
            None
        } else {
            let c_str = CStr::from_ptr(value);
            match c_str.to_str() {
                Ok(str) => Some(str),
                Err(err) => {
                    ::log::warn!("Failed to parse {} name as a UTF-8 string: {}", name, err);
                    None
                }
            }
        }
    }
}

ffi_fn! {
    /// Match a pair of messages, producing a collection of mismatches,
    /// which is empty if the two messages matched.
    fn pactffi_match_message(msg_1: *const Message, msg_2: *const Message) -> *const Mismatches {
        let msg_1: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_1 as *mut Message) };
        let msg_2: Box<dyn Interaction + Send + Sync> = unsafe { Box::from_raw(msg_2 as *mut Message) };

        let runtime = tokio::runtime::Runtime::new().unwrap();
        let mismatches = runtime.block_on(async move {
            // TODO: match_message also requires the Pact that the messages belong to
            Mismatches(pm::match_message(&msg_1, &msg_2, &V4Pact::default().boxed()).await)
        });

        ptr::raw_to(mismatches) as *const Mismatches
    } {
        ptr::null_to::<Mismatches>() as *const Mismatches
    }
}

ffi_fn! {
    /// Get an iterator over mismatches.
    fn pactffi_mismatches_get_iter(mismatches: *const Mismatches) -> *mut MismatchesIterator {
        let mismatches = as_ref!(mismatches);
        let iter = MismatchesIterator { current: 0, mismatches };
        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<MismatchesIterator>()
    }
}

ffi_fn! {
    /// Delete mismatches
    fn pactffi_mismatches_delete(mismatches: *const Mismatches) {
        ptr::drop_raw(mismatches as *mut Mismatches);
    }
}

ffi_fn! {
    /// Get the next mismatch from a mismatches iterator.
    ///
    /// Returns a null pointer if no mismatches remain.
    fn pactffi_mismatches_iter_next(iter: *mut MismatchesIterator) -> *const Mismatch {
        let iter = as_mut!(iter);
        let mismatches = as_ref!(iter.mismatches);
        let index = iter.next();
        let mismatch = mismatches
            .0
            .get(index)
            .ok_or(anyhow::anyhow!("iter past the end of mismatches"))?;
       mismatch as *const Mismatch
    } {
        ptr::null_to::<Mismatch>()
    }
}

ffi_fn! {
    /// Delete a mismatches iterator when you're done with it.
    fn pactffi_mismatches_iter_delete(iter: *mut MismatchesIterator) {
        ptr::drop_raw(iter);
    }
}

ffi_fn! {
    /// Get a JSON representation of the mismatch.
    fn pactffi_mismatch_to_json(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let json = mismatch.to_json().to_string();
        string::to_c(&json)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get the type of a mismatch.
    fn pactffi_mismatch_type(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let t = mismatch.mismatch_type();
        string::to_c(t)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a summary of a mismatch.
    fn pactffi_mismatch_summary(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let summary = mismatch.summary();
        string::to_c(&summary)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get a description of a mismatch.
    fn pactffi_mismatch_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let description = mismatch.description();
        string::to_c(&description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Get an ANSI-compatible description of a mismatch.
    fn pactffi_mismatch_ansi_description(mismatch: *const Mismatch) -> *const c_char {
        let mismatch = as_ref!(mismatch);
        let ansi_description = mismatch.ansi_description();
        string::to_c(&ansi_description)? as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

/// A collection of mismatches from a matching comparison.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct Mismatches(Vec<Mismatch>);

/// An iterator over mismatches.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct MismatchesIterator {
    current: usize,
    mismatches: *const Mismatches,
}

impl MismatchesIterator {
    fn next(&mut self) -> usize {
        let idx = self.current;
        self.current += 1;
        idx
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs;
use std::path;
use itertools::Itertools;
use OutConfig;
use features::Features;

/**
An "abstract" calling convention.

This is to answer the question: "if a function uses the C calling convention, is that the same thing as `"system"`, or do I have to *actually* say `"C"`?"

Without this, almost every Windows API call would need two decls: one with `extern "C"`, and one with `extern "stdcall"`.  Yuck.
*/
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum AbsCallConv {
    ExplicitlyC,
    System,
}

impl AbsCallConv {
    /// Gets the calling convention as a string, suitable for use with Rust's `extern`.
    pub fn as_str(self) -> &'static str {
        use self::AbsCallConv::*;
        match self {
            ExplicitlyC => "C",
            System => "system",
        }
    }
}

/**
Used to centralise how output of translated items is done.

One of the major reasons for this is to consolidate disparate bindings.  That is, if the output for both x86 and x86-64 are the same, then they should use a *single* declaration with an appropriate `#[cfg]` attribute.

Note that `annot` is used for "annotations", which are free-form strings that may be emitted as comments in the output.  These are handy for identifying, for example, *where* a declaration originally came from, for debugging purposes.
*/
pub struct OutputItems {
    next_seq_id: u64,

    /// `[name => [(alias, feat, decl, annot)]]`
    pub fn_aliases: HashMap<String, Vec<(u64, String, Features, String, String)>>,

    /// `[name => [(feat, cconv, decl, annot)]]`
    pub fn_items: HashMap<String, Vec<(u64, Features, AbsCallConv, String, String)>>,

    /// `[name => [(header, feat, decl, annot)]]`
    pub header_items: HashMap<String, Vec<(u64, String, Features, String, String)>>,

    /// `[name => [(feat, decl, annot)]]`
    pub var_items: HashMap<String, Vec<(u64, Features, String, String)>>,
}

impl OutputItems {
    pub fn new() -> Self {
        OutputItems {
            next_seq_id: 0,
            fn_aliases: HashMap::new(),
            fn_items: HashMap::new(),
            header_items: HashMap::new(),
            var_items: HashMap::new(),
        }
    }

    /**
    Adds a function alias.

    This is different from a regular function item in that the library is should be emitted to is based on some *other* function which it is aliasing.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_func_alias(&mut self, name: String, alias: String, feat: Features, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_func_alias({:?}, {:?}, {:?}, {:?}, {:?})", name, alias, feat, decl, annot);

        let decls = self.fn_aliases.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref mut dal, ref mut df, ref dd, ref mut da) in decls.iter_mut() {
            if *dd == decl && *dal == alias {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                if *da != annot {
                    da.push_str(", ");
                    da.push_str(&annot);
                }
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, alias, feat, decl, annot));
        self.next_seq_id += 1;
    }

    /**
    Adds a function declaration.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_func_item(&mut self, name: String, feat: Features, cconv: AbsCallConv, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_func_item({:?}, {:?}, {:?}, {:?}, {:?})", name, feat, cconv, decl, annot);

        let decls = self.fn_items.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref mut df, ref dcc, ref dd, ref mut da) in decls.iter_mut() {
            if *dd == decl && *dcc == cconv {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                if *da != annot {
                    da.push_str(", ");
                    da.push_str(&annot);
                }
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, feat, cconv, decl, annot));
        self.next_seq_id += 1;
    }

    /**
    Adds a header declaration.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_header_item(&mut self, name: String, header: String, feat: Features, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_header_item({:?}, {:?}, {:?}, {:?}, {:?})", header, name, feat, decl, annot);

        let decls = self.header_items.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref dh, ref mut df, ref dd, ref mut da) in decls.iter_mut() {
            if *dh == header && *dd == decl {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                da.push_str(", ");
                da.push_str(&annot);
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, header, feat, decl, annot));
        self.next_seq_id += 1;
    }

    /**
    Adds a variable declaration.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_var_item(&mut self, name: String, feat: Features, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_var_item({:?}, {:?}, {:?}, {:?})", name, feat, decl, annot);

        let decls = self.var_items.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref mut df, ref dd, ref mut da) in decls.iter_mut() {
            if *dd == decl {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                if *da != annot {
                    da.push_str(", ");
                    da.push_str(&annot);
                }
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, feat, decl, annot));
        self.next_seq_id += 1;
    }
}

/**
This cache owns the output files and saves us from constantly opening and closing them.
*/
pub struct OutputFiles<'a> {
    out_config: &'a OutConfig,
    files: HashMap<path::PathBuf, (fs::File, Option<(Features, AbsCallConv)>)>,
}

impl<'a> OutputFiles<'a> {
    pub fn new(out_config: &'a OutConfig) -> Self {
        OutputFiles {
            out_config: out_config,
            files: HashMap::new(),
        }
    }

    pub fn emit_to_header(&mut self, name: &str, feat: &Features, decl: &str, annot: &str) {
        use std::io::prelude::*;
        let (file, _) = self.get_file(name, &self.out_config.header_path);
        writeln!(file, "{}{} /* {} */", feat, decl, annot).unwrap();
    }

    pub fn emit_to_library(&mut self, name: &str, feat: &Features, cconv: Option<AbsCallConv>, decl: &str, annot: &str) {
        use std::io::prelude::*;
        let (file, group) = self.get_file(name, &self.out_config.library_path);

        if let Some(cconv) = cconv {
            // Change grouping if necessary.
            match *group {
                Some((ref gf, ref gcc)) if gf == feat && *gcc == cconv => (),
                Some(_) => {
                    writeln!(file, "}}\n{}\nextern {:?} {{", feat, cconv.as_str()).unwrap();
                },
                None => {
                    writeln!(file, "{}\nextern {:?} {{", feat, cconv.as_str()).unwrap();
                }
            }

            // Proceed with output.
            writeln!(file, "    {} /* {} */", decl, annot).unwrap();

            // Update the "last" group.
            *group = Some((feat.clone(), cconv));
        } else {
            if group.is_some() {
                writeln!(file, "}}").unwrap();
            }
            writeln!(file, "{}{} /* {} */", feat, decl, annot).unwrap();
            *group = None;
        }
    }

    /**
    Finishes output to all open files.

    This includes things like closing `extern` blocks.
    */
    pub fn finish_output(self) {
        use std::io::prelude::*;
        debug!("finish_output()");

        for (_, (mut file, group)) in self.files.into_iter() {
            match group {
                Some(_) => writeln!(file, "}}").unwrap(),
                None => ()
            }
        }
    }

    fn get_file<'b>(
        &'b mut self,
        name: &str,
        pattern: &str
    ) -> (&'b mut fs::File, &'b mut Option<(Features, AbsCallConv)>) {
        use std::path::PathBuf;
        let mut path = PathBuf::from(&self.out_config.output_dir);
        path.push(pattern.replace("{}", name));
        let fg = self.files.entry(path.clone())
            .or_insert_with(|| (fs::File::create(path).unwrap(), None));
        (&mut fg.0, &mut fg.1)
    }
}

pub fn output_header_items(items: &OutputItems, output: &mut OutputFiles) {
    let mut lines = vec![];
    for (_, decls) in &items.header_items {
        for &(idx, ref header, ref feat, ref decl, ref annot) in decls {
            lines.push((header, idx, feat, decl, annot));
        }
    }
    lines.sort();

    let lines = lines.into_iter()
        .group_by_lazy(|&(header, _, feat, _, _)| (header, feat));

    for ((header, feat), group) in &lines {
        for (_, _, _, decl, annot) in group {
            output.emit_to_header(header, feat, decl, annot);
        }
    }
}

pub fn output_func_items(items: &OutputItems, output: &mut OutputFiles, out_config: &OutConfig) {
    let mut lines = vec![];
    for (name, decls) in &items.fn_items {
        for &(_, ref feat, ref cconv, ref decl, ref annot) in decls {
            for &ref lib in out_config.get_fn_libs(name) {
                lines.push((lib, feat, name, Some(*cconv), decl, annot));
            }
        }
    }
    for (name, decls) in &items.fn_aliases {
        for &(_, ref alias, ref feat, ref decl, ref annot) in decls {
            for &ref lib in out_config.get_fn_libs(alias) {
                lines.push((lib, feat, name, None, decl, annot));
            }
        }
    }
    for (name, decls) in &items.var_items {
        for &(_, ref feat, ref decl, ref annot) in decls {
            for &ref lib in out_config.get_fn_libs(name) {
                lines.push((lib, feat, name, Some(AbsCallConv::System), decl, annot));
            }
        }
    }
    lines.sort();

    let lines = lines.into_iter()
        .group_by_lazy(|&(lib, feat, _, cconv, _, _)| (lib, feat, cconv));

    for ((lib, feat, cconv), group) in &lines {
        for (_, _, _, _, decl, annot) in group {
            output.emit_to_library(lib, feat, cconv, decl, annot);
        }
    }
}
<commit_msg>Fix output of stubbed-out header entries.<commit_after>use std::collections::HashMap;
use std::fs;
use std::path;
use itertools::Itertools;
use OutConfig;
use features::Features;

/**
An "abstract" calling convention.

This is to answer the question: "if a function uses the C calling convention, is that the same thing as `"system"`, or do I have to *actually* say `"C"`?"

Without this, almost every Windows API call would need two decls: one with `extern "C"`, and one with `extern "stdcall"`.  Yuck.
*/
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum AbsCallConv {
    ExplicitlyC,
    System,
}

impl AbsCallConv {
    /// Gets the calling convention as a string, suitable for use with Rust's `extern`.
    pub fn as_str(self) -> &'static str {
        use self::AbsCallConv::*;
        match self {
            ExplicitlyC => "C",
            System => "system",
        }
    }
}

/**
Used to centralise how output of translated items is done.

One of the major reasons for this is to consolidate disparate bindings.  That is, if the output for both x86 and x86-64 are the same, then they should use a *single* declaration with an appropriate `#[cfg]` attribute.

Note that `annot` is used for "annotations", which are free-form strings that may be emitted as comments in the output.  These are handy for identifying, for example, *where* a declaration originally came from, for debugging purposes.
*/
pub struct OutputItems {
    next_seq_id: u64,

    /// `[name => [(alias, feat, decl, annot)]]`
    pub fn_aliases: HashMap<String, Vec<(u64, String, Features, String, String)>>,

    /// `[name => [(feat, cconv, decl, annot)]]`
    pub fn_items: HashMap<String, Vec<(u64, Features, AbsCallConv, String, String)>>,

    /// `[name => [(header, feat, decl, annot)]]`
    pub header_items: HashMap<String, Vec<(u64, String, Features, String, String)>>,

    /// `[name => [(feat, decl, annot)]]`
    pub var_items: HashMap<String, Vec<(u64, Features, String, String)>>,
}

impl OutputItems {
    pub fn new() -> Self {
        OutputItems {
            next_seq_id: 0,
            fn_aliases: HashMap::new(),
            fn_items: HashMap::new(),
            header_items: HashMap::new(),
            var_items: HashMap::new(),
        }
    }

    /**
    Adds a function alias.

    This is different from a regular function item in that the library is should be emitted to is based on some *other* function which it is aliasing.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_func_alias(&mut self, name: String, alias: String, feat: Features, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_func_alias({:?}, {:?}, {:?}, {:?}, {:?})", name, alias, feat, decl, annot);

        let decls = self.fn_aliases.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref mut dal, ref mut df, ref dd, ref mut da) in decls.iter_mut() {
            if *dd == decl && *dal == alias {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                if *da != annot {
                    da.push_str(", ");
                    da.push_str(&annot);
                }
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, alias, feat, decl, annot));
        self.next_seq_id += 1;
    }

    /**
    Adds a function declaration.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_func_item(&mut self, name: String, feat: Features, cconv: AbsCallConv, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_func_item({:?}, {:?}, {:?}, {:?}, {:?})", name, feat, cconv, decl, annot);

        let decls = self.fn_items.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref mut df, ref dcc, ref dd, ref mut da) in decls.iter_mut() {
            if *dd == decl && *dcc == cconv {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                if *da != annot {
                    da.push_str(", ");
                    da.push_str(&annot);
                }
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, feat, cconv, decl, annot));
        self.next_seq_id += 1;
    }

    /**
    Adds a header declaration.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_header_item(&mut self, name: String, header: String, feat: Features, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_header_item({:?}, {:?}, {:?}, {:?}, {:?})", header, name, feat, decl, annot);

        let decls = self.header_items.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref dh, ref mut df, ref dd, ref mut da) in decls.iter_mut() {
            if *dh == header && *dd == decl {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                da.push_str(", ");
                da.push_str(&annot);
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, header, feat, decl, annot));
        self.next_seq_id += 1;
    }

    /**
    Adds a variable declaration.

    If the given `decl` matches an already existing `decl` with the same `name`, the existing entry will have its feature set unioned with `feat`, and `annot` appended to its annotation.
    */
    pub fn add_var_item(&mut self, name: String, feat: Features, decl: String, annot: String) {
        use std::mem::replace;
        debug!("add_var_item({:?}, {:?}, {:?}, {:?})", name, feat, decl, annot);

        let decls = self.var_items.entry(name).or_insert(vec![]);

        // Is there already a decl which is compatible with this one?
        for &mut (_, ref mut df, ref dd, ref mut da) in decls.iter_mut() {
            if *dd == decl {
                debug!(".. merging");
                // The decls are the same.  Just combine the feature sets together.
                let new_df = replace(df, Features::default()).or(feat);
                *df = new_df;
                if *da != annot {
                    da.push_str(", ");
                    da.push_str(&annot);
                }
                return;
            }
        }

        // Add it to the set of decls.
        debug!(".. adding");
        decls.push((self.next_seq_id, feat, decl, annot));
        self.next_seq_id += 1;
    }
}

/**
This cache owns the output files and saves us from constantly opening and closing them.
*/
pub struct OutputFiles<'a> {
    out_config: &'a OutConfig,
    files: HashMap<path::PathBuf, (fs::File, Option<(Features, AbsCallConv)>)>,
}

impl<'a> OutputFiles<'a> {
    pub fn new(out_config: &'a OutConfig) -> Self {
        OutputFiles {
            out_config: out_config,
            files: HashMap::new(),
        }
    }

    pub fn emit_to_header(&mut self, name: &str, feat: &Features, decl: &str, annot: &str) {
        use std::io::prelude::*;
        let (file, _) = self.get_file(name, &self.out_config.header_path);
        if !decl.starts_with("//") {
            writeln!(file, "{}{} /* {} */", feat, decl, annot).unwrap();
        } else {
            writeln!(file, "/* {}{} */ /* {} */", feat, decl, annot).unwrap();
        }
    }

    pub fn emit_to_library(&mut self, name: &str, feat: &Features, cconv: Option<AbsCallConv>, decl: &str, annot: &str) {
        use std::io::prelude::*;
        let (file, group) = self.get_file(name, &self.out_config.library_path);

        if let Some(cconv) = cconv {
            // Change grouping if necessary.
            match *group {
                Some((ref gf, ref gcc)) if gf == feat && *gcc == cconv => (),
                Some(_) => {
                    writeln!(file, "}}\n{}\nextern {:?} {{", feat, cconv.as_str()).unwrap();
                },
                None => {
                    writeln!(file, "{}\nextern {:?} {{", feat, cconv.as_str()).unwrap();
                }
            }

            // Proceed with output.
            writeln!(file, "    {} /* {} */", decl, annot).unwrap();

            // Update the "last" group.
            *group = Some((feat.clone(), cconv));
        } else {
            if group.is_some() {
                writeln!(file, "}}").unwrap();
            }
            writeln!(file, "{}{} /* {} */", feat, decl, annot).unwrap();
            *group = None;
        }
    }

    /**
    Finishes output to all open files.

    This includes things like closing `extern` blocks.
    */
    pub fn finish_output(self) {
        use std::io::prelude::*;
        debug!("finish_output()");

        for (_, (mut file, group)) in self.files.into_iter() {
            match group {
                Some(_) => writeln!(file, "}}").unwrap(),
                None => ()
            }
        }
    }

    fn get_file<'b>(
        &'b mut self,
        name: &str,
        pattern: &str
    ) -> (&'b mut fs::File, &'b mut Option<(Features, AbsCallConv)>) {
        use std::path::PathBuf;
        let mut path = PathBuf::from(&self.out_config.output_dir);
        path.push(pattern.replace("{}", name));
        let fg = self.files.entry(path.clone())
            .or_insert_with(|| (fs::File::create(path).unwrap(), None));
        (&mut fg.0, &mut fg.1)
    }
}

pub fn output_header_items(items: &OutputItems, output: &mut OutputFiles) {
    let mut lines = vec![];
    for (_, decls) in &items.header_items {
        for &(idx, ref header, ref feat, ref decl, ref annot) in decls {
            lines.push((header, idx, feat, decl, annot));
        }
    }
    lines.sort();

    let lines = lines.into_iter()
        .group_by_lazy(|&(header, _, feat, _, _)| (header, feat));

    for ((header, feat), group) in &lines {
        for (_, _, _, decl, annot) in group {
            output.emit_to_header(header, feat, decl, annot);
        }
    }
}

pub fn output_func_items(items: &OutputItems, output: &mut OutputFiles, out_config: &OutConfig) {
    let mut lines = vec![];
    for (name, decls) in &items.fn_items {
        for &(_, ref feat, ref cconv, ref decl, ref annot) in decls {
            for &ref lib in out_config.get_fn_libs(name) {
                lines.push((lib, feat, name, Some(*cconv), decl, annot));
            }
        }
    }
    for (name, decls) in &items.fn_aliases {
        for &(_, ref alias, ref feat, ref decl, ref annot) in decls {
            for &ref lib in out_config.get_fn_libs(alias) {
                lines.push((lib, feat, name, None, decl, annot));
            }
        }
    }
    for (name, decls) in &items.var_items {
        for &(_, ref feat, ref decl, ref annot) in decls {
            for &ref lib in out_config.get_fn_libs(name) {
                lines.push((lib, feat, name, Some(AbsCallConv::System), decl, annot));
            }
        }
    }
    lines.sort();

    let lines = lines.into_iter()
        .group_by_lazy(|&(lib, feat, _, cconv, _, _)| (lib, feat, cconv));

    for ((lib, feat, cconv), group) in &lines {
        for (_, _, _, _, decl, annot) in group {
            output.emit_to_library(lib, feat, cconv, decl, annot);
        }
    }
}
<|endoftext|>


<commit_before>use crate::term2;
use std::fmt;
use std::io::Write;

macro_rules! warn {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::warn_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}
macro_rules! err {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::err_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}
macro_rules! info {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::info_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}

macro_rules! verbose {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::verbose_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}

pub fn warn_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.fg(term2::color::BRIGHT_YELLOW);
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "warning: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn err_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.fg(term2::color::BRIGHT_RED);
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "error: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn info_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "info: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn verbose_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.fg(term2::color::BRIGHT_MAGENTA);
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "verbose: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}
<commit_msg>Add a log macro at debug level<commit_after>use crate::term2;
use std::fmt;
use std::io::Write;

macro_rules! warn {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::warn_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}
macro_rules! err {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::err_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}
macro_rules! info {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::info_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}

macro_rules! verbose {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::verbose_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}

macro_rules! debug {
    ( $ ( $ arg : tt ) * ) => ( $crate::log::debug_fmt ( format_args ! ( $ ( $ arg ) * ) ) )
}

pub fn warn_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.fg(term2::color::BRIGHT_YELLOW);
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "warning: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn err_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.fg(term2::color::BRIGHT_RED);
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "error: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn info_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "info: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn verbose_fmt(args: fmt::Arguments) {
    let mut t = term2::stderr();
    let _ = t.fg(term2::color::BRIGHT_MAGENTA);
    let _ = t.attr(term2::Attr::Bold);
    let _ = write!(t, "verbose: ");
    let _ = t.reset();
    let _ = t.write_fmt(args);
    let _ = write!(t, "\n");
}

pub fn debug_fmt(args: fmt::Arguments) {
    if std::env::var("RUSTUP_DEBUG").is_ok() {
        let mut t = term2::stderr();
        let _ = t.fg(term2::color::BRIGHT_BLUE);
        let _ = t.attr(term2::Attr::Bold);
        let _ = write!(t, "verbose: ");
        let _ = t.reset();
        let _ = t.write_fmt(args);
        let _ = write!(t, "\n");
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_osc;

use std::error::Error;
use std::fmt;
use std::io::Cursor;
use serde::Deserializer;
use serde::de::{SeqVisitor, Visitor};
use serde_osc::de::PktDeserializer;

#[test]
fn basic() {
    /// Struct we'll deserialize into
    #[derive(Debug, PartialEq, Eq)]
    struct Deserialized {
        address: String,
        arg_0: i32,
        arg_1: i32,
    }
    struct MyVisitor;
    impl Visitor for MyVisitor {
        type Value = Deserialized;
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            write!(formatter, "An OSC path followed by two integer arguments")
        }
        fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where V: SeqVisitor
        {
            let address = visitor.visit()?.unwrap();
            let arg_0 = visitor.visit()?.unwrap();
            let arg_1 = visitor.visit()?.unwrap();
            Ok(Deserialized{
                address: address,
                arg_0: arg_0,
                arg_1: arg_1})
        }
    }
    let test_input = b"\x00\x00\x00\x1c/example/path\0\0\0,ii\0\x01\x02\x03\x04\x05\x06\x07\x08";
    let expected = Deserialized {
        address: "/example/path".to_owned(),
        arg_0: 0x01020304,
        arg_1: 0x05060708,
    };
    let rd = Cursor::new(test_input);
    let mut visitor = MyVisitor;
    let mut test_de = PktDeserializer::new(rd);
    let deserialized = test_de.deserialize(visitor).unwrap();
    assert_eq!(deserialized, expected);
}

<commit_msg>Clean up warnings in test<commit_after>extern crate serde;
extern crate serde_osc;

use std::fmt;
use std::io::Cursor;
use serde::Deserializer;
use serde::de::{SeqVisitor, Visitor};
use serde_osc::de::PktDeserializer;

#[test]
fn basic() {
    /// Struct we'll deserialize into
    #[derive(Debug, PartialEq, Eq)]
    struct Deserialized {
        address: String,
        arg_0: i32,
        arg_1: i32,
    }
    struct MyVisitor;
    impl Visitor for MyVisitor {
        type Value = Deserialized;
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            write!(formatter, "An OSC path followed by two integer arguments")
        }
        fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where V: SeqVisitor
        {
            let address = visitor.visit()?.unwrap();
            let arg_0 = visitor.visit()?.unwrap();
            let arg_1 = visitor.visit()?.unwrap();
            Ok(Deserialized{
                address: address,
                arg_0: arg_0,
                arg_1: arg_1})
        }
    }
    let test_input = b"\x00\x00\x00\x1c/example/path\0\0\0,ii\0\x01\x02\x03\x04\x05\x06\x07\x08";
    let expected = Deserialized {
        address: "/example/path".to_owned(),
        arg_0: 0x01020304,
        arg_1: 0x05060708,
    };
    let rd = Cursor::new(test_input);
    let visitor = MyVisitor;
    let mut test_de = PktDeserializer::new(rd);
    let deserialized = test_de.deserialize(visitor).unwrap();
    assert_eq!(deserialized, expected);
}

<|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.

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

use instance::Instance;
use instance::PhysicalDevice;
use swapchain::Surface;

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
pub struct DisplayPlane {
    instance: Arc<Instance>,
    physical_device: usize,
    index: u32,
    properties: vk::DisplayPlanePropertiesKHR,
    supported_displays: Vec<vk::DisplayKHR>,
}

impl DisplayPlane {
    /// Enumerates all the display planes that are available on a given physical device.
    pub fn enumerate(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())
    }

    /// 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 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.
#[derive(Clone)]
pub struct Display {
    instance: Arc<Instance>,
    physical_device: usize,
    properties: Arc<vk::DisplayPropertiesKHR>,      // TODO: Arc because struct isn't clone
}

impl Display {
    /// Enumerates all the displays that are available on a given physical device.
    pub fn enumerate(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())
    }

    /// 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 resolution of the display.
    #[inline]
    pub fn physical_resolution(&self) -> [u32; 2] {
        let ref r = self.properties.physicalResolution;
        [r.width, r.height]
    }

    /// Returns a list of all modes available on this display.
    pub fn display_modes(&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())
    }
}

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>Minor docs in swapchain/display<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.

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

use instance::Instance;
use instance::PhysicalDevice;
use swapchain::Surface;

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
pub struct DisplayPlane {
    instance: Arc<Instance>,
    physical_device: usize,
    index: u32,
    properties: vk::DisplayPlanePropertiesKHR,
    supported_displays: Vec<vk::DisplayKHR>,
}

impl DisplayPlane {
    /// Enumerates all the display planes that are available on a given physical device.
    pub fn enumerate(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())
    }

    /// 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 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.
#[derive(Clone)]
pub struct Display {
    instance: Arc<Instance>,
    physical_device: usize,
    properties: Arc<vk::DisplayPropertiesKHR>,      // TODO: Arc because struct isn't clone
}

impl Display {
    /// Enumerates all the displays that are available on a given physical device.
    pub fn enumerate(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())
    }

    /// 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 resolution of the display.
    #[inline]
    pub fn physical_resolution(&self) -> [u32; 2] {
        let ref r = self.properties.physicalResolution;
        [r.width, r.height]
    }

    /// Returns a list of all modes available on this display.
    pub fn display_modes(&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())
    }
}

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>
use std;
use std::cmp::max;

use {
    Buffer2d,
    Packer,
    Rect,
};

struct Skyline {
    pub x: u32,
    pub y: u32,
    pub w: u32,
}

pub struct SkylinePacker<B: Buffer2d> {
    buf: B,
    width: u32,
    height: u32,
    skylines: Vec<Skyline>,
    margin: u32,
}

impl<B: Buffer2d> SkylinePacker<B> {
    pub fn new(buf: B) -> SkylinePacker<B> {
        let (width, height) = buf.dimensions();
        let mut skylines = Vec::new();
        skylines.push(Skyline {
            x: 0,
            y: 0,
            w: width,
        });

        SkylinePacker {
            buf: buf,
            width: width,
            height: height,
            skylines: skylines,
            margin: 0,
        }
    }

    fn can_put(&self, i: uint, w: u32, h: u32) -> Option<u32> {
        let x = self.skylines[i].x;
        if x + w > self.width {
            return None;
        }
        let mut width_left = w;
        let mut i = i;
        let mut y = self.skylines[i].y;
        loop {
            y = max(y, self.skylines[i].y);
            if y + h > self.height {
                return None;
            }
            if self.skylines[i].w > width_left {
                return Some(y);
            }
            width_left -= self.skylines[i].w;
            i += 1;
            assert!(i < self.skylines.len());
        }
    }

    fn find_skyline(&self, w: u32, h: u32) -> Option<(uint, Rect)> {
        let mut min_height = std::u32::MAX;
        let mut min_width = std::u32::MAX;
        let mut index = None;
        let mut rect = Rect::new(0, 0, 0, 0);

        // keep the min_height as small as possible
        for i in range(0, self.skylines.len()) {
            match self.can_put(i, w, h) {
                Some(y) => {
                    if y + h < min_height ||
                       (y + h == min_height && self.skylines[i].w < min_width) {
                        min_height = y + h;
                        min_width = self.skylines[i].w;
                        index = Some(i);
                        rect.x = self.skylines[i].x;
                        rect.y = y;
                        rect.w = w;
                        rect.h = h;
                    }
                },
                _ => {},
            }

            match self.can_put(i, h, w) {
                Some(y) => {
                    if y + w < min_height ||
                       (y + w == min_height && self.skylines[i].w < min_width) {
                        min_height = y + w;
                        min_width = self.skylines[i].w;
                        index = Some(i);
                        rect.x = self.skylines[i].x;
                        rect.y = y;
                        rect.w = h;
                        rect.h = w;
                    }
                },
                _ => {},
            }
        }

        if index.is_some() {
            Some((index.unwrap(), rect))
        } else {
            None
        }
    }

    fn split(&mut self, index: uint, rect: &Rect) {
        let skyline = Skyline {
            x: rect.x,
            y: rect.y + rect.h,
            w: rect.w,
        };

        assert!(skyline.x + skyline.w <= self.width);
        assert!(skyline.y <= self.height);

        self.skylines.insert(index, skyline);

        let i = index + 1;
        while i < self.skylines.len() {
            assert!(self.skylines[i-1].x <= self.skylines[i].x);

            if self.skylines[i].x < self.skylines[i-1].x + self.skylines[i-1].w {
                let shrink = self.skylines[i-1].x + self.skylines[i-1].w - self.skylines[i].x;
                if self.skylines[i].w <= shrink {
                    self.skylines.remove(i);
                } else {
                    self.skylines.get_mut(i).x += shrink;
                    self.skylines.get_mut(i).w -= shrink;
                    break;
                }
            } else {
                break;
            }
        }
    }

    fn merge(&mut self) {
        let mut i = 1;
        while i < self.skylines.len() {
            if self.skylines[i-1].y == self.skylines[i].y {
                self.skylines.get_mut(i-1).w += self.skylines[i].w;
                self.skylines.remove(i);
                i -= 1;
            }
            i += 1;
        }
    }
}

impl<B: Buffer2d> Packer<B> for SkylinePacker<B> {
    fn pack(&mut self, buf: &Buffer2d) -> Option<Rect> {
        let (mut width, mut height) = buf.dimensions();
        width += self.margin;
        height += self.margin;

        match self.find_skyline(width, height) {
            Some((i, mut rect)) => {
                if width == rect.w {
                    self.buf.patch(rect.x, rect.y, buf);
                } else {
                    self.buf.patch_rotated(rect.x, rect.y, buf);
                }

                self.split(i, &rect);
                self.merge();

                rect.w -= self.margin;
                rect.h -= self.margin;
                Some(rect)
            },
            _ => {
                None
            },
        }
    }

    fn buf(&self) -> &B {
        &self.buf
    }

    fn set_margin(&mut self, val: u32) {
        self.margin = val;
    }
}

<commit_msg>Fixes build errors<commit_after>
use std;
use std::cmp::max;

use {
    Buffer2d,
    Packer,
    Rect,
};

struct Skyline {
    pub x: u32,
    pub y: u32,
    pub w: u32,
}

pub struct SkylinePacker<B: Buffer2d> {
    buf: B,
    width: u32,
    height: u32,
    skylines: Vec<Skyline>,
    margin: u32,
}

impl<B: Buffer2d> SkylinePacker<B> {
    pub fn new(buf: B) -> SkylinePacker<B> {
        let (width, height) = buf.dimensions();
        let mut skylines = Vec::new();
        skylines.push(Skyline {
            x: 0,
            y: 0,
            w: width,
        });

        SkylinePacker {
            buf: buf,
            width: width,
            height: height,
            skylines: skylines,
            margin: 0,
        }
    }

    fn can_put(&self, i: uint, w: u32, h: u32) -> Option<u32> {
        let x = self.skylines[i].x;
        if x + w > self.width {
            return None;
        }
        let mut width_left = w;
        let mut i = i;
        let mut y = self.skylines[i].y;
        loop {
            y = max(y, self.skylines[i].y);
            if y + h > self.height {
                return None;
            }
            if self.skylines[i].w > width_left {
                return Some(y);
            }
            width_left -= self.skylines[i].w;
            i += 1;
            assert!(i < self.skylines.len());
        }
    }

    fn find_skyline(&self, w: u32, h: u32) -> Option<(uint, Rect)> {
        let mut min_height = std::u32::MAX;
        let mut min_width = std::u32::MAX;
        let mut index = None;
        let mut rect = Rect::new(0, 0, 0, 0);

        // keep the min_height as small as possible
        for i in range(0, self.skylines.len()) {
            match self.can_put(i, w, h) {
                Some(y) => {
                    if y + h < min_height ||
                       (y + h == min_height && self.skylines[i].w < min_width) {
                        min_height = y + h;
                        min_width = self.skylines[i].w;
                        index = Some(i);
                        rect.x = self.skylines[i].x;
                        rect.y = y;
                        rect.w = w;
                        rect.h = h;
                    }
                },
                _ => {},
            }

            match self.can_put(i, h, w) {
                Some(y) => {
                    if y + w < min_height ||
                       (y + w == min_height && self.skylines[i].w < min_width) {
                        min_height = y + w;
                        min_width = self.skylines[i].w;
                        index = Some(i);
                        rect.x = self.skylines[i].x;
                        rect.y = y;
                        rect.w = h;
                        rect.h = w;
                    }
                },
                _ => {},
            }
        }

        if index.is_some() {
            Some((index.unwrap(), rect))
        } else {
            None
        }
    }

    fn split(&mut self, index: uint, rect: &Rect) {
        let skyline = Skyline {
            x: rect.x,
            y: rect.y + rect.h,
            w: rect.w,
        };

        assert!(skyline.x + skyline.w <= self.width);
        assert!(skyline.y <= self.height);

        self.skylines.insert(index, skyline);

        let i = index + 1;
        while i < self.skylines.len() {
            assert!(self.skylines[i-1].x <= self.skylines[i].x);

            if self.skylines[i].x < self.skylines[i-1].x + self.skylines[i-1].w {
                let shrink = self.skylines[i-1].x + self.skylines[i-1].w - self.skylines[i].x;
                if self.skylines[i].w <= shrink {
                    self.skylines.remove(i);
                } else {
                    self.skylines[i].x += shrink;
                    self.skylines[i].w -= shrink;
                    break;
                }
            } else {
                break;
            }
        }
    }

    fn merge(&mut self) {
        let mut i = 1;
        while i < self.skylines.len() {
            if self.skylines[i-1].y == self.skylines[i].y {
                self.skylines[i-1].w += self.skylines[i].w;
                self.skylines.remove(i);
                i -= 1;
            }
            i += 1;
        }
    }
}

impl<B: Buffer2d> Packer<B> for SkylinePacker<B> {
    fn pack(&mut self, buf: &Buffer2d) -> Option<Rect> {
        let (mut width, mut height) = buf.dimensions();
        width += self.margin;
        height += self.margin;

        match self.find_skyline(width, height) {
            Some((i, mut rect)) => {
                if width == rect.w {
                    self.buf.patch(rect.x, rect.y, buf);
                } else {
                    self.buf.patch_rotated(rect.x, rect.y, buf);
                }

                self.split(i, &rect);
                self.merge();

                rect.w -= self.margin;
                rect.h -= self.margin;
                Some(rect)
            },
            _ => {
                None
            },
        }
    }

    fn buf(&self) -> &B {
        &self.buf
    }

    fn set_margin(&mut self, val: u32) {
        self.margin = val;
    }
}

<|endoftext|>